diff --git a/src/components/IconFont/icon.stories.tsx b/src/components/IconFont/icon.stories.tsx
index 60d8759..2bf0848 100644
--- a/src/components/IconFont/icon.stories.tsx
+++ b/src/components/IconFont/icon.stories.tsx
@@ -3,33 +3,33 @@ import { storiesOf } from "@storybook/react";
// import { action } from "@storybook/addon-actions";
// import { withInfo } from '@storybook/addon-info'
-import IconFont from "./index";
+import Icon from "./index";
const IconFontComp = () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
-const SpinIconFont = () => ;
+const SpinIconFont = () => ;
storiesOf("Icon图标", module)
.add("IconFont", IconFontComp)
diff --git a/src/components/IconFont/index.tsx b/src/components/IconFont/index.tsx
index 37d78d1..72cf1c9 100644
--- a/src/components/IconFont/index.tsx
+++ b/src/components/IconFont/index.tsx
@@ -32,7 +32,7 @@ function createScript() {
* import { Icon } from 'jadedui'
* ~~~
*/
-const IconFont: FC = (props) => {
+const Icon: FC = (props) => {
const { type, color, spin = false, ...restProps } = props;
createScript();
@@ -51,4 +51,4 @@ const IconFont: FC = (props) => {
);
};
-export default IconFont;
+export default Icon;
diff --git a/src/components/Rate/_style.scss b/src/components/Rate/_style.scss
new file mode 100644
index 0000000..7e1122e
--- /dev/null
+++ b/src/components/Rate/_style.scss
@@ -0,0 +1,72 @@
+.dui-rate {
+ display: flex;
+
+ svg {
+ color: $rate-color-default;
+ font-size: 25px;
+ }
+
+ .dui-rate-star:not(:last-child) {
+ margin-right: 8px;
+ }
+
+ .dui-rate-star {
+ position: relative;
+ transition: all 0.2s;
+
+ .dui-rate-star-first {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 50%;
+ height: 100%;
+ overflow: hidden;
+ opacity: 0;
+ color: $rate-color-default;
+ font-size: 25px;
+ }
+
+ .dui-rate-star-second {
+ color: $rate-color-default;
+ font-size: 25px;
+ }
+ }
+
+ .dui-rate-star:hover {
+ transform: scale(1.1);
+ }
+
+ .dui-rate-star-disabled:hover {
+ transform: none;
+ }
+
+ .dui-rate-star.ant-rate-star-half {
+ .dui-rate-star-first {
+ opacity: 1;
+ color: $rate-color;
+
+ svg {
+ color: $rate-color;
+ }
+ }
+ }
+
+ .dui-rate-star.ant-rate-star-full {
+ .dui-rate-star-first {
+ opacity: 0;
+ color: $rate-color-default;
+
+ svg {
+ color: $rate-color-default;
+ }
+ }
+
+ .dui-rate-star-second {
+ color: $rate-color;
+
+ svg {
+ color: $rate-color;
+ }
+ }
+ }
+}
diff --git a/src/components/Rate/index.tsx b/src/components/Rate/index.tsx
new file mode 100644
index 0000000..e4d2039
--- /dev/null
+++ b/src/components/Rate/index.tsx
@@ -0,0 +1,168 @@
+import React, { useEffect, useState } from "react";
+import type { ReactNode } from "react";
+import classnames from "classnames";
+import Icon from "../IconFont";
+
+export type OrientationType = "left" | "right" | "center";
+
+export interface RateProps {
+ /** 自定义样式类名 */
+ className?: string;
+ /** 自定义样式对象 */
+ style?: React.CSSProperties;
+ /** 当前数,受控值 */
+ value?: number;
+ /** 默认值 */
+ defaultValue?: number;
+ /** 只读,无法进行交互 */
+ disabled?: boolean;
+ /** 自定义字符 */
+ character?: ReactNode | ((index: number) => ReactNode);
+ /** 选择时的回调 */
+ onChange?: (value: number) => void;
+}
+
+/**
+ * Rate 评分
+ * 对评价进行展示
+ * 对事物进行快速的评级操作
+ * ### 引用方法
+ *
+ * ~~~js
+ * import { Rate } from 'jadedui'
+ * ~~~
+ */
+const Rate: React.FC = (props) => {
+ const { className, value, defaultValue, character, disabled, onChange } =
+ props;
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const [ids, setIds] = useState([0, 1, 2, 3, 4]);
+ const [rateValue, setRateValue] = useState<[number, number]>([-1, -1]);
+ // const [rateDefaultValue,setRateDefaultValue] = useState<[number,number]>([-1,-1]);
+ const [pos, setPos] = useState({
+ curIndexLi: -1,
+ curIndexStar: -1,
+ isFocus: false,
+ });
+ const cls = ["ant-rate-star-half", "ant-rate-star-full"];
+ if (
+ (value && typeof value !== "number") ||
+ (defaultValue && typeof defaultValue !== "number")
+ ) {
+ throw new Error("value or defaultValue must be a number!");
+ }
+
+ const initRate = () => {
+ if (value || defaultValue) {
+ const transValue = String(value || defaultValue).split(".");
+ const curIndexLi = Number(transValue[0]);
+ const curIndexStar = transValue[1]
+ ? Number(transValue[1]) >= 5
+ ? 0
+ : -1
+ : -1;
+ console.log("curIndexLi: ", curIndexLi);
+ console.log("curIndexStar: ", curIndexStar);
+ setRateValue([curIndexLi, curIndexStar]);
+ setPos({
+ curIndexLi,
+ curIndexStar,
+ isFocus: true,
+ });
+ }
+ };
+
+ useEffect(() => {
+ initRate();
+ }, [value]);
+
+ const onMouseFirstEnter = (d: number, curStar: number) => {
+ if (disabled) return;
+ const curIndex = ids.findIndex((id) => id == d);
+ setPos({
+ ...pos,
+ curIndexLi: curIndex,
+ curIndexStar: curStar,
+ });
+ };
+
+ const renderClassNames = (key: number) => {
+ let classNames = "dui-rate-star";
+ if (disabled) classNames += " dui-rate-star-disabled";
+ if (pos.curIndexLi === -1) {
+ classNames += " dui-rate-star-zero";
+ } else {
+ if (key < pos.curIndexLi) {
+ classNames += " ant-rate-star-full";
+ return classNames;
+ }
+ if (key == pos.curIndexLi) {
+ classNames += " " + cls[pos.curIndexStar];
+ return classNames;
+ }
+ if (key > pos.curIndexLi) {
+ classNames += " dui-rate-star-zero";
+ }
+ }
+
+ return classNames;
+ };
+
+ const rateClickHandle = (type: string, key: number) => {
+ if (value || disabled) return;
+ onMouseFirstEnter(key, type === "first" ? 0 : 1);
+ setRateValue([key, type === "first" ? 0 : 1]);
+ setPos({
+ ...pos,
+ isFocus: true,
+ });
+ onChange && onChange(type === "first" ? key + 0.5 : key + 1);
+ };
+
+ const onMouseLeave = () => {
+ if (disabled) return;
+ if (!pos.isFocus) {
+ onMouseFirstEnter(-1, -1);
+ } else {
+ onMouseFirstEnter(...rateValue);
+ }
+ };
+
+ const renderNode = (key: number) =>
+ typeof character === "function" ? character(key) : character;
+
+ return (
+
+ {ids.map((key) => {
+ return (
+ -
+
onMouseFirstEnter(key, 0)}
+ onClick={() => rateClickHandle("first", key)}
+ >
+ {renderNode(key)}
+
+ onMouseFirstEnter(key, 1)}
+ onClick={() => rateClickHandle("second", key)}
+ >
+ {renderNode(key)}
+
+
+ );
+ })}
+
+ );
+};
+
+Rate.defaultProps = {
+ character: ,
+ disabled: false,
+};
+
+export default Rate;
diff --git a/src/components/Rate/rate.stories.tsx b/src/components/Rate/rate.stories.tsx
new file mode 100644
index 0000000..d04beb7
--- /dev/null
+++ b/src/components/Rate/rate.stories.tsx
@@ -0,0 +1,28 @@
+import React from "react";
+import { storiesOf } from "@storybook/react";
+// import { action } from "@storybook/addon-actions";
+// import { withInfo } from '@storybook/addon-info'
+
+import Rate from "./index";
+
+const defaultRate = () => {
+ const onChange = (v: any) => {
+ console.log("v: ", v);
+ };
+ return ;
+};
+
+const characterRate = () => (
+ <>
+
+
+ 星} />
+ >
+);
+
+const disableRate = () => ;
+
+storiesOf("Rate 评分", module)
+ .add("Rate", defaultRate)
+ .add("只读 Rate", disableRate)
+ .add("自定义字符 Rate", characterRate);
diff --git a/src/styles/_reboot.scss b/src/styles/_reboot.scss
index 4f782d4..403bbd4 100644
--- a/src/styles/_reboot.scss
+++ b/src/styles/_reboot.scss
@@ -150,6 +150,7 @@ address {
ol,
ul {
padding-left: 2rem;
+ list-style: none;
}
ol,
diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss
index a2ceb94..084c518 100644
--- a/src/styles/_variables.scss
+++ b/src/styles/_variables.scss
@@ -274,3 +274,7 @@ $alert-padding-x-right: 1rem !default;
$alert-font-color: #000000d9;
$alert-message-font-size: $font-size-base * 1.1 !default;
$alert-description-font-size: $font-size-base * 0.8 !default;
+
+// Rate
+$rate-color: $yellow !default;
+$rate-color-default: $gray-200 !default;
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 3374646..3bc37db 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -28,3 +28,6 @@
//Divider
@import "../components/Divider/style";
+
+//Rate
+@import "../components/Rate/style";
diff --git a/todoList.md b/todoList.md
index 722e641..f9a32d4 100644
--- a/todoList.md
+++ b/todoList.md
@@ -4,5 +4,6 @@
- 图片水印
canvas、mutationObserver
- Flip 动画思路
+- 滑动验证码