Skip to content

Commit

Permalink
feat(ui): add time-picker component
Browse files Browse the repository at this point in the history
  • Loading branch information
xiejay97 committed Jun 23, 2022
1 parent 1cafbbc commit e3dc42d
Show file tree
Hide file tree
Showing 185 changed files with 2,987 additions and 1,397 deletions.
28 changes: 0 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,3 @@ For non-new component contributions, please refer to [Contribution Guide](CONTRI
## VSCode configuration

Refer to [README.md](https://github.com/xiejay97/react-devui/tree/main/.vscode) under the `.vscode` directory

## Design guide

- Use Hooks to complete the components.
- Keep the independence of components to the greatest extent possible, and use component combinations to complete more complex logic, for example: [Drawer](https://github.com/xiejay97/react-devui/tree/main/packages/ui/src/components/drawer) component separates the Header, so that we can use the DrawerHeader alone instead of passing the header's Props to the Drawer component. More than that, the separation of the components saves us from worrying about future component functions becoming more and more difficult to maintain.
- Ensure that the component `Props` inherits native attributes, such as `React.HTMLAttributes<HTMLElement>`. We hope that the use of the component is consistent with the DOM element. When implementing the component, we need to be careful not to overwrite the `id` and `className` passed by the user , `style` and events (such as onClick).
- Ensure that only the `Props` of the root component of the complex component provides callbacks, such as only [DMenu](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/menu/Menu.tsx) provides the `onActiveChange` callback.
- Support two-way binding ([useTwoWayBinding](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/hooks/two-way-binding.ts)), refer to [DRadio](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/radio/Radio.tsx).
- Data entry must be implemented using native `input`, and use [useTwoWayBinding](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/hooks/two-way-binding.ts) to support future `form` components, refer to [DRadio](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/radio/Radio.tsx).
- Use `useAsync` to manage asynchronous functions. By intercepting asynchronous methods, such as `setTimeout`, we ensure that asynchronous functions will not be executed after the component is destroyed.
- Be sure to follow [WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.2/), some undefined components, such as `Drawer`, we should also try our best according to the usage Provide WAI-ARIA support.
- Support internationalization, refer to [DFooter](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/_footer/Footer.tsx).
- Don't introduce third-party components, we want components to be completely controllable.
- Use class instead of style whenever possible to allow users to modify the style.

## Style

- The class naming follows the [BEM](http://getbem.com/introduction/) specification.
- When designing components, be sure to consider whether they should be added to [DCompose](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/compose/Compose.tsx). In theory, all data input components should be able to be combined. For implementation, please refer to [DButton](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/button/Button.tsx).
- [Mixin](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/styles/mixins/_bem.scss) that provides additional themes, status, js, refer to [namespaces ](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/).
- All `font-size` use [RFS](https://github.com/twbs/rfs#readme) to achieve responsive text.
- We use the sass output style, but our variables use the native `var()`.

## Test

- Don't use snapshots (I have good reasons to convince you why not use it).
- The test should focus on the completeness of the function, that is, whether the input Props can get the response we expect.
- If the non-Props changes of the component will affect the test, such as the style of the component (adjust the position of the icon), the text content of the component (when testing the button in the component, text is often used to determine whether the button is the expected button), then you should doubt whether the test is Reasonable. Refer to [DFooter](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/_footer/Footer.tsx).
28 changes: 0 additions & 28 deletions README.zh-Hant.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,3 @@ yarn site:serve
## VSCode 配置

参考 `.vscode` 目录下的 [README.md](https://github.com/xiejay97/react-devui/tree/main/.vscode)

## 设计指南

- 全部使用 Hook 完成组件。
- 最大程度保持组件的独立性,使用组件组合完成更复杂的逻辑,例如:[Drawer](https://github.com/xiejay97/react-devui/tree/main/packages/ui/src/components/drawer) 组件分离了 Header,这样我们可以单独使用 DrawerHeader,而不是通过向 Drawer 组件传递 Header 的 Props,不止如此,分离组件使我们不必担心未来组件功能越来越多而难以维护。
- 确保组件 `Props` 继承了原生属性,如 `React.HTMLAttributes<HTMLElement>`, 我们希望组件的使用与 DOM 元素一致,在实现组件时需要注意不覆盖掉用户传递的 `id``className``style` 和事件(如 onClick)。
- 确保复杂组件仅根组件的 `Props` 提供回调,如 `menu` 中仅 [DMenu](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/menu/Menu.tsx) 提供了 `onActiveChange` 回调。
- 支持双向绑定([useTwoWayBinding](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/hooks/two-way-binding.ts)),参考 [DRadio](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/radio/Radio.tsx)
- 数据录入务必使用原生的 `input` 实现,并且使用 [useTwoWayBinding](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/hooks/two-way-binding.ts) 以支持未来的 `form` 组件,参考 [DRadio](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/radio/Radio.tsx)
- 使用 `useAsync` 管理异步函数,通过拦截异步方法,如 `setTimeout`, 我们确保异步函数不会在组件销毁后执行。
- 务必遵循 [WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.2/),一些未定义的组件,如 `Drawer`,我们也应该尽可能根据使用情况提供 WAI-ARIA 支持。
- 支持国际化,参考 [DFooter](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/_footer/Footer.tsx)
- 不要引入第三方组件,我们希望组件是完全可控的。
- 尽可能使用 class 而不是 style 以允许使用者可以修改样式。

## 样式

- class 命名遵循 [BEM](http://getbem.com/introduction/) 规范。
- 设计组件时务必考虑是否应该添加到 [DCompose](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/compose/Compose.tsx)。理论上所有数据输入组件都应该能够被组合,实现可参考 [DButton](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/button/Button.tsx)
- 提供额外的 主题、状态、js 的 [mixin](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/styles/mixins/_bem.scss),参考 [namespaces](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/)
- 所有的 `font-size` 使用 [RFS](https://github.com/twbs/rfs#readme) 以实现响应式文字。
- 我们使用 sass 输出样式,但是我们的变量使用原生的 `var()`

## 测试

- 不要使用快照(我有充分的理由让你相信为什么不使用它)。
- 测试应当专注于功能的完整性, 即输入 Props 是否能够得到我们期望的响应。
- 如果组件非 Props 的变更会影响测试,如组件样式(调整图标位置)、组件包含的文字内容(测试组件中的按钮时经常会用文字来判断是否为预期的按钮),那么应当怀疑测试是否合理。参考 [DFooter](https://github.com/xiejay97/react-devui/blob/main/packages/ui/src/components/_footer/Footer.tsx)
30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,20 @@
},
"dependencies": {
"@ant-design/icons-svg": "^4.2.1",
"core-js": "^3.22.8",
"core-js": "^3.23.1",
"dayjs": "^1.11.3",
"highlight.js": "^11.5.1",
"i18next": "^21.8.9",
"immer": "^9.0.14",
"immer": "^9.0.15",
"lodash": "^4.17.21",
"marked": "^4.0.16",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-i18next": "^11.17.0",
"marked": "^4.0.17",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-i18next": "^11.17.2",
"react-router-dom": "^6.3.0",
"regenerator-runtime": "^0.13.9",
"rfs": "^9.0.6",
"rxjs": "^7.5.5",
"scrollview-resize": "^1.0.2",
"tslib": "^2.4.0"
},
"devDependencies": {
Expand All @@ -65,11 +65,11 @@
"@types/jest": "^27.5.1",
"@types/lodash": "^4.14.182",
"@types/marked": "^4.0.3",
"@types/node": "^17.0.41",
"@types/node": "^17.0.43",
"@types/react": "^18.0.12",
"@types/react-dom": "^18.0.5",
"@typescript-eslint/eslint-plugin": "^5.27.1",
"@typescript-eslint/parser": "^5.27.1",
"@typescript-eslint/eslint-plugin": "^5.28.0",
"@typescript-eslint/parser": "^5.28.0",
"babel-jest": "^28.1.1",
"dotenv": "^16.0.1",
"eslint": "^8.17.0",
Expand All @@ -80,25 +80,25 @@
"eslint-plugin-markdown": "^2.2.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.30.0",
"eslint-plugin-react-hooks": "^4.5.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-tsdoc": "^0.2.16",
"fs-extra": "^10.1.0",
"husky": "^8.0.1",
"jest": "^28.1.1",
"postcss-html": "^1.4.1",
"postcss-markdown": "^1.2.0",
"prettier": "^2.6.2",
"react-test-renderer": "^18.1.0",
"prettier": "^2.7.0",
"react-test-renderer": "^18.2.0",
"rxjs-for-await": "^1.0.0",
"sass": "^1.52.3",
"standard-version": "^9.5.0",
"stylelint": "^14.9.0",
"stylelint": "^14.9.1",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recess-order": "^3.0.0",
"stylelint-config-recommended-scss": "^6.0.0",
"stylelint-config-standard": "^26.0.0",
"stylelint-scss": "^4.2.0",
"ts-jest": "^28.0.4",
"ts-jest": "^28.0.5",
"ts-node": "^10.8.1",
"typescript": "~4.7.3",
"yaml-front-matter": "^4.1.1"
Expand Down
4 changes: 3 additions & 1 deletion packages/site/src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { DConfigContextData } from '@react-devui/ui/hooks/d-config/contex';
import type { DLang, DTheme } from '@react-devui/ui/utils/global';

import React, { useEffect, useMemo, useRef, useState } from 'react';
Expand Down Expand Up @@ -54,10 +55,11 @@ export function App() {
document.documentElement.lang = i18n.language;
}, [i18n.language]);

const rootContext = useMemo(
const rootContext = useMemo<DConfigContextData>(
() => ({
theme,
i18n: { lang: i18n.language as DLang },
updatePosition: { scroll: ['main.app-main'], resize: ['article.app-route-article'] },
}),
[i18n.language, theme]
);
Expand Down
7 changes: 4 additions & 3 deletions packages/site/src/app/components/layout/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ export function AppSidebar(props: { aMenuOpen: boolean; onMenuOpenChange: (open:
to: child.to,
})),
}))}
dActive={[activeId, setActiveId]}
dActive={activeId}
onActiveChange={(id, option) => {
setActiveId(id);
if (option.to) {
navigate(option.to, { replace: true });
onMenuOpenChange(false);
Expand All @@ -86,15 +87,15 @@ export function AppSidebar(props: { aMenuOpen: boolean; onMenuOpenChange: (open:
) : (
<DDrawer
className="app-sidebar__drawer"
dVisible={[aMenuOpen]}
dVisible={aMenuOpen}
dHeader={
<DDrawerHeader>
<img className="app-sidebar__logo" src="/assets/logo.svg" alt="Logo" width="24" height="24" />
<span className="app-sidebar__title">DevUI</span>
</DDrawerHeader>
}
dWidth={280}
onClose={() => onMenuOpenChange(false)}
onVisibleChange={onMenuOpenChange}
>
{menuNode}
</DDrawer>
Expand Down
9 changes: 3 additions & 6 deletions packages/site/src/app/components/route/RouteArticle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export function AppRouteArticle(props: AppRouteArticleProps) {

const mediaMatch = useMediaMatch();

const [links, setLinks] = useImmer<{ title: string; href: string }[]>(props.links ?? []);
const [_links, setLinks] = useImmer<{ title: string; href: string }[]>([]);
const links = isUndefined(props.links) ? _links : [...props.links, { title: 'API', href: '#API' }];

const [menuOpen, setMenuOpen] = useState(false);

const icon = (top: boolean) => (
Expand Down Expand Up @@ -59,11 +61,6 @@ m -673.67664,1221.6502 -231.2455,-231.24803 55.6165,
arr.push({ title: el.id, href: `#${el.id}` });
});
setLinks(arr);
return () => {
setLinks([]);
};
} else {
setLinks([...props.links, { title: 'API', href: '#API' }]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { AppComponentRouteArticleProps } from './ComponentRouteArticle';

import React from 'react';
import { useTranslation } from 'react-i18next';

import { AppComponentRouteArticle } from './ComponentRouteArticle';

export function AppComponentRoute(props: { 'en-US': AppComponentRouteArticleProps; 'zh-Hant': AppComponentRouteArticleProps }) {
const { i18n } = useTranslation();

return <AppComponentRouteArticle {...props[i18n.language]} />;
return React.createElement(AppComponentRouteArticle, props[i18n.language]);
}
7 changes: 5 additions & 2 deletions packages/site/src/app/components/route/component/DemoBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ ${'```'}
return () => {
asyncCapture.deleteGroup(asyncId);
};
}, [asyncCapture, id, setActive]);
}, [asyncCapture, id]);

return (
<section
Expand Down Expand Up @@ -132,9 +132,12 @@ ${'```'}
title: code,
panel: <div dangerouslySetInnerHTML={{ __html: code === 'tsx' ? tsx : scss }} />,
}))}
dActive={[tab, setTab]}
dActive={tab}
dSize="smaller"
dCenter
onActiveChange={(id) => {
setTab(id);
}}
/>
)}
</div>
Expand Down
12 changes: 11 additions & 1 deletion packages/site/src/app/styles/_app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,17 @@ h3 {
}
}

@each $id, $selector in ('Tag': 'tag', 'Select': 'select', 'Cascader': 'cascader', 'Radio': 'radio', 'Input': 'input', 'Switch': 'switch')
@each $id,
$selector
in (
'Tag': 'tag',
'Select': 'select',
'Cascader': 'cascader',
'Radio': 'radio',
'Input': 'input',
'Switch': 'switch',
'Time-picker': 'time-picker'
)
{
section[id^='#{$id}'] {
.d-#{$selector} {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/_alert-dialog/AlertDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface DAlertDialogProps extends React.HTMLAttributes<HTMLDivElement>
onClose?: () => void;
}

export function DAlertDialog(props: DAlertDialogProps): JSX.Element | null {
export function DAlertDialog(props: DAlertDialogProps) {
const {
children,
dDuration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React, { useContext } from 'react';
import { DComposeContext } from '../compose';
import { DFormContext } from '../form';

export interface DBaseSupportProps {
export interface DBaseDesignProps {
children: React.ReactElement;
dCompose?: {
active?: boolean;
Expand All @@ -14,7 +14,7 @@ export interface DBaseSupportProps {
dFormControl?: DFormControl;
}

export function DBaseSupport(props: DBaseSupportProps): JSX.Element | null {
export function DBaseDesign(props: DBaseDesignProps) {
const { children, dCompose, dFormControl } = props;

const composeContext = useContext(DComposeContext);
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/components/_base-design/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './BaseDesign';
7 changes: 4 additions & 3 deletions packages/ui/src/components/_base-input/BaseInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { usePrefixConfig } from '../../hooks';
import { DFormContext } from '../form';

export interface DBaseInputProps extends React.InputHTMLAttributes<any> {
dTag?: string;
dFormControl?: DFormControl;
dTag?: string;
dFor?: boolean;
}

function BaseInput(props: DBaseInputProps, ref: React.ForwardedRef<any>) {
const { dTag = 'input', dFormControl, ...restProps } = props;
const { dFormControl, dTag = 'input', dFor = true, ...restProps } = props;

//#region Context
const dPrefix = usePrefixConfig();
Expand All @@ -26,7 +27,7 @@ function BaseInput(props: DBaseInputProps, ref: React.ForwardedRef<any>) {

const attrs = supportForm
? {
'data-form-support-input': true,
'data-form-label-for': dFor,
...dFormControl.inputAttrs,
}
: {};
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/components/_base-support/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/ui/src/components/_focus-visible/FocusVisible.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface DFocusVisibleProps {
children: React.ReactElement;
onFocusVisibleChange?: (visible: boolean) => void;
}
export function DFocusVisible(props: DFocusVisibleProps): JSX.Element | null {
export function DFocusVisible(props: DFocusVisibleProps) {
const { children, onFocusVisibleChange } = props;

const dataRef = useRef({
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/_footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface DFooterProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
onClose?: () => void;
}

export function DFooter(props: DFooterProps): JSX.Element | null {
export function DFooter(props: DFooterProps) {
const {
dAlign = 'right',
dButtons = ['cancel', 'ok'],
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/_header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface DHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
onClose?: () => void;
}

export function DHeader(props: DHeaderProps): JSX.Element | null {
export function DHeader(props: DHeaderProps) {
const {
children,
dClosable = true,
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/_mask/Mask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface DMaskProps extends Omit<React.HTMLAttributes<HTMLDivElement>, '
}

const TTANSITION_DURING = 100;
export function DMask(props: DMaskProps): JSX.Element | null {
export function DMask(props: DMaskProps) {
const {
dVisible,
onClose,
Expand Down
Loading

0 comments on commit e3dc42d

Please sign in to comment.