fiboui 1.0.0

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.
Files changed (141) hide show
  1. package/README.md +101 -0
  2. package/dist/content/Alert/index.d.ts +878 -0
  3. package/dist/content/Avatar/index.d.ts +886 -0
  4. package/dist/content/Badge/index.d.ts +887 -0
  5. package/dist/content/Image/index.d.ts +893 -0
  6. package/dist/content/Label/index.d.ts +879 -0
  7. package/dist/content/Progress/index.d.ts +898 -0
  8. package/dist/content/Skeleton/index.d.ts +879 -0
  9. package/dist/content/Spinner/index.d.ts +880 -0
  10. package/dist/content/Text/index.d.ts +878 -0
  11. package/dist/content/index.d.ts +9 -0
  12. package/dist/core/StateWrapper.d.ts +28 -0
  13. package/dist/core/builder.d.ts +50 -0
  14. package/dist/core/component.d.ts +7 -0
  15. package/dist/core/effects.d.ts +3 -0
  16. package/dist/core/icons.d.ts +11 -0
  17. package/dist/core/index.d.ts +5 -0
  18. package/dist/core/state.d.ts +37 -0
  19. package/dist/core/types.d.ts +51 -0
  20. package/dist/demo.d.ts +7 -0
  21. package/dist/effects-Co9C_Dyx.mjs +9 -0
  22. package/dist/examples/ScaffoldExamples.d.ts +3 -0
  23. package/dist/examples/StateExamples.d.ts +5 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.esm.js +4622 -0
  26. package/dist/index.umd.js +251 -0
  27. package/dist/interactive/Button/index.d.ts +897 -0
  28. package/dist/interactive/Checkbox/index.d.ts +884 -0
  29. package/dist/interactive/Combobox/index.d.ts +898 -0
  30. package/dist/interactive/RadioGroup/index.d.ts +888 -0
  31. package/dist/interactive/Select/index.d.ts +895 -0
  32. package/dist/interactive/Switch/index.d.ts +881 -0
  33. package/dist/interactive/TextField/index.d.ts +892 -0
  34. package/dist/interactive/Textarea/index.d.ts +890 -0
  35. package/dist/interactive/index.d.ts +8 -0
  36. package/dist/layout/Center/index.d.ts +869 -0
  37. package/dist/layout/Column/index.d.ts +881 -0
  38. package/dist/layout/Container/index.d.ts +870 -0
  39. package/dist/layout/DashboardLayout/index.d.ts +870 -0
  40. package/dist/layout/Header/index.d.ts +870 -0
  41. package/dist/layout/Line/index.d.ts +872 -0
  42. package/dist/layout/Row/index.d.ts +879 -0
  43. package/dist/layout/Scaffold/index.d.ts +878 -0
  44. package/dist/layout/ScrollView/index.d.ts +879 -0
  45. package/dist/layout/Sidebar/index.d.ts +870 -0
  46. package/dist/layout/Spacer/index.d.ts +875 -0
  47. package/dist/layout/StakentComponents.d.ts +4 -0
  48. package/dist/layout/index.d.ts +11 -0
  49. package/dist/structure/Banner/index.d.ts +879 -0
  50. package/dist/structure/Box/index.d.ts +869 -0
  51. package/dist/structure/Card/index.d.ts +881 -0
  52. package/dist/structure/Collapse/index.d.ts +884 -0
  53. package/dist/structure/Grid/index.d.ts +1757 -0
  54. package/dist/structure/List/index.d.ts +888 -0
  55. package/dist/structure/Table/index.d.ts +895 -0
  56. package/dist/structure/Tags/index.d.ts +876 -0
  57. package/dist/structure/cards/AssetCard/index.d.ts +884 -0
  58. package/dist/structure/cards/CollectionCard/index.d.ts +880 -0
  59. package/dist/structure/cards/ContentCard/index.d.ts +884 -0
  60. package/dist/structure/cards/ProfileCard/index.d.ts +892 -0
  61. package/dist/structure/cards/index.d.ts +5 -0
  62. package/dist/structure/cards/variants/index.d.ts +3490 -0
  63. package/dist/structure/index.d.ts +9 -0
  64. package/dist/style.css +1 -0
  65. package/dist/theme/cupertino.d.ts +3 -0
  66. package/dist/theme/index.d.ts +5 -0
  67. package/dist/theme/material.d.ts +3 -0
  68. package/dist/theme/provider.d.ts +16 -0
  69. package/dist/theme/types.d.ts +57 -0
  70. package/dist/theme/web.d.ts +3 -0
  71. package/package.json +54 -0
  72. package/src/content/Alert/index.ts +110 -0
  73. package/src/content/Avatar/index.ts +116 -0
  74. package/src/content/Badge/index.ts +162 -0
  75. package/src/content/Image/index.ts +137 -0
  76. package/src/content/Label/index.ts +66 -0
  77. package/src/content/Progress/index.ts +378 -0
  78. package/src/content/Skeleton/index.ts +71 -0
  79. package/src/content/Spinner/index.ts +139 -0
  80. package/src/content/Text/index.ts +74 -0
  81. package/src/content/index.ts +9 -0
  82. package/src/core/StateWrapper.tsx +105 -0
  83. package/src/core/builder.ts +259 -0
  84. package/src/core/component.ts +49 -0
  85. package/src/core/effects.ts +27 -0
  86. package/src/core/icons.tsx +57 -0
  87. package/src/core/index.ts +5 -0
  88. package/src/core/state.ts +233 -0
  89. package/src/core/types.ts +62 -0
  90. package/src/demo.tsx +1045 -0
  91. package/src/examples/ScaffoldExamples.tsx +299 -0
  92. package/src/examples/StateExamples.tsx +149 -0
  93. package/src/index.ts +8 -0
  94. package/src/interactive/Button/index.ts +218 -0
  95. package/src/interactive/Checkbox/index.ts +145 -0
  96. package/src/interactive/Combobox/index.ts +278 -0
  97. package/src/interactive/RadioGroup/index.ts +124 -0
  98. package/src/interactive/Select/index.ts +227 -0
  99. package/src/interactive/Switch/index.ts +123 -0
  100. package/src/interactive/TextField/index.ts +200 -0
  101. package/src/interactive/Textarea/index.ts +129 -0
  102. package/src/interactive/index.ts +8 -0
  103. package/src/layout/Center/index.ts +34 -0
  104. package/src/layout/Column/index.ts +101 -0
  105. package/src/layout/Container/index.ts +28 -0
  106. package/src/layout/DashboardLayout/index.ts +106 -0
  107. package/src/layout/Header/index.ts +50 -0
  108. package/src/layout/Line/index.ts +41 -0
  109. package/src/layout/Row/index.ts +93 -0
  110. package/src/layout/Scaffold/index.ts +133 -0
  111. package/src/layout/ScrollView/index.ts +67 -0
  112. package/src/layout/Sidebar/index.ts +56 -0
  113. package/src/layout/Spacer/index.ts +46 -0
  114. package/src/layout/StakentComponents.tsx +57 -0
  115. package/src/layout/index.ts +11 -0
  116. package/src/structure/Banner/index.ts +92 -0
  117. package/src/structure/Box/index.ts +45 -0
  118. package/src/structure/Card/index.ts +113 -0
  119. package/src/structure/Collapse/index.ts +122 -0
  120. package/src/structure/Grid/index.ts +197 -0
  121. package/src/structure/List/index.ts +185 -0
  122. package/src/structure/Table/index.ts +165 -0
  123. package/src/structure/Tags/index.ts +69 -0
  124. package/src/structure/cards/AssetCard/index.ts +158 -0
  125. package/src/structure/cards/CollectionCard/index.ts +95 -0
  126. package/src/structure/cards/ContentCard/index.ts +127 -0
  127. package/src/structure/cards/ProfileCard/index.ts +152 -0
  128. package/src/structure/cards/index.ts +5 -0
  129. package/src/structure/cards/variants/index.ts +301 -0
  130. package/src/structure/index.ts +10 -0
  131. package/src/styles/base.css +186 -0
  132. package/src/styles/core.css +52 -0
  133. package/src/styles/themes/cupertino.css +197 -0
  134. package/src/styles/themes/material.css +322 -0
  135. package/src/styles/themes/web.css +196 -0
  136. package/src/theme/cupertino.ts +85 -0
  137. package/src/theme/index.ts +5 -0
  138. package/src/theme/material.ts +86 -0
  139. package/src/theme/provider.tsx +76 -0
  140. package/src/theme/types.ts +62 -0
  141. package/src/theme/web.ts +82 -0
@@ -0,0 +1,227 @@
1
+ import React, { ReactElement, useState, useRef, useEffect } from 'react';
2
+ import { FiboBuilder, createBuilder } from '../../core/builder';
3
+ import { BaseProps } from '../../core/types';
4
+
5
+ interface Option {
6
+ label: string;
7
+ value: string;
8
+ }
9
+
10
+ const SelectInner = React.memo((props: any) => {
11
+ const uniqueId = React.useId();
12
+ const inputId = props.id || uniqueId;
13
+ const [isOpen, setIsOpen] = useState(false);
14
+ const containerRef = useRef<HTMLDivElement>(null);
15
+
16
+ const {
17
+ containerClass,
18
+ containerStyle,
19
+ label,
20
+ error,
21
+ value,
22
+ options = [],
23
+ placeholder,
24
+ onChange,
25
+ disabled,
26
+ multiple,
27
+ ...rest
28
+ } = props;
29
+
30
+ useEffect(() => {
31
+ const handleClickOutside = (event: MouseEvent) => {
32
+ if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
33
+ setIsOpen(false);
34
+ }
35
+ };
36
+ document.addEventListener('mousedown', handleClickOutside);
37
+ return () => document.removeEventListener('mousedown', handleClickOutside);
38
+ }, []);
39
+
40
+ const isSelected = (val: string) => {
41
+ if (multiple) {
42
+ return Array.isArray(value) && value.includes(val);
43
+ }
44
+ return value === val;
45
+ };
46
+
47
+ let displayText = '';
48
+ if (multiple) {
49
+ if (Array.isArray(value) && value.length > 0) {
50
+ displayText = options
51
+ .filter((opt: Option) => value.includes(opt.value))
52
+ .map((opt: Option) => opt.label)
53
+ .join(', ');
54
+ }
55
+ } else {
56
+ const selectedOption = options.find((opt: Option) => opt.value === value);
57
+ displayText = selectedOption ? selectedOption.label : '';
58
+ }
59
+
60
+ const handleSelect = (val: string) => {
61
+ if (disabled) return;
62
+
63
+ if (multiple) {
64
+ const currentValues = Array.isArray(value) ? [...value] : [];
65
+ const index = currentValues.indexOf(val);
66
+ if (index > -1) {
67
+ currentValues.splice(index, 1);
68
+ } else {
69
+ currentValues.push(val);
70
+ }
71
+ onChange?.(currentValues);
72
+ } else {
73
+ onChange?.(val);
74
+ setIsOpen(false);
75
+ }
76
+ };
77
+
78
+ return React.createElement(
79
+ 'div',
80
+ {
81
+ ref: containerRef,
82
+ className: containerClass,
83
+ style: containerStyle
84
+ },
85
+ React.createElement('div', { className: 'relative w-full' }, [
86
+ React.createElement('button', {
87
+ key: 'trigger',
88
+ id: inputId,
89
+ type: 'button',
90
+ disabled: disabled,
91
+ className: `fibo-textfield-input text-left w-full flex items-center justify-between ${!displayText ? 'text-gray-400' : ''}`,
92
+ onClick: () => !disabled && setIsOpen(!isOpen),
93
+ ...rest
94
+ }, [
95
+ React.createElement('span', { key: 'text', className: 'truncate' }, displayText || placeholder || ' '),
96
+ React.createElement('svg', {
97
+ key: 'icon',
98
+ className: `w-4 h-4 transition-transform ${isOpen ? 'rotate-180' : ''}`,
99
+ fill: "none",
100
+ stroke: "currentColor",
101
+ viewBox: "0 0 24 24"
102
+ }, React.createElement('path', { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }))
103
+ ]),
104
+
105
+ label && React.createElement(
106
+ 'label',
107
+ {
108
+ key: 'label',
109
+ htmlFor: inputId,
110
+ className: 'fibo-textfield-label'
111
+ },
112
+ label
113
+ ),
114
+
115
+ isOpen && React.createElement('div', {
116
+ key: 'dropdown',
117
+ className: 'absolute z-50 w-full mt-1 bg-[var(--fibo-surface)] border border-[var(--fibo-outline)] rounded-md shadow-lg max-h-60 overflow-auto focus:outline-none'
118
+ }, options.map((opt: Option) => {
119
+ const selected = isSelected(opt.value);
120
+ return React.createElement('div', {
121
+ key: opt.value,
122
+ className: `px-4 py-2 cursor-pointer text-sm hover:bg-[var(--fibo-primary-container)] hover:text-[var(--fibo-on-primary-container)] flex items-center justify-between ${selected ? 'bg-[var(--fibo-primary-container)] text-[var(--fibo-on-primary-container)] font-medium' : 'text-[var(--fibo-on-surface)]'}`,
123
+ onClick: () => handleSelect(opt.value)
124
+ }, [
125
+ React.createElement('span', { key: 'label' }, opt.label),
126
+ selected && React.createElement('svg', {
127
+ key: 'check',
128
+ className: "w-4 h-4 text-[var(--fibo-primary)]",
129
+ viewBox: "0 0 20 20",
130
+ fill: "currentColor"
131
+ }, React.createElement('path', { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }))
132
+ ])
133
+ }))
134
+ ]),
135
+
136
+ error && React.createElement(
137
+ 'span',
138
+ { className: 'text-[var(--fibo-error)] text-xs mt-1 ml-1' },
139
+ error
140
+ )
141
+ );
142
+ });
143
+
144
+ class SelectBuilder extends FiboBuilder {
145
+ private _value: string | string[] = '';
146
+ private _label: string = '';
147
+ private _placeholder: string = '';
148
+ private _disabled: boolean = false;
149
+ private _error?: string;
150
+ private _multiple: boolean = false;
151
+ private _options: Option[] = [];
152
+ private _onChange?: (value: string | string[]) => void;
153
+
154
+ value(val: string | string[]): this {
155
+ this._value = val;
156
+ return this;
157
+ }
158
+
159
+ label(val: string): this {
160
+ this._label = val;
161
+ return this;
162
+ }
163
+
164
+ placeholder(val: string): this {
165
+ this._placeholder = val;
166
+ return this;
167
+ }
168
+
169
+ options(opts: Option[]): this {
170
+ this._options = opts;
171
+ return this;
172
+ }
173
+
174
+ multiple(val: boolean = true): this {
175
+ this._multiple = val;
176
+ return this;
177
+ }
178
+
179
+ disabled(val: boolean = true): this {
180
+ this._disabled = val;
181
+ return this;
182
+ }
183
+
184
+ error(val: string): this {
185
+ this._error = val;
186
+ return this;
187
+ }
188
+
189
+ onChange(handler: (value: string | string[]) => void): this {
190
+ this._onChange = handler;
191
+ return this;
192
+ }
193
+
194
+ build(): ReactElement {
195
+ const containerClass = ['fibo-textfield-container relative', ...this._classNames]
196
+ .filter(Boolean)
197
+ .join(' ');
198
+
199
+ const props = {
200
+ containerClass,
201
+ containerStyle: this.getStyle(),
202
+ label: this._label,
203
+ error: this._error,
204
+ value: this._value,
205
+ placeholder: this._placeholder,
206
+ options: this._options,
207
+ disabled: this._disabled,
208
+ multiple: this._multiple,
209
+ onChange: this._onChange,
210
+ ...this._props
211
+ };
212
+
213
+ return React.createElement(SelectInner, props);
214
+ }
215
+ }
216
+
217
+
218
+ export const Select = createBuilder(SelectBuilder);
219
+
220
+ export interface SelectProps extends BaseProps {
221
+ value: string | string[];
222
+ label?: string;
223
+ placeholder?: string;
224
+ multiple?: boolean;
225
+ options: Option[];
226
+ onChange?: (value: string | string[]) => void;
227
+ }
@@ -0,0 +1,123 @@
1
+ import React, { ReactElement } from 'react';
2
+ import { FiboBuilder, createBuilder } from '../../core/builder';
3
+ import { BaseProps } from '../../core/types';
4
+
5
+ const SwitchInner = React.memo((props: any) => {
6
+ const {
7
+ checked,
8
+ onChange,
9
+ label,
10
+ disabled,
11
+ className,
12
+ style
13
+ } = props;
14
+
15
+
16
+ const trackBaseStyle: React.CSSProperties = {
17
+ width: '44px',
18
+ height: '24px',
19
+ borderRadius: '9999px',
20
+ position: 'relative',
21
+ transition: 'background-color 0.2s ease-in-out',
22
+ cursor: disabled ? 'not-allowed' : 'pointer',
23
+ opacity: disabled ? 0.5 : 1,
24
+ backgroundColor: checked ? 'var(--fibo-primary, #3B82F6)' : '#E5E7EB',
25
+ ...style
26
+ };
27
+
28
+ const thumbStyle: React.CSSProperties = {
29
+ width: '20px',
30
+ height: '20px',
31
+ borderRadius: '50%',
32
+ backgroundColor: 'white',
33
+ position: 'absolute',
34
+ top: '2px',
35
+ left: '2px',
36
+ transition: 'transform 0.2s ease-in-out',
37
+ transform: checked ? 'translateX(20px)' : 'translateX(0)',
38
+ boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
39
+ };
40
+
41
+ return React.createElement(
42
+ 'label',
43
+ {
44
+ className: `fibo-switch flex items-center gap-3 ${className}`
45
+ },
46
+ React.createElement(
47
+ 'div',
48
+ {
49
+ className: 'fibo-switch-track',
50
+ style: trackBaseStyle,
51
+ onClick: (e: React.MouseEvent) => {
52
+ e.preventDefault();
53
+ if (!disabled && onChange) {
54
+ onChange(!checked);
55
+ }
56
+ }
57
+ },
58
+ React.createElement('div', { style: thumbStyle })
59
+ ),
60
+ label && React.createElement(
61
+ 'span',
62
+ { className: 'text-sm font-medium text-gray-700 select-none' },
63
+ label
64
+ ),
65
+
66
+ React.createElement('input', {
67
+ type: 'checkbox',
68
+ checked: checked,
69
+ disabled: disabled,
70
+ className: 'sr-only',
71
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => !disabled && onChange?.(e.target.checked)
72
+ })
73
+ );
74
+ });
75
+
76
+ class SwitchBuilder extends FiboBuilder {
77
+ private _checked: boolean = false;
78
+ private _onChange?: (checked: boolean) => void;
79
+ private _label?: string;
80
+ private _disabled: boolean = false;
81
+
82
+ checked(value: boolean): this {
83
+ this._checked = value;
84
+ return this;
85
+ }
86
+
87
+ onChange(handler: (checked: boolean) => void): this {
88
+ this._onChange = handler;
89
+ return this;
90
+ }
91
+
92
+ label(text: string): this {
93
+ this._label = text;
94
+ return this;
95
+ }
96
+
97
+ disabled(value: boolean = true): this {
98
+ this._disabled = value;
99
+ return this;
100
+ }
101
+
102
+ build(): ReactElement {
103
+ const props = {
104
+ checked: this._checked,
105
+ onChange: this._onChange,
106
+ label: this._label,
107
+ disabled: this._disabled,
108
+ className: this.getClassName(),
109
+ style: this.getStyle()
110
+ };
111
+ return React.createElement(SwitchInner, props);
112
+ }
113
+ }
114
+
115
+
116
+ export const Switch = createBuilder(SwitchBuilder);
117
+
118
+ export interface SwitchProps extends BaseProps {
119
+ checked: boolean;
120
+ onChange?: (checked: boolean) => void;
121
+ label?: string;
122
+ disabled?: boolean;
123
+ }
@@ -0,0 +1,200 @@
1
+ import React, { ReactElement, ChangeEvent } from 'react';
2
+ import { FiboBuilder, createBuilder } from '../../core/builder';
3
+ import { BaseProps } from '../../core/types';
4
+
5
+ const applyMask = (value: string, mask: string) => {
6
+ let i = 0;
7
+ const valueChars = value.replace(/\D/g, '').split('');
8
+ let output = '';
9
+
10
+ for (let m = 0; m < mask.length; m++) {
11
+ if (i >= valueChars.length) break;
12
+
13
+ if (mask[m] === '9') {
14
+ output += valueChars[i++];
15
+ } else {
16
+ output += mask[m];
17
+ }
18
+ }
19
+ return output;
20
+ };
21
+
22
+ const TextFieldInner = React.memo((props: any) => {
23
+ const uniqueId = React.useId();
24
+ const inputId = props.id || uniqueId;
25
+ const [showPassword, setShowPassword] = React.useState(false);
26
+
27
+ const {
28
+ containerClass,
29
+ containerStyle,
30
+ label,
31
+ error,
32
+ mask,
33
+ type,
34
+ onChange,
35
+ ...inputRest
36
+ } = props;
37
+
38
+ const isPassword = type === 'password';
39
+ const effectiveType = isPassword && showPassword ? 'text' : type;
40
+
41
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
42
+ let newValue = e.target.value;
43
+ if (mask) {
44
+ newValue = applyMask(newValue, mask);
45
+
46
+ const syntheticEvent = {
47
+ ...e,
48
+ target: {
49
+ ...e.target,
50
+ value: newValue
51
+ }
52
+ } as React.ChangeEvent<HTMLInputElement>;
53
+
54
+ onChange?.(syntheticEvent);
55
+ } else {
56
+ onChange?.(e);
57
+ }
58
+ };
59
+
60
+ return React.createElement(
61
+ 'div',
62
+ { className: containerClass, style: containerStyle },
63
+ React.createElement('div', { className: 'relative w-full' }, [
64
+ React.createElement('input', {
65
+ key: 'input',
66
+ id: inputId,
67
+ className: 'fibo-textfield-input',
68
+ type: effectiveType,
69
+ onChange: handleChange,
70
+ ...inputRest
71
+ }),
72
+ label && React.createElement(
73
+ 'label',
74
+ {
75
+ key: 'label',
76
+ htmlFor: inputId,
77
+ className: 'fibo-textfield-label'
78
+ },
79
+ label
80
+ ),
81
+ isPassword && React.createElement(
82
+ 'button',
83
+ {
84
+ key: 'toggle',
85
+ type: 'button',
86
+ className: 'absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 focus:outline-none',
87
+ onClick: () => setShowPassword(!showPassword),
88
+ tabIndex: -1
89
+ },
90
+ showPassword ?
91
+ React.createElement('svg', { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" },
92
+ React.createElement('path', { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" }),
93
+ React.createElement('line', { x1: 1, y1: 1, x2: 23, y2: 23 })
94
+ ) :
95
+ React.createElement('svg', { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" },
96
+ React.createElement('path', { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
97
+ React.createElement('circle', { cx: 12, cy: 12, r: 3 })
98
+ )
99
+ )
100
+ ]),
101
+ error && React.createElement(
102
+ 'span',
103
+ { className: 'text-[var(--fibo-error)] text-xs mt-1 ml-1' },
104
+ error
105
+ )
106
+ );
107
+ });
108
+
109
+ class TextFieldBuilder extends FiboBuilder {
110
+ private _value: string = '';
111
+ private _label: string = '';
112
+ private _placeholder: string = '';
113
+ private _type: string = 'text';
114
+ private _disabled: boolean = false;
115
+ private _error?: string;
116
+ private _mask?: string;
117
+ private _onChange?: (value: string) => void;
118
+
119
+ constructor(value: string = '') {
120
+ super();
121
+ this._value = value;
122
+ }
123
+
124
+ value(val: string): this {
125
+ this._value = val;
126
+ return this;
127
+ }
128
+
129
+ label(val: string): this {
130
+ this._label = val;
131
+ return this;
132
+ }
133
+
134
+ placeholder(val: string): this {
135
+ this._placeholder = val;
136
+ return this;
137
+ }
138
+
139
+ type(val: 'text' | 'password' | 'email' | 'number' | 'tel'): this {
140
+ this._type = val;
141
+ return this;
142
+ }
143
+
144
+ mask(format: string): this {
145
+ this._mask = format;
146
+ return this;
147
+ }
148
+
149
+ disabled(val: boolean = true): this {
150
+ this._disabled = val;
151
+ return this;
152
+ }
153
+
154
+ error(val: string): this {
155
+ this._error = val;
156
+ return this;
157
+ }
158
+
159
+ onChange(handler: (value: string) => void): this {
160
+ this._onChange = handler;
161
+ return this;
162
+ }
163
+
164
+ build(): ReactElement {
165
+ const containerClass = ['fibo-textfield-container', ...this._classNames]
166
+ .filter(Boolean)
167
+ .join(' ');
168
+
169
+ const props = {
170
+ containerClass,
171
+ containerStyle: this.getStyle(),
172
+ label: this._label,
173
+ error: this._error,
174
+ value: this._value,
175
+ placeholder: this._placeholder || ' ',
176
+ type: this._type,
177
+ mask: this._mask,
178
+ disabled: this._disabled,
179
+ onChange: (e: ChangeEvent<HTMLInputElement>) => {
180
+ this._onChange?.(e.target.value);
181
+ },
182
+ ...this._props
183
+ };
184
+
185
+ return React.createElement(TextFieldInner, props);
186
+ }
187
+ }
188
+
189
+
190
+
191
+ export const TextField = createBuilder(TextFieldBuilder);
192
+
193
+ export interface TextFieldProps extends BaseProps {
194
+ value: string;
195
+ label?: string;
196
+ placeholder?: string;
197
+ onChange?: (value: string) => void;
198
+ type?: 'text' | 'password' | 'email' | 'number' | 'tel';
199
+ mask?: string;
200
+ }
@@ -0,0 +1,129 @@
1
+ import React, { ReactElement, ChangeEvent } from 'react';
2
+ import { FiboBuilder, createBuilder } from '../../core/builder';
3
+ import { BaseProps } from '../../core/types';
4
+
5
+
6
+ const TextareaInner = React.memo((props: any) => {
7
+ const uniqueId = React.useId();
8
+ const inputId = props.id || uniqueId;
9
+
10
+ const {
11
+ containerClass,
12
+ containerStyle,
13
+ label,
14
+ error,
15
+ ...inputRest
16
+ } = props;
17
+
18
+
19
+
20
+
21
+ return React.createElement(
22
+ 'div',
23
+ { className: containerClass, style: containerStyle },
24
+ React.createElement('textarea', {
25
+ id: inputId,
26
+ className: 'fibo-textarea-input',
27
+ ...inputRest
28
+ }),
29
+ label && React.createElement(
30
+ 'label',
31
+ {
32
+ htmlFor: inputId,
33
+ className: 'fibo-textarea-label'
34
+ },
35
+ label
36
+ ),
37
+ error && React.createElement(
38
+ 'span',
39
+ { className: 'text-[var(--fibo-error)] text-xs mt-1 ml-1' },
40
+ error
41
+ )
42
+ );
43
+ });
44
+
45
+ class TextareaBuilder extends FiboBuilder {
46
+ private _value: string = '';
47
+ private _label: string = '';
48
+ private _placeholder: string = '';
49
+ private _disabled: boolean = false;
50
+ private _rows: number = 4;
51
+ private _error?: string;
52
+ private _resize: 'none' | 'vertical' | 'horizontal' | 'both' = 'vertical';
53
+ private _onChange?: (value: string) => void;
54
+
55
+ value(val: string): this {
56
+ this._value = val;
57
+ return this;
58
+ }
59
+
60
+ label(val: string): this {
61
+ this._label = val;
62
+ return this;
63
+ }
64
+
65
+ placeholder(val: string): this {
66
+ this._placeholder = val;
67
+ return this;
68
+ }
69
+
70
+ disabled(val: boolean = true): this {
71
+ this._disabled = val;
72
+ return this;
73
+ }
74
+
75
+ rows(val: number): this {
76
+ this._rows = val;
77
+ return this;
78
+ }
79
+
80
+ resize(val: 'none' | 'vertical' | 'horizontal' | 'both'): this {
81
+ this._resize = val;
82
+ return this;
83
+ }
84
+
85
+ error(val: string): this {
86
+ this._error = val;
87
+ return this;
88
+ }
89
+
90
+ onChange(handler: (value: string) => void): this {
91
+ this._onChange = handler;
92
+ return this;
93
+ }
94
+
95
+ build(): ReactElement {
96
+ const containerClass = ['fibo-textarea-container', ...this._classNames]
97
+ .filter(Boolean)
98
+ .join(' ');
99
+
100
+ const props = {
101
+ containerClass,
102
+ containerStyle: { width: '100%', ...this.getStyle() },
103
+ label: this._label,
104
+ error: this._error,
105
+ rows: this._rows,
106
+ value: this._value,
107
+ placeholder: this._placeholder || ' ',
108
+ disabled: this._disabled,
109
+ style: { resize: this._resize },
110
+ onChange: (e: ChangeEvent<HTMLTextAreaElement>) => {
111
+ this._onChange?.(e.target.value);
112
+ },
113
+ ...this._props
114
+ };
115
+
116
+ return React.createElement(TextareaInner, props);
117
+ }
118
+ }
119
+
120
+
121
+ export const Textarea = createBuilder(TextareaBuilder);
122
+
123
+ export interface TextareaProps extends BaseProps {
124
+ value: string;
125
+ label?: string;
126
+ placeholder?: string;
127
+ onChange?: (value: string) => void;
128
+ rows?: number;
129
+ }
@@ -0,0 +1,8 @@
1
+ export * from './Button';
2
+ export * from './TextField';
3
+ export * from './Switch';
4
+ export * from './Checkbox';
5
+ export * from './RadioGroup';
6
+ export * from './Textarea';
7
+ export * from './Select';
8
+ export * from './Combobox';