Skip to content

Commit

Permalink
Merge pull request #59 from js-tool-pack/input
Browse files Browse the repository at this point in the history
Input
  • Loading branch information
mengxinssfd authored Sep 22, 2023
2 parents 868698f + 1d56e68 commit 687f4e5
Show file tree
Hide file tree
Showing 37 changed files with 1,564 additions and 29 deletions.
30 changes: 18 additions & 12 deletions .dumirc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const env = process.env['NODE_ENV'] as ENV;

export default defineConfig({
...map[env],
mfsu: true,
// mfsu: true, // windows 系统开启该选项会启动不了
outputPath: 'docs-dist',
themeConfig: {
name: 'react-ui',
Expand Down Expand Up @@ -63,16 +63,22 @@ export default defineConfig({
],
alias: {
'@tool-pack/react-ui': Path.resolve(__dirname, 'packages/react-ui/src'),
...pkgs.reduce((prev, cur) => {
prev['@pkg/' + cur] = Path.resolve(__dirname, `packages/${cur}/src`);
return prev;
}, {} as Record<string, string>),
...components.reduce((prev, cur) => {
prev['~/' + cur] = Path.resolve(
__dirname,
`packages/components/src/${cur}`,
);
return prev;
}, {} as Record<string, string>),
...pkgs.reduce(
(prev, cur) => {
prev['@pkg/' + cur] = Path.resolve(__dirname, `packages/${cur}/src`);
return prev;
},
{} as Record<string, string>,
),
...components.reduce(
(prev, cur) => {
prev['~/' + cur] = Path.resolve(
__dirname,
`packages/components/src/${cur}`,
);
return prev;
},
{} as Record<string, string>,
),
},
});
5 changes: 5 additions & 0 deletions internal/playground/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ export const baseRouter = [
name: 'select 选择器',
path: '/select',
},
{
element: getDemos(import.meta.glob('~/input/demo/*.tsx')),
name: 'input 输入框',
path: '/input',
},
/*insert target*/
];

Expand Down
1 change: 1 addition & 0 deletions packages/components/src/icon/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
text-align: center;
fill: currentcolor;
transform: translateZ(0);
user-select: none;
> svg {
width: 1em;
height: 1em;
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
@import './transition';
@import './tag';
@import './select';
@import './input';
1 change: 1 addition & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export * from './alert';
export * from './switch';
export * from './tag';
export * from './select';
export * from './input';
174 changes: 174 additions & 0 deletions packages/components/src/input/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import {
getSizeClassName,
useForceUpdate,
useForwardRef,
getClasses,
useWatch,
} from '@pkg/shared';
import type { RequiredPart } from '@tool-pack/types';
import { InnerInput, Suffix } from './components';
import { getClassNames } from '@tool-pack/basic';
import type { InputProps } from './input.types';
import React, { useState, useRef } from 'react';

const cls = getClasses(
'input',
['clear', 'prefix', 'suffix', 'loading', 'icon', 'count', 'switch'],
['focus', 'clearable', 'disabled', 'loading', 'textarea', 'autosize'],
);
const defaultProps = {
showPasswordOn: 'click',
size: 'medium',
type: 'text',
rows: 3,
} satisfies Partial<InputProps>;

export const Input: React.FC<InputProps> = React.forwardRef<
HTMLInputElement,
InputProps
>((props, ref) => {
const {
showPasswordOn,
rootAttrs = {},
placeholder,
attrs = {},
clearable,
showCount,
maxLength,
countView,
disabled,
autoSize,
onChange,
loading,
rootRef,
prefix,
suffix,
status,
value,
count,
type,
size,
rows,
} = props as RequiredPart<InputProps, keyof typeof defaultProps>;

const forceUpdate = useForceUpdate();
const valueRef = useRef(value || '');
const containerRef = useForwardRef(rootRef);
const [innerType, setInnerType] = useState(type);

useWatch(value, (v) => {
valueRef.current = v || '';
});
useWatch(type, (v) => {
setInnerType(v);
});

const [focus, setFocus] = useState(false);

const Count = showCount && (
<div className={cls.__.count}>{getCountView()}</div>
);

return (
<label
{...rootAttrs}
className={getClassNames(
cls.root,
rootAttrs.className,
getSizeClassName(size),
{
[cls['--'].textarea]: type === 'textarea',
[cls['--'].textarea]: type === 'textarea',
[`${cls.root}--${status}`]: status,
[cls['--'].clearable]: clearable,
[cls['--'].disabled]: disabled,
[cls['--'].autosize]: autoSize,
[cls['--'].loading]: loading,
[cls['--'].focus]: focus,
},
)}
ref={containerRef}
>
{prefix && <div className={cls.__.prefix}>{prefix}</div>}
<InnerInput
placeholder={placeholder || attrs.placeholder}
onResize={onInputResize}
value={valueRef.current}
onChange={_onChange}
disabled={disabled}
autoSize={autoSize}
onFocus={_onFocus}
type={innerType}
onBlur={_onBlur}
attrs={attrs}
rows={rows}
ref={ref}
/>
<Suffix
showPasswordOn={showPasswordOn}
setInnerType={setInnerType}
value={valueRef.current}
clearable={clearable}
showCount={showCount}
innerType={innerType}
onClear={_onClear}
loading={loading}
suffix={suffix}
countEl={Count}
type={type}
/>
</label>
);

function getCountView() {
const wordCount = getWordCount(valueRef.current);
if (countView) return countView(valueRef.current, wordCount);
if (!maxLength) return <span>{wordCount}</span>;
return (
<span>
{wordCount} / {maxLength}
</span>
);
}
function getWordCount(value: string) {
if (count) return count(value);
return value.length;
}
function onInputResize(size: {
height: number;
max?: number;
min: number;
}): void {
const el = containerRef.current;
if (!el) return;

const style = getComputedStyle(el);
const padding = parseInt(style.paddingTop) + parseInt(style.paddingBottom);

el.style.height = padding + size.height + 'px';
el.style.minHeight = padding + size.min + 'px';
if (!size.max) return;
el.style.maxHeight = padding + size.max + 'px';
}
function _onClear(): void {
const value = '';
valueRef.current = value;
onChange?.(value);
forceUpdate();
}
function _onChange(value: string): void {
if (maxLength && getWordCount(value) > maxLength) return;
valueRef.current = value;
onChange?.(value);
forceUpdate();
}
function _onFocus(): void {
setFocus(true);
}
function _onBlur(): void {
setFocus(false);
}
});

Input.defaultProps = defaultProps;
Input.displayName = 'Input';
Loading

0 comments on commit 687f4e5

Please sign in to comment.