@sio-group/form-react 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +14 -46
- package/package.json +3 -2
- package/src/assets/scss/index.scss +0 -3
- package/src/components/Form.tsx +1 -3
- package/src/index.ts +0 -2
- package/src/types/index.ts +0 -1
- package/src/assets/scss/components/button.scss +0 -164
- package/src/assets/scss/components/link.scss +0 -66
- package/src/components/Button/index.tsx +0 -106
- package/src/components/Link/index.tsx +0 -106
- package/src/types/ui-props.d.ts +0 -33
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -4,11 +4,6 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
<!--
|
|
8
|
-
[](https://www.npmjs.com/package/@sio-group/form-validation)
|
|
9
|
-
[](https://www.npmjs.com/package/@sio-group/form-validation)
|
|
10
|
-
-->
|
|
11
|
-
|
|
12
7
|
A powerful, type-safe React form framework. This package provides ready-to-use form components with built-in validation, layout management, and extensive customization options. This package is designed to work seamlessly with `@sio-group/form-builder` and `@sio-group/form-validation`, but can be used independently.
|
|
13
8
|
|
|
14
9
|
Part of the SIO Form ecosystem, it consumes form definitions from `@sio-group/form-builder` and renders them with full type safety and accessibility in mind.
|
|
@@ -187,7 +182,7 @@ const layout = [
|
|
|
187
182
|
|
|
188
183
|
### Button Configuration
|
|
189
184
|
|
|
190
|
-
Buttons can be configured as an array
|
|
185
|
+
Buttons can be configured as an array using the props from `@sio-group/ui-core`.
|
|
191
186
|
|
|
192
187
|
```tsx
|
|
193
188
|
const buttons = [
|
|
@@ -207,7 +202,6 @@ const buttons = [
|
|
|
207
202
|
},
|
|
208
203
|
{
|
|
209
204
|
type: 'link',
|
|
210
|
-
variant: 'link',
|
|
211
205
|
color: 'info',
|
|
212
206
|
label: 'Help',
|
|
213
207
|
href: '/help'
|
|
@@ -215,15 +209,14 @@ const buttons = [
|
|
|
215
209
|
];
|
|
216
210
|
```
|
|
217
211
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
- `
|
|
221
|
-
- `
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
-
|
|
226
|
-
- `disabled?: boolean`
|
|
212
|
+
Button and link properties are inherited from the UI components:
|
|
213
|
+
|
|
214
|
+
- `Button` from `@sio-group/ui-core`
|
|
215
|
+
- `Link` from `@sio-group/ui-core`
|
|
216
|
+
|
|
217
|
+
Refer to their documentation for all available props.
|
|
218
|
+
|
|
219
|
+
[@sio-group/ui-core](https://github.com/SiO-group/UI-React/tree/main/packages/ui-core)
|
|
227
220
|
|
|
228
221
|
---
|
|
229
222
|
|
|
@@ -489,7 +482,8 @@ All standard HTML input types are supported:
|
|
|
489
482
|
You can use the `useForm` hook to control how you use the form, centrally managing state, validation, and submission. This also demonstrates conditional rendering and error automation.
|
|
490
483
|
|
|
491
484
|
```javascript
|
|
492
|
-
import { useForm, Input
|
|
485
|
+
import { useForm, Input } from '@sio-group/form-react';
|
|
486
|
+
import { Button } from '@sio-group/ui-core';
|
|
493
487
|
|
|
494
488
|
function FormWithHook() {
|
|
495
489
|
const { register, getValue, isValid, isBusy, submit } = useForm();
|
|
@@ -536,7 +530,8 @@ All field components and buttons can also be used independently. You can keep an
|
|
|
536
530
|
|
|
537
531
|
```javascript
|
|
538
532
|
import { useState } from 'react';
|
|
539
|
-
import { Input
|
|
533
|
+
import { Input } from '@sio-group/form-react';
|
|
534
|
+
import { Button } from '@sio-group/ui-core';
|
|
540
535
|
|
|
541
536
|
function SimpleForm() {
|
|
542
537
|
const [value, setValue] = useState('');
|
|
@@ -591,34 +586,6 @@ function SimpleForm() {
|
|
|
591
586
|
}
|
|
592
587
|
```
|
|
593
588
|
|
|
594
|
-
### Button Props
|
|
595
|
-
| Prop | Type | Default | Description |
|
|
596
|
-
|------------|------------------------------------------------------------|-------------|-------------------------|
|
|
597
|
-
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Button type |
|
|
598
|
-
| `label` | `string` | - | Label of the Link |
|
|
599
|
-
| `onClick` | `(e: React.MouseEvent) => void` | - | Custom onClick function |
|
|
600
|
-
| `variant` | `'primary' \| 'secondary' \| 'link'` | `'primary'` | Visual variant |
|
|
601
|
-
| `color` | `'default' \| 'error' \| 'success' \| 'warning' \| 'info'` | `'default'` | Color theme |
|
|
602
|
-
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
|
|
603
|
-
| `block` | `boolean` | `false` | Full width |
|
|
604
|
-
| `loading` | `boolean` | `false` | Loading state |
|
|
605
|
-
| `disabled` | `boolean` | `false` | Disabled state |
|
|
606
|
-
|
|
607
|
-
### Link Props
|
|
608
|
-
| Prop | Type | Default | Description |
|
|
609
|
-
|------------|------------------------------------------------------------|-------------|--------------------------|
|
|
610
|
-
| `label` | `string` | - | Label of the Link |
|
|
611
|
-
| `to` | `string` | `'#'` | URL or pad |
|
|
612
|
-
| `onClick` | `(e: React.MouseEvent) => void` | - | Custom onClick function |
|
|
613
|
-
| `color` | `'default' \| 'error' \| 'success' \| 'warning' \| 'info'` | `'default'` | Color theme |
|
|
614
|
-
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
|
|
615
|
-
| `block` | `boolean` | `false` | Full width |
|
|
616
|
-
| `loading` | `boolean` | `false` | Loading state |
|
|
617
|
-
| `disabled` | `boolean` | `false` | Disabled state |
|
|
618
|
-
| `navigate` | `() => void` | - | Custom navigate function |
|
|
619
|
-
| `external` | `boolean` | `false` | Force external link |
|
|
620
|
-
|
|
621
|
-
|
|
622
589
|
---
|
|
623
590
|
|
|
624
591
|
## Styling
|
|
@@ -683,6 +650,7 @@ Example with Tailwind CSS:
|
|
|
683
650
|
import { Form } from '@sio-group/form-react';
|
|
684
651
|
import { formBuilder } from '@sio-group/form-builder';
|
|
685
652
|
import '@sio-group/form-react/sio-form-style.css';
|
|
653
|
+
import '@sio-group/ui-core/sio-core-style.css';
|
|
686
654
|
|
|
687
655
|
function RegistrationForm() {
|
|
688
656
|
const fields = formBuilder()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sio-group/form-react",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"description": "",
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@sio-group/form-types": "0.1.3",
|
|
31
|
-
"@sio-group/form-validation": "0.1.3"
|
|
31
|
+
"@sio-group/form-validation": "0.1.3",
|
|
32
|
+
"@sio-group/ui-core": "~0.1.1"
|
|
32
33
|
},
|
|
33
34
|
"peerDependencies": {
|
|
34
35
|
"react": "^19",
|
package/src/components/Form.tsx
CHANGED
|
@@ -5,8 +5,7 @@ import { useForm } from "../hooks/useForm";
|
|
|
5
5
|
import { ButtonProps, LinkProps, FormLayout, RadioFieldProps, SelectFieldProps, TextareaFieldProps } from "../types";
|
|
6
6
|
import { getColumnClasses } from "../utils/get-column-classes";
|
|
7
7
|
import { Checkbox, Input, Radio, Select, Textarea } from "./Fields";
|
|
8
|
-
import { Link } from "
|
|
9
|
-
import { Button } from "./Button";
|
|
8
|
+
import { Link, Button } from "@sio-group/ui-core";
|
|
10
9
|
|
|
11
10
|
const DefaultContainer: React.FC<FormContainerProps> = ({ children }) => (
|
|
12
11
|
<div>{children}</div>
|
|
@@ -146,7 +145,6 @@ export const Form = ({
|
|
|
146
145
|
onClick={handleCancel}
|
|
147
146
|
variant='secondary'
|
|
148
147
|
label={cancelLabel}
|
|
149
|
-
disabled={!isDirty()}
|
|
150
148
|
/>
|
|
151
149
|
)}
|
|
152
150
|
{buttons?.map(renderButton)}
|
package/src/index.ts
CHANGED
package/src/types/index.ts
CHANGED
|
@@ -14,5 +14,4 @@ export type { FieldSetters } from './field-setters';
|
|
|
14
14
|
export type { FieldType, FieldState, FieldValue } from './field-state';
|
|
15
15
|
export type { FormConfig } from './form-config';
|
|
16
16
|
export type { FormLayout } from './form-layout';
|
|
17
|
-
export type { ButtonProps, LinkProps } from './ui-props';
|
|
18
17
|
export type { UseFormOptions } from './use-form-options';
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
@use "../utilities/mixins" as *;
|
|
2
|
-
@use "../tokens/colors" as *;
|
|
3
|
-
|
|
4
|
-
:where(.btn--primary) {
|
|
5
|
-
--sio-btn-bg: var(--sio-btn-primary-bg);
|
|
6
|
-
--sio-btn-border: var(--sio-btn-primary-border);
|
|
7
|
-
--sio-btn-text: var(--sio-btn-primary-text);
|
|
8
|
-
|
|
9
|
-
--sio-btn-bg-hover: color-mix(in srgb, var(--sio-btn-bg) 85%, black);
|
|
10
|
-
--sio-btn-border-hover: color-mix(in srgb, var(--sio-btn-border) 85%, black);
|
|
11
|
-
--sio-btn-text-hover: var(--sio-btn-text);
|
|
12
|
-
|
|
13
|
-
--sio-btn-bg-disabled: color-mix(in srgb, var(--sio-btn-bg) 40%, white);
|
|
14
|
-
--sio-btn-border-disabled: color-mix(in srgb, var(--sio-btn-border) 40%, white);
|
|
15
|
-
--sio-btn-text-disabled: color-mix(in srgb, var(--sio-btn-text) 60%, black);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
:where(.btn--secondary) {
|
|
19
|
-
--sio-btn-bg: var(--sio-btn-secondary-bg);
|
|
20
|
-
--sio-btn-border: var(--sio-btn-secondary-border);
|
|
21
|
-
--sio-btn-text: var(--sio-btn-secondary-text);
|
|
22
|
-
|
|
23
|
-
--sio-btn-bg-hover: var(--sio-btn-bg);
|
|
24
|
-
--sio-btn-border-hover: color-mix(in srgb, var(--sio-btn-border) 85%, black);
|
|
25
|
-
--sio-btn-text-hover: var(--sio-btn-text);
|
|
26
|
-
|
|
27
|
-
--sio-btn-bg-disabled: var(--sio-btn-bg);
|
|
28
|
-
--sio-btn-border-disabled: color-mix(in srgb, var(--sio-btn-border) 40%, white);
|
|
29
|
-
--sio-btn-text-disabled: color-mix(in srgb, var(--sio-btn-text) 40%, white);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
:where(.btn--link) {
|
|
33
|
-
--sio-btn-bg: var(--sio-btn-link-bg);
|
|
34
|
-
--sio-btn-border: var(--sio-btn-link-border);
|
|
35
|
-
--sio-btn-text: var(--sio-btn-link-text);
|
|
36
|
-
|
|
37
|
-
--sio-btn-bg-hover: var(--sio-btn-bg);
|
|
38
|
-
--sio-btn-border-hover: var(--sio-btn-border);
|
|
39
|
-
--sio-btn-text-hover: color-mix(in srgb, var(--sio-btn-text) 85%, black);
|
|
40
|
-
|
|
41
|
-
--sio-btn-bg-disabled: var(--sio-btn-bg);
|
|
42
|
-
--sio-btn-border-disabled: var(--sio-btn-border);
|
|
43
|
-
--sio-btn-text-disabled: color-mix(in srgb, var(--sio-btn-text) 40%, white);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
:where(.btn) {
|
|
47
|
-
background-color: var(--sio-btn-bg);
|
|
48
|
-
color: var(--sio-btn-text);
|
|
49
|
-
display: inline-block;
|
|
50
|
-
font-size: .9em;
|
|
51
|
-
font-weight: 500;
|
|
52
|
-
user-select: none;
|
|
53
|
-
text-align: center;
|
|
54
|
-
border: 1px solid var(--sio-btn-border);
|
|
55
|
-
padding: 2px 15px;
|
|
56
|
-
border-radius: 3px;
|
|
57
|
-
cursor: pointer;
|
|
58
|
-
min-height: 22px;
|
|
59
|
-
transition: all .3s ease-in;
|
|
60
|
-
text-decoration: none;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
:where(.btn--link) {
|
|
64
|
-
display: inline;
|
|
65
|
-
font-weight: unset;
|
|
66
|
-
user-select: none;
|
|
67
|
-
text-align: left;
|
|
68
|
-
padding: 0;
|
|
69
|
-
border-radius: unset;
|
|
70
|
-
min-height: unset;
|
|
71
|
-
transition: all 0.3s ease-in;
|
|
72
|
-
text-decoration: underline;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
:where(.btn:hover),
|
|
76
|
-
:where(.btn:active),
|
|
77
|
-
:where(.btn:focus),
|
|
78
|
-
:where(.btn.btn--active) {
|
|
79
|
-
background: var(--sio-btn-bg-hover, var(--sio-btn-bg));
|
|
80
|
-
border-color: var(--sio-btn-border-hover, var(--sio-btn-border));
|
|
81
|
-
color: var(--sio-btn-text-hover, var(--sio-btn-text));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
:where(.btn:disabled),
|
|
85
|
-
:where(.btn.btn--disabled) {
|
|
86
|
-
cursor: not-allowed;
|
|
87
|
-
|
|
88
|
-
background: var(--sio-btn-bg-disabled, var(--sio-btn-bg));
|
|
89
|
-
border-color: var(--sio-btn-border-disabled, var(--sio-btn-border));
|
|
90
|
-
color: var(--sio-btn-text-disabled, var(--sio-btn-text));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
@each $name, $color in $colors {
|
|
94
|
-
:where(.btn--primary.btn--#{$name}) {
|
|
95
|
-
--sio-btn-bg: var(--sio-color-#{$name});
|
|
96
|
-
--sio-btn-border: var(--sio-color-#{$name});
|
|
97
|
-
--sio-btn-text: var(--sio-color-white);
|
|
98
|
-
}
|
|
99
|
-
:where(.btn--secondary.btn--#{$name}) {
|
|
100
|
-
--sio-btn-bg: transparent;
|
|
101
|
-
--sio-btn-border: var(--sio-color-#{$name});
|
|
102
|
-
--sio-btn-text: var(--sio-color-#{$name});
|
|
103
|
-
}
|
|
104
|
-
:where(.btn--link.btn--#{$name}) {
|
|
105
|
-
--sio-btn-bg: transparent;
|
|
106
|
-
--sio-btn-border: transparent;
|
|
107
|
-
--sio-btn-text: var(--sio-color-#{$name});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
:where(.btn--block) {
|
|
112
|
-
display: block;
|
|
113
|
-
width: 100%;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
:where(.btn--lg) {
|
|
117
|
-
padding: 5px 20px;
|
|
118
|
-
font-size: 1.1em;
|
|
119
|
-
min-height: 34px;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
:where(.btn--sm) {
|
|
123
|
-
padding: 2.5px 5px;
|
|
124
|
-
font-size: .7em;
|
|
125
|
-
min-height: 23px;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
:where(.btn--loading) {
|
|
129
|
-
position: relative;
|
|
130
|
-
cursor: wait !important;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
:where(.btn__spinner) {
|
|
134
|
-
display: flex;
|
|
135
|
-
animation: spin 1s infinite linear;
|
|
136
|
-
margin-right: 8px;
|
|
137
|
-
width: 20px;
|
|
138
|
-
height: 20px;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
:where(.btn__spinner svg) {
|
|
142
|
-
display: block;
|
|
143
|
-
width: 100%;
|
|
144
|
-
height: 100%;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
:where(.btn__spinner circle) {
|
|
148
|
-
fill: none;
|
|
149
|
-
stroke: currentColor;
|
|
150
|
-
stroke-width: 2;
|
|
151
|
-
stroke-dasharray: 30 100;
|
|
152
|
-
stroke-linecap: round;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
:where(.btn__loading-text) {
|
|
156
|
-
position: absolute;
|
|
157
|
-
clip: rect(1px, 1px, 1px, 1px);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
:where(.btn-group) {
|
|
161
|
-
display: flex;
|
|
162
|
-
flex-wrap: wrap;
|
|
163
|
-
gap: 5px;
|
|
164
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
@use "../utilities/mixins" as *;
|
|
2
|
-
@use "../tokens/colors" as *;
|
|
3
|
-
|
|
4
|
-
:where(.btn--link) {
|
|
5
|
-
--sio-btn-bg: var(--sio-btn-link-bg);
|
|
6
|
-
--sio-btn-border: var(--sio-btn-link-border);
|
|
7
|
-
--sio-btn-text: var(--sio-btn-link-text);
|
|
8
|
-
|
|
9
|
-
--sio-btn-bg-hover: var(--sio-btn-bg);
|
|
10
|
-
--sio-btn-border-hover: var(--sio-btn-border);
|
|
11
|
-
--sio-btn-text-hover: color-mix(in srgb, var(--sio-btn-text) 85%, black);
|
|
12
|
-
|
|
13
|
-
--sio-btn-bg-disabled: var(--sio-btn-bg);
|
|
14
|
-
--sio-btn-border-disabled: var(--sio-btn-border);
|
|
15
|
-
--sio-btn-text-disabled: color-mix(in srgb, var(--sio-btn-text) 40%, white);
|
|
16
|
-
}
|
|
17
|
-
:where(.link) {
|
|
18
|
-
display: inline;
|
|
19
|
-
user-select: none;
|
|
20
|
-
transition: all 0.3s ease-in;
|
|
21
|
-
text-decoration: underline;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
:where(.link:hover),
|
|
25
|
-
:where(.link:active),
|
|
26
|
-
:where(.link:focus),
|
|
27
|
-
:where(.link.link--active) {
|
|
28
|
-
background: var(--sio-btn-bg-hover, var(--sio-btn-bg));
|
|
29
|
-
border-color: var(--sio-btn-border-hover, var(--sio-btn-border));
|
|
30
|
-
color: var(--sio-btn-text-hover, var(--sio-btn-text));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
:where(.link:disabled),
|
|
34
|
-
:where(.link.link--disabled) {
|
|
35
|
-
cursor: not-allowed;
|
|
36
|
-
|
|
37
|
-
background: var(--sio-btn-bg-disabled, var(--sio-btn-bg));
|
|
38
|
-
border-color: var(--sio-btn-border-disabled, var(--sio-btn-border));
|
|
39
|
-
color: var(--sio-btn-text-disabled, var(--sio-btn-text));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@each $name, $color in $colors {
|
|
43
|
-
:where(.link--#{$name}) {
|
|
44
|
-
--sio-btn-bg: transparent;
|
|
45
|
-
--sio-btn-border: transparent;
|
|
46
|
-
--sio-btn-text: var(--sio-color-#{$name});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
:where(.link--block) {
|
|
51
|
-
display: block;
|
|
52
|
-
width: 100%;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
:where(.link--lg) {
|
|
56
|
-
font-size: 1.1em;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
:where(.link--sm) {
|
|
60
|
-
font-size: .7em;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
:where(.link--loading) {
|
|
64
|
-
position: relative;
|
|
65
|
-
cursor: wait !important;
|
|
66
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { ButtonProps } from "../../types";
|
|
3
|
-
|
|
4
|
-
const ButtonComponent: React.FC<ButtonProps> = ({
|
|
5
|
-
type = 'button',
|
|
6
|
-
label,
|
|
7
|
-
onClick,
|
|
8
|
-
variant = 'primary',
|
|
9
|
-
color = 'default',
|
|
10
|
-
size = 'md',
|
|
11
|
-
block = false,
|
|
12
|
-
loading = false,
|
|
13
|
-
disabled = false,
|
|
14
|
-
className = '',
|
|
15
|
-
ariaLabel = '',
|
|
16
|
-
style = {},
|
|
17
|
-
children,
|
|
18
|
-
}: ButtonProps) => {
|
|
19
|
-
const isDisabled: boolean = disabled || loading;
|
|
20
|
-
|
|
21
|
-
const handleClick = (e: React.MouseEvent) => {
|
|
22
|
-
if (isDisabled) {
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
onClick?.(e);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const buttonClasses = [
|
|
31
|
-
'btn',
|
|
32
|
-
`btn--${variant}`,
|
|
33
|
-
`btn--${size}`,
|
|
34
|
-
`btn--${color}`,
|
|
35
|
-
block && 'btn--block',
|
|
36
|
-
loading && 'btn--loading',
|
|
37
|
-
isDisabled && 'btn--disabled',
|
|
38
|
-
className,
|
|
39
|
-
]
|
|
40
|
-
.filter(Boolean)
|
|
41
|
-
.join(' ');
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<button
|
|
45
|
-
type={type}
|
|
46
|
-
onClick={handleClick}
|
|
47
|
-
className={buttonClasses}
|
|
48
|
-
style={style}
|
|
49
|
-
disabled={isDisabled}
|
|
50
|
-
aria-label={ariaLabel || (label as string)}
|
|
51
|
-
aria-busy={loading}
|
|
52
|
-
aria-disabled={isDisabled}>
|
|
53
|
-
{loading ? (
|
|
54
|
-
<>
|
|
55
|
-
<span className='btn__spinner' aria-hidden='true'>
|
|
56
|
-
<svg viewBox='0 0 20 20'>
|
|
57
|
-
<circle cx='10' cy='10' r='8' />
|
|
58
|
-
</svg>
|
|
59
|
-
</span>
|
|
60
|
-
<span className='btn__loading-text'>Processing...</span>
|
|
61
|
-
</>
|
|
62
|
-
) : (
|
|
63
|
-
<>
|
|
64
|
-
{children}
|
|
65
|
-
{label}
|
|
66
|
-
</>
|
|
67
|
-
)}
|
|
68
|
-
</button>
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Button component for user interaction.
|
|
74
|
-
*
|
|
75
|
-
* @component
|
|
76
|
-
* @example
|
|
77
|
-
* // Primaire button
|
|
78
|
-
* <Button label="Save" onClick={handleSave} />
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* // Submit button with loading state
|
|
82
|
-
* <Button
|
|
83
|
-
* type="submit"
|
|
84
|
-
* label="Send"
|
|
85
|
-
* variant="primary"
|
|
86
|
-
* loading
|
|
87
|
-
* />
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* // Button with icon and tekst
|
|
91
|
-
* <Button type="button" onClick={handleClick}>
|
|
92
|
-
* <Icon name="plus" />
|
|
93
|
-
* <span>Add</span>
|
|
94
|
-
* </Button>
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* // Error variant
|
|
98
|
-
* <Button
|
|
99
|
-
* type="button"
|
|
100
|
-
* label="Delete"
|
|
101
|
-
* variant="secondary"
|
|
102
|
-
* color="error"
|
|
103
|
-
* onClick={handleDelete}
|
|
104
|
-
* />
|
|
105
|
-
*/
|
|
106
|
-
export const Button: React.FC<ButtonProps> = React.memo(ButtonComponent);
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { LinkProps } from "../../types";
|
|
2
|
-
import React from "react";
|
|
3
|
-
|
|
4
|
-
const LinkComponent: React.FC<LinkProps> = ({
|
|
5
|
-
label,
|
|
6
|
-
to = '#',
|
|
7
|
-
onClick,
|
|
8
|
-
color = 'default',
|
|
9
|
-
size = 'md',
|
|
10
|
-
block = false,
|
|
11
|
-
loading = false,
|
|
12
|
-
disabled = false,
|
|
13
|
-
className = '',
|
|
14
|
-
ariaLabel = '',
|
|
15
|
-
navigate,
|
|
16
|
-
external = false,
|
|
17
|
-
style = {},
|
|
18
|
-
children,
|
|
19
|
-
}: LinkProps) => {
|
|
20
|
-
const isDisabled: boolean = disabled || loading;
|
|
21
|
-
const isExternal: boolean = external || /^(https?:|mailto:|tel:|ftp:)/.test(to);
|
|
22
|
-
|
|
23
|
-
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
24
|
-
if (isDisabled) {
|
|
25
|
-
e.preventDefault();
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
onClick?.(e);
|
|
30
|
-
|
|
31
|
-
if (!isExternal && navigate) {
|
|
32
|
-
e.preventDefault();
|
|
33
|
-
navigate();
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const linkClasses = [
|
|
38
|
-
'link',
|
|
39
|
-
`link--${color}`,
|
|
40
|
-
`btn--${size}`,
|
|
41
|
-
block && 'link--block',
|
|
42
|
-
loading && 'link--loading',
|
|
43
|
-
isDisabled && 'link--disabled',
|
|
44
|
-
className,
|
|
45
|
-
]
|
|
46
|
-
.filter(Boolean)
|
|
47
|
-
.join(' ');
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<a
|
|
51
|
-
href={isDisabled ? undefined : to}
|
|
52
|
-
onClick={handleClick}
|
|
53
|
-
className={linkClasses}
|
|
54
|
-
style={style}
|
|
55
|
-
aria-label={ariaLabel || (label as string)}
|
|
56
|
-
aria-busy={loading}
|
|
57
|
-
aria-disabled={isDisabled}
|
|
58
|
-
target={isExternal ? '_blank' : undefined}
|
|
59
|
-
rel={isExternal ? 'noopener noreferrer' : undefined}>
|
|
60
|
-
{loading ? (
|
|
61
|
-
<>
|
|
62
|
-
<span className='btn__spinner' aria-hidden='true'>
|
|
63
|
-
<svg viewBox='0 0 20 20'>
|
|
64
|
-
<circle cx='10' cy='10' r='8' />
|
|
65
|
-
</svg>
|
|
66
|
-
</span>
|
|
67
|
-
<span className='btn__loading-text'>Processing...</span>
|
|
68
|
-
</>
|
|
69
|
-
) : (
|
|
70
|
-
<>
|
|
71
|
-
{children}
|
|
72
|
-
{label && <span className="btn__label">{label}</span>}
|
|
73
|
-
</>
|
|
74
|
-
)}
|
|
75
|
-
</a>
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Custom Link component for internal or external navigation
|
|
81
|
-
*
|
|
82
|
-
* @component
|
|
83
|
-
* @example
|
|
84
|
-
* // Internal link
|
|
85
|
-
* <Link to="/dashboard" label="Dashboard" />
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* // External link
|
|
89
|
-
* // external property is optional
|
|
90
|
-
* // http(s), ftp, email and tel with automatically render as external
|
|
91
|
-
* <Link to="https://example.com" label="Visit website" external />
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* // Link with loading state
|
|
95
|
-
* <Link to="/profile" label="Profile" loading />
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* // Link with custom click handler en navigation
|
|
99
|
-
* <Link
|
|
100
|
-
* to="/settings"
|
|
101
|
-
* label="Settings"
|
|
102
|
-
* onClick={() => console.log('clicked')}
|
|
103
|
-
* navigate={customNavigate}
|
|
104
|
-
* />
|
|
105
|
-
*/
|
|
106
|
-
export const Link: React.FC<LinkProps> = React.memo(LinkComponent);
|
package/src/types/ui-props.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
|
-
export type ButtonType = 'button' | 'submit' | 'reset';
|
|
4
|
-
export type Variant = 'primary' | 'secondary' | 'link';
|
|
5
|
-
export type Color = 'default' | 'error' | 'success' | 'warning' | 'info';
|
|
6
|
-
export type Size = 'sm' | 'md' | 'lg';
|
|
7
|
-
|
|
8
|
-
type BaseUiProps = {
|
|
9
|
-
variant?: Variant;
|
|
10
|
-
label?: string | React.ReactNode;
|
|
11
|
-
color?: Color;
|
|
12
|
-
size?: Size;
|
|
13
|
-
block?: boolean;
|
|
14
|
-
loading?: boolean;
|
|
15
|
-
disabled?: boolean;
|
|
16
|
-
className?: string;
|
|
17
|
-
ariaLabel?: string;
|
|
18
|
-
style?: React.CSSProperties;
|
|
19
|
-
children?: React.ReactNode;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type ButtonProps = BaseUiProps & {
|
|
23
|
-
type?: ButtonType;
|
|
24
|
-
onClick: (e: React.MouseEvent) => void;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export type LinkProps = Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'onClick' | 'color'> &
|
|
28
|
-
BaseUiProps & {
|
|
29
|
-
to: string;
|
|
30
|
-
navigate?: () => void;
|
|
31
|
-
external?: boolean;
|
|
32
|
-
onClick?: (e: React.MouseEvent) => void;
|
|
33
|
-
};
|