Skip to content

Commit

Permalink
feat: Universal package input element support (#5)
Browse files Browse the repository at this point in the history
* feat: Input Init

* feat: Input Element Done
  • Loading branch information
MaxtuneLee authored Mar 21, 2024
1 parent e37ee38 commit 465eb8c
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 2 deletions.
3 changes: 2 additions & 1 deletion docs/docs/components/universal/_meta.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[
"index",
"button",
"accordion"
"accordion",
"input"
]
93 changes: 93 additions & 0 deletions docs/docs/components/universal/input.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Wraper from '../../tools/wraper/index'
import {Input} from '@sast/ui-universal'


# Input Component

Input component allows users to input text or passwords.

<Wraper>
<s-input
label="Username"
></s-input>
</Wraper>

## Properties

| Property | Description | Type | Default |
|------------------|-----------------------------------------------|---------------------------------------------------------|---------|
| `width` | The width of the Input. | `number` | `250` |
| `disabled` | If `true`, the input will be disabled. | `boolean` | `false` |
| `label` | The label of the input. | `string` | `"输入框"` |
| `mode` | The type of the input (text or password). | `"text"`, `"password"` | `"text"` |
| `placeholder` | The placeholder of the input. | `string` | |
| `fontsize` | The font size of the input. | `number` | `16` |
| `isFillFather` | If `true`, the input will fill its container.| `boolean` | `false` |
| `value` | The value of the input. | `string` | |
| `defaultValue` | The default value of the input. | `string` | |
| `isBorder` | If `true`, the input will have a border. | `boolean` | `true` |

## Example in HTML
```html
<s-input
width="300"
disabled="false"
label="Username"
></s-input>
```

## How to fire events

```jsx
import React, {useRef} from 'react';
import { Input, Button } from '@sast/ui-universal';

export default function App () {
const handleChange = (e) => {
console.log(e.target.value);
}
const handleBlur = (e) => {
console.log(e.target.value);
}
const handleClick = () => {
inputRef.current.value = '';
}
const inputRef = useRef(null);

return (
<>
<Input
ref={inputRef}
width={300}
label="Username"
onInput={handleChange}
onBlur={handleBlur}
/>
<Button onClick={handleClick}>Clear</Button>
</>
);
}

```


## Try yourself

```jsx
import React from 'react';
import { Input } from '@sast/ui-universal';

export default function App (){
return (
<Input
width={300}
disabled={false}
label="Username"
mode="text"
fontsize={18}
isFillFather={false}
isBorder={true}
/>
);
}
```
71 changes: 71 additions & 0 deletions packages/ui-universal/lib/components/Input/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
@use "../../variables" as *;
@use "../../_variables/color.scss" as *;

$border-radius: $radius-8;
$border-width: $border-1;
$font-size-select: $font-size-14;
$font-size-label: $font-size-10;
$padding-left-right: 11px;
$padding-label-top: 8px;
$animation-duration: $duration-200;
.base {
width: fit-content;
border-radius: $border-radius;
box-sizing: border-box;
color: var(--shadow-color);
position: relative;
transition: all $animation-duration $cubic-bezier;
font-weight: 500;
background-color: var(--white-color);
&.border {
border: $border-width solid var(--shadow-color) !important;
&:hover:not(&.disabled) {
border: $border-width solid var(--primary-color) !important;
}
&:has(.input:focus) {
border: $border-width solid var(--primary-color) !important;
}
}
cursor: text;
.inputLabel {
position: absolute;
transition: all $animation-duration $cubic-bezier;
top: 50%;
transform: translate(0, -50%);
left: $padding-left-right;
font-size: $font-size-select;
}
.isUpInputLabel {
top: $padding-label-top;
font-size: $font-size-label;
transform: translate(0);
}

.input:focus ~ .inputLabel {
color: var(--primary-color) !important;
top: $padding-label-top;
font-size: $font-size-label;
transform: translate(0);
}

.input {
all: unset;
padding: 22px $padding-left-right 8px $padding-left-right;
width: -webkit-fill-available;
position: relative;
top: 0;
bottom: 0;
color: var(--black-color);
box-sizing: border-box;
font-size: $font-size-select;
}
&.disabled {
@include disabled;
}
&.fill {
width: 100% !important;
.input {
width: 100% !important;
}
}
}
126 changes: 126 additions & 0 deletions packages/ui-universal/lib/components/Input/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { LitElement, html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import styles from "./index.scss?inline";
import { ifDefined } from "lit/directives/if-defined.js";
import { createComponent } from "@lit/react";
import React from "react";
import { classMap } from "lit/directives/class-map.js";

export interface InputProps {
/**
* The width of the Input.
*/
width: number;
/**
* If `true`, the input will be disabled.
*/
disabled: boolean;
/**
* label,the label of the input
*/
label: string;
/**
* The type of the mode.
*/
mode: "text" | "password";
/**
* placeholder,the placeholder of the input
*/
placeholder?: string;
/**
* placeholder,the placeholder of the input
*/
fontsize: number;
/**
* isFillFather, is ture the input fill the father
*/
isFillFather: boolean;
/**
* value ,the value of the input
*/
value: string;
/**
* defaultValue, the defaultValue of the input
*/
defaultValue?: string;
/**
* isBorder? have the border of the input
*/
isBorder: boolean;
}

@customElement("s-input")
export class SInput extends LitElement {
static styles = styles;
@property({ type: Number }) width: InputProps["width"] = 250;
@property({ type: Boolean }) disabled: InputProps["disabled"] = false;
@property({ type: String }) label: InputProps["label"] = "输入框";
@property({ type: String }) mode: InputProps["mode"] = "text";
@property({ type: String }) placeholder: InputProps["placeholder"];
@property({ type: Number }) fontsize: InputProps["fontsize"] = 16;
@property({ type: Boolean }) isFillFather: InputProps["isFillFather"] = false;
@property({ type: String }) value: InputProps["value"] = "";
@property({ type: String }) defaultValue: InputProps["defaultValue"];
@property({ type: Boolean }) isBorder: InputProps["isBorder"] = true;

@state() isFocus = false;

handleInput(e: InputEvent) {
const target = e.target as HTMLInputElement;
this.value = target.value;
}

handleFocus() {
this.isFocus = true;
}

handleBlur() {
this.isFocus = false;
}

protected render() {
return html`
<div
class="base ${classMap({
disabled: this.disabled,
fill: this.isFillFather,
border: this.isBorder,
})}"
style="width:${this.width}px;--input-font-size:${this.fontsize}px;"
>
${this.label
? html`<label htmlFor="input" class="inputLabel ${classMap({ isUpInputLabel: !!(this.value || this.placeholder || this.isFocus) })}">${this.label}</label>`
: ""}
<input
id="input"
class="input"
type="${ifDefined(this.mode)}"
placeholder=${ifDefined(this.placeholder)}
.value="${this.value}"
.disabled="${this.disabled}"
@input="${this.handleInput}"
@focus="${this.handleFocus}"
@blur="${this.handleBlur}"
/>
</div>
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"s-input": SInput;
}
}

export const Input = createComponent({
tagName: "s-input",
elementClass: SInput,
react: React,
events: {
onchange: "onChange",
focus: "onFocus",
blur: "onBlur",
}
});

3 changes: 2 additions & 1 deletion packages/ui-universal/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./components/Button";
export * from "./components/Accordion";
export * from "./components/Accordion";
export * from "./components/Input";

0 comments on commit 465eb8c

Please sign in to comment.