@sio-group/form-react 0.4.1 → 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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Removed buttons and replace with ui-core-package
8
+
3
9
  ## 0.4.1
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -4,11 +4,6 @@
4
4
  ![npm](https://img.shields.io/npm/v/@sio-group/form-react)
5
5
  ![TypeScript](https://img.shields.io/badge/types-Yes-brightgreen)
6
6
 
7
- <!--
8
- [![npm version](https://img.shields.io/npm/v/@sio-group/form-validation.svg)](https://www.npmjs.com/package/@sio-group/form-validation)
9
- [![npm downloads](https://img.shields.io/npm/dm/@sio-group/form-validation.svg)](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
- **Button Props:**
219
- - `type: 'button' | 'link'`
220
- - `variant: 'primary' | 'secondary' | 'link'`
221
- - `color: 'default' | 'success' | 'warning' | 'error' | 'info'`
222
- - `label: string`
223
- - `onClick?: () => void` (for buttons)
224
- - `href?: string` (for links)
225
- - `loading?: boolean`
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, Button } from '@sio-group/form-react';
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, Button } from '@sio-group/form-react';
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.1",
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",
@@ -4,9 +4,6 @@
4
4
 
5
5
  @use "components/grid";
6
6
 
7
- @use "components/button";
8
- @use "components/link";
9
-
10
7
  @use "components/input";
11
8
  @use "components/form-field";
12
9
  @use "components/form-states";
@@ -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 "./Link";
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>
package/src/index.ts CHANGED
@@ -2,8 +2,6 @@ export { Form } from './components/Form';
2
2
 
3
3
  export { useForm } from './hooks/useForm';
4
4
 
5
- export { Button } from './components/Button';
6
- export { Link } from './components/Link';
7
5
  export * from './components/Fields';
8
6
 
9
7
  export type {
@@ -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);
@@ -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
- };