Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [progress] add progress #10

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion doc/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,34 @@
* 江湖的业务千篇一律,复杂的代码好几百行。
*/
import 'shuimo-ui-react/global.css';
import { MButton, MAvatar, MTag } from 'shuimo-ui-react';
import { MButton, MAvatar, MTag, MProgress } from 'shuimo-ui-react';
import { useState, useEffect } from 'react';

function Progress() {
const [loopPer, setLoopPer] = useState(0);

useEffect(() => {
const interval = setInterval(() => {
if (loopPer < 1000) {
setLoopPer(prevLoopPer => prevLoopPer + 1);
} else {
setLoopPer(0);
}
}, 16);
return () => clearInterval(interval);
});

return (
<MProgress
value={loopPer}
max={1000}
height={18}
showInfo={true}
>
{Math.ceil(loopPer / 10)}%
</MProgress>
);
}


export default function Page() {
Expand All @@ -30,6 +57,7 @@ export default function Page() {
<MTag type="error">你好</MTag>
<MTag type="warning">你好</MTag>
<MTag style={{ '--m-tag-bg': '#951c48' }}>菜头紫</MTag>
<Progress/>
</>
);
}
48 changes: 48 additions & 0 deletions lib/components/base/progress/MProgress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @description 进度条组件
* @author Muzych
* @date 2024/03/15 12:04
* @version v1.0.0
*/
import './progress.css';
import { ProgressProps } from './index';
import { MC, Slot } from '../../../types';
import { leaf, useProgress } from './useProgress.ts';
import { CSSProperties, useEffect, useMemo, useState } from 'react';

export default function MProgress(_props: ProgressProps & MC & Slot) {

const props = _props as Required<ProgressProps>;
const [value, setValue] = useState(props.value ?? 0);
const [max, setMax] = useState(props.max ?? 100);

useEffect(() => {
setValue(props.value ?? 0);
setMax(props.max ?? 100);
}, [props.value, props.max]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should value and max use two useEffect?
Their changes don't seem to affect each other.


const { getProgressWrapperStyle, getProgressInfo } = useProgress({ props });
const progressInfo = useMemo(() => getProgressInfo(), [value, max]);
const progressWrapperInfo = useMemo(() => {
if (props.showInfo) {
return getProgressWrapperStyle(progressInfo);
}
return undefined;
}, [props.showInfo, progressInfo]);

return (
<>
{props.showInfo ? (
<div className="m-progress-border" style={progressWrapperInfo?.baseStyle as CSSProperties}>
<div className="m-progress-per" style={progressWrapperInfo?.textStyle as CSSProperties}>
<img className="m-progress-leaf" src={leaf} alt=""/>
{_props.children}
</div>
<progress className="m-progress" value={value} max={max} style={progressInfo.style as CSSProperties | undefined}/>
</div>
) : (
<progress className="m-progress" value={value} max={max} style={progressInfo.style as CSSProperties | undefined}/>
)}
</>
);
}
Binary file added lib/components/base/progress/assets/bamboo.webp
Binary file not shown.
Binary file not shown.
Binary file added lib/components/base/progress/assets/leaf.webp
Binary file not shown.
65 changes: 65 additions & 0 deletions lib/components/base/progress/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy file from vue version , you should update comments

* @description process api type
* @author 阿怪
* @date 2022/4/17 01:12
* @version v1.0.0
*
* @name m-progress
* @docDescription progress component with shuimo-ui style.
* 水墨组件的进度条组件。
* @docUrl https://shuimo.design/progress
*
* 江湖的业务千篇一律,复杂的代码好几百行。
*/

export declare type ProgressProps = {
/**
* @description progress bar width
* 进度条的宽度
* @type number
* @default 399
*/
width?: number,
/**
* @description progress bar height
* 进度条的高度
* @type number
* @default 26.547
*/
height?: number,
/**
* @description progress value
* 进度条的值
* @type number
* @default 0
*/
value?: number,
/**
* @description progress value max
* 进度条最大值
* @type number
* @default 100
*/
max?: number,
/**
* @description display value
* 是否显示进度值
* @type boolean
* @default false
*/
showInfo?: boolean,
/**
* @description info width
* 进度值的宽度
* @type number
* @default 44
*/
infoWidth?: number,
/**
* @description leaf height
* 叶子的高度
* @type number
* @default 28
*/
leafHeight?: number
};
56 changes: 56 additions & 0 deletions lib/components/base/progress/progress.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
:root {
--m-progress-width: 300px;
--m-progress-height: unset;
}

.m-progress, .m-progress-border {
--m-progress-real-width: calc(var(--m-progress-width, 556px));
--m-progress-real-height: var(--m-progress-height, 37px);
--m-progress-bg-width: var(--m-progress-width, 556px);
--m-progress-bg-size: calc(var(--m-progress-bg-width) / 2) var(--m-progress-height);
--m-progress-leaf-height: var(--m-progress-leaf-height, 28px);
--m-progress-per-width: var(--m-progress-per-width, 80px);
--m-progress-per-height: max(var(--m-progress-per-height, 20px), var(--m-progress-leaf-height));
--m-progress-per-font-size: var(--m-progress-per-font-size, 16px);
}


.m-progress-border {
display: inline-block;
width: var(--m-progress-real-width);
}

.m-progress-per {
position: relative;
display: inline-block;
width: var(--m-progress-per-width);
height: var(--m-progress-per-height);
line-height: var(--m-progress-per-height);
top: calc(var(--m-progress-per-height) * 0.4);
font-size: var(--m-progress-per-font-size);
font-weight: bold;

& img, & span {
float: right;
}
}

.m-progress-leaf {
height: var(--m-progress-leaf-height);
}

.m-progress {
width: var(--m-progress-real-width);
height: var(--m-progress-real-height);
-webkit-appearance: none;

&::-webkit-progress-bar {
background: url('./assets/bamboo_bg.webp') repeat-x;
background-size: var(--m-progress-bg-size);
}

&::-webkit-progress-value {
background: url('./assets/bamboo.webp') repeat-x;
background-size: var(--m-progress-bg-size);
}
}
87 changes: 87 additions & 0 deletions lib/components/base/progress/useProgress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* @description progress hook
* @author 阿怪
* @date 2023/4/23 01:39
* @version v1.0.0
*
* 江湖的业务千篇一律,复杂的代码好几百行。
*/
import { ProgressProps } from './index';
// @ts-ignore todo fix this
import leafPng from './assets/leaf.webp';
import { isEmpty, notEmpty } from '../../../tools';
import { Options } from '../../../compositions/common/defineCore.ts';

export const BASE_SIZE = {
BG: { W: 556, H: 37 },
LEAF: { W: 95, H: 109 },
};

const W2H = BASE_SIZE.BG.W / BASE_SIZE.BG.H;
const LEAF_W2H = BASE_SIZE.LEAF.W / BASE_SIZE.LEAF.H;

const getSize = (w?: number, h?: number, w2h = W2H) => {
const size = {
width: w || BASE_SIZE.BG.W,
height: h || BASE_SIZE.BG.H,
};
if (isEmpty(h) && notEmpty(w)) {
return { width: w!, height: w! / w2h };
}
if (notEmpty(h) && isEmpty(w)) {
return { width: h! * w2h, height: h! };
}
return size;
};

const getTextLeft = (width: number, infoWidth: number, leafWidth: number, per: number) => {
return ((width - leafWidth) * per) / 100 - infoWidth / 2;
};


export const leaf = leafPng;


export function useProgress(options: Options<{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try this:

export function useProgress(props:ProgressProps) 

props: ProgressProps,
}>) {
const { props } = options;
const getProgressInfo = () => {
const { width, height } = getSize(props.width ?? 399, props.height ?? 26.547);

return {
style: {
'--m-progress-width': `${width}px`,
'--m-progress-height': `${height}px`,
},
width,
};
};

const getProgressWrapperStyle = (progressInfo: ReturnType<typeof getProgressInfo>) => {
const { width, style } = progressInfo;
const leafSize = getSize(undefined, props.leafHeight ?? 28, LEAF_W2H);
const per = Math.ceil((props.value / props.max) * 100);
const perWidth = leafSize.width + props.infoWidth;
const textStyle = {
left: `${getTextLeft(width, props.infoWidth ?? 44, leafSize.width, per)}px`,
};

const baseStyle = {
...style,
'--m-progress-per-height': `${leafSize.height}px`,
'--m-progress-per-width': `${perWidth}px`,
'--m-progress-leaf-height': `${props.leafHeight ?? 28}px`,
};

return {
textStyle, baseStyle,
};
};

return {
getProgressInfo,
getProgressWrapperStyle,
};

}
55 changes: 55 additions & 0 deletions lib/compositions/common/defineCore.ts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defineCore in vue version has some "historical reasons".
I don't think this is necessary in react version.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/* eslint-disable */
/**
* @description A tool for normalizing grammatical structures
* @author 阿怪
* @date 2023/6/16 11:25
* @version v1.0.0
*
* 江湖的业务千篇一律,复杂的代码好几百行。
*/

import { useRef } from 'react';

type OptionsEmpty = undefined;


type IsAllUndefined<T extends any[]> = T extends [infer H, ...infer R]
? H extends undefined
? IsAllUndefined<R>
: false
: true;

interface OptionsNotEmpty<P, V, E> {
props: Required<P>;
value: { [K in keyof V]: React.MutableRefObject<V[K]>; };
event: E;
}

type CoreArguments = keyof OptionsNotEmpty<any, any, any>;
type AnyArguments = {
[K in CoreArguments]?: any
}

type DefinedKeys<T extends AnyArguments> = { [K in keyof T]: T[K] extends undefined ? never : K }[keyof T];
type UndefinedKeys<T extends AnyArguments> = Exclude<keyof CoreArguments, DefinedKeys<T>>;

export type OptionsKeys<
A extends AnyArguments,
P, V, E,
DK extends string | number | symbol = DefinedKeys<A>,
UK extends string | number | symbol = UndefinedKeys<A>
> = {
[K in DK & keyof OptionsNotEmpty<P, V, E>]: OptionsNotEmpty<P, V, E>[K];
} & {
[K in UK & keyof OptionsNotEmpty<P, V, E>]-?: OptionsNotEmpty<P, V, E>[K];
}

export type Options<
K extends AnyArguments,
P = K['props'],
V = K['value'],
E = K['event'],
> =
IsAllUndefined<[P, V, E]> extends true
? OptionsEmpty
: OptionsKeys<K, P, V, E>;
3 changes: 3 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ export { default as MAvatar } from './components/base/avatar/MAvatar.tsx';


export { default as MTag } from './components/base/tag/MTag.tsx';


export { default as MProgress } from './components/base/progress/MProgress.tsx';
Loading