powell-react 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. package/api/PowellProvider.tsx +37 -0
  2. package/api/api.ts +126 -0
  3. package/api/configService.ts +4 -0
  4. package/api/index.ts +4 -0
  5. package/api/powellDefaults.ts +11 -0
  6. package/components/AutoComplete/AutoComplete.scss +126 -0
  7. package/components/AutoComplete/AutoComplete.tsx +184 -0
  8. package/components/AutoComplete/index.ts +1 -0
  9. package/components/Button/Button.tsx +85 -0
  10. package/components/Button/index.ts +1 -0
  11. package/components/Checkbox/Checkbox.scss +35 -0
  12. package/components/Checkbox/Checkbox.tsx +136 -0
  13. package/components/Checkbox/index.ts +1 -0
  14. package/components/Dropdown/Dropdown.scss +126 -0
  15. package/components/Dropdown/Dropdown.tsx +184 -0
  16. package/components/Dropdown/index.ts +1 -0
  17. package/components/ErrorMessage/ErrorMessage.scss +7 -0
  18. package/components/ErrorMessage/ErrorMessage.tsx +23 -0
  19. package/components/ErrorMessage/index.ts +1 -0
  20. package/components/FormContainer/FormContainer.tsx +49 -0
  21. package/components/FormContainer/FormContext.tsx +17 -0
  22. package/components/FormContainer/index.ts +2 -0
  23. package/components/InputText/InputText.scss +126 -0
  24. package/components/InputText/InputText.tsx +184 -0
  25. package/components/InputText/index.ts +1 -0
  26. package/components/InputTextarea/InputTextarea.scss +126 -0
  27. package/components/InputTextarea/InputTextarea.tsx +181 -0
  28. package/components/InputTextarea/index.ts +1 -0
  29. package/hooks/index.ts +4 -0
  30. package/hooks/useApplyConfig.ts +36 -0
  31. package/hooks/useFormContext.ts +14 -0
  32. package/hooks/usePowellConfig.ts +64 -0
  33. package/hooks/useTransform.ts +27 -0
  34. package/index.js +1 -0
  35. package/models/common.ts +7 -0
  36. package/models/config.ts +86 -0
  37. package/models/forms.ts +23 -0
  38. package/models/index.ts +3 -0
  39. package/package.json +16 -0
  40. package/themes/arya-blue.css +1 -0
  41. package/themes/arya-green.css +1 -0
  42. package/themes/arya-orange.css +1 -0
  43. package/themes/arya-purple.css +1 -0
  44. package/themes/bootstrap4-dark-blue.css +1 -0
  45. package/themes/bootstrap4-dark-purple.css +1 -0
  46. package/themes/bootstrap4-light-blue.css +1 -0
  47. package/themes/bootstrap4-light-purple.css +1 -0
  48. package/themes/fluent-light.css +1 -0
  49. package/themes/lara-dark-amber.css +1 -0
  50. package/themes/lara-dark-blue.css +1 -0
  51. package/themes/lara-dark-cyan.css +1 -0
  52. package/themes/lara-dark-green.css +1 -0
  53. package/themes/lara-dark-indigo.css +1 -0
  54. package/themes/lara-dark-pink.css +1 -0
  55. package/themes/lara-dark-purple.css +1 -0
  56. package/themes/lara-dark-teal.css +1 -0
  57. package/themes/lara-light-amber.css +1 -0
  58. package/themes/lara-light-blue.css +1 -0
  59. package/themes/lara-light-cyan.css +1 -0
  60. package/themes/lara-light-green.css +1 -0
  61. package/themes/lara-light-indigo.css +1 -0
  62. package/themes/lara-light-pink.css +1 -0
  63. package/themes/lara-light-purple.css +1 -0
  64. package/themes/lara-light-teal.css +1 -0
  65. package/themes/luna-amber.css +1 -0
  66. package/themes/luna-blue.css +1 -0
  67. package/themes/luna-green.css +1 -0
  68. package/themes/luna-pink.css +1 -0
  69. package/themes/md-dark-deeppurple.css +1 -0
  70. package/themes/md-dark-indigo.css +1 -0
  71. package/themes/md-light-deeppurple.css +1 -0
  72. package/themes/md-light-indigo.css +1 -0
  73. package/themes/mdc-dark-deeppurple.css +1 -0
  74. package/themes/mdc-dark-indigo.css +1 -0
  75. package/themes/mdc-light-deeppurple.css +1 -0
  76. package/themes/mdc-light-indigo.css +1 -0
  77. package/themes/mira.css +1 -0
  78. package/themes/nano.css +1 -0
  79. package/themes/nova-accent.css +1 -0
  80. package/themes/nova-alt.css +1 -0
  81. package/themes/nova.css +1 -0
  82. package/themes/rhea.css +1 -0
  83. package/themes/saga-blue.css +1 -0
  84. package/themes/saga-green.css +1 -0
  85. package/themes/saga-orange.css +1 -0
  86. package/themes/saga-purple.css +1 -0
  87. package/themes/soho-dark.css +1 -0
  88. package/themes/soho-light.css +1 -0
  89. package/themes/tailwind-light.css +1 -0
  90. package/themes/vela-blue.css +1 -0
  91. package/themes/vela-green.css +1 -0
  92. package/themes/vela-orange.css +1 -0
  93. package/themes/vela-purple.css +1 -0
  94. package/themes/viva-dark.css +1 -0
  95. package/themes/viva-light.css +1 -0
  96. package/utils/globalState.ts +96 -0
  97. package/utils/index.ts +2 -0
  98. package/utils/utilsService.tsx +39 -0
@@ -0,0 +1,37 @@
1
+ import {PropsWithChildren} from "react";
2
+ import {configService, powellDefaults, PrimeProvider} from "@powell/api";
3
+ import {PowellConfig, ThemeName} from "@powell/models";
4
+
5
+ const createThemeLink = () => {
6
+ const headEl = document.head;
7
+ const linkEl = document.createElement("link");
8
+ linkEl.rel = "stylesheet";
9
+ linkEl.type = "text/css";
10
+ linkEl.id = "powell-theme-link";
11
+ headEl.appendChild(linkEl);
12
+ return linkEl;
13
+ }
14
+
15
+ const applyTheme = (theme: ThemeName) => {
16
+ let themeEl: HTMLLinkElement = document.getElementById('powell-theme-link') as HTMLLinkElement;
17
+ if (!themeEl) {
18
+ themeEl = createThemeLink();
19
+ }
20
+ const themeLink = `/src/powell/themes/${theme}.css`;
21
+ themeEl.setAttribute('href', themeLink);
22
+ }
23
+
24
+ export const PowellProvider = (props: PropsWithChildren<{ config?: PowellConfig }>) => {
25
+ const {children, config} = props;
26
+ const defaultConfig: PowellConfig = {
27
+ ...powellDefaults,
28
+ ...config
29
+ };
30
+ configService.set(defaultConfig);
31
+ applyTheme(defaultConfig.theme!);
32
+ return (
33
+ <PrimeProvider value={defaultConfig}>
34
+ {children}
35
+ </PrimeProvider>
36
+ )
37
+ }
package/api/api.ts ADDED
@@ -0,0 +1,126 @@
1
+ import {
2
+ AutoComplete,
3
+ AutoCompleteChangeEvent,
4
+ AutoCompleteCompleteEvent,
5
+ AutoCompleteDropdownClickEvent,
6
+ AutoCompleteProps,
7
+ AutoCompleteSelectEvent,
8
+ AutoCompleteUnselectEvent,
9
+ } from "primereact/autocomplete";
10
+ import {
11
+ Calendar,
12
+ CalendarDateTemplateEvent,
13
+ CalendarMonthChangeEvent,
14
+ CalendarMonthNavigatorTemplateEvent,
15
+ CalendarNavigatorTemplateEvent,
16
+ CalendarProps,
17
+ CalendarSelectEvent,
18
+ CalendarViewChangeEvent,
19
+ CalendarVisibleChangeEvent,
20
+ CalendarYearNavigatorTemplateEvent,
21
+ } from "primereact/calendar";
22
+ import {
23
+ Checkbox,
24
+ CheckboxChangeEvent,
25
+ CheckboxContext,
26
+ CheckboxPassThroughMethodOptions,
27
+ CheckboxPassThroughOptions,
28
+ CheckboxPassThroughType,
29
+ CheckboxProps,
30
+ CheckboxState
31
+ } from "primereact/checkbox";
32
+ import {Dropdown, DropdownChangeEvent, DropdownFilterEvent, DropdownProps} from "primereact/dropdown";
33
+ import {FloatLabel} from "primereact/floatlabel";
34
+ import {InputIcon} from 'primereact/inputicon';
35
+ import {IconField, IconFieldProps} from "primereact/iconfield";
36
+ import {InputText, InputTextProps} from "primereact/inputtext";
37
+ import {InputTextarea, InputTextareaProps} from "primereact/inputtextarea";
38
+ import {Button, ButtonProps} from "primereact/button";
39
+ import {Sidebar} from "primereact/sidebar";
40
+ import {PanelMenu} from 'primereact/panelmenu';
41
+ import {MenuItem} from "primereact/menuitem";
42
+ import {
43
+ addLocale,
44
+ APIOptions,
45
+ locale,
46
+ localeOption,
47
+ localeOptions,
48
+ PrimeReactContext,
49
+ PrimeReactProvider,
50
+ updateLocaleOption,
51
+ updateLocaleOptions,
52
+ ZIndexOptions
53
+ } from "primereact/api";
54
+ import {classNames, UniqueComponentId} from "primereact/utils";
55
+
56
+ export const PrimeAutoComplete = AutoComplete;
57
+ export type PrimeAutoCompleteProps = AutoCompleteProps;
58
+ export type PrimeAutoCompleteSelectEvent = AutoCompleteSelectEvent;
59
+ export type PrimeAutoCompleteUnselectEvent = AutoCompleteUnselectEvent;
60
+ export type PrimeAutoCompleteCompleteEvent = AutoCompleteCompleteEvent;
61
+ export type PrimeAutoCompleteChangeEvent = AutoCompleteChangeEvent;
62
+ export type PrimeAutoCompleteDropdownClickEvent = AutoCompleteDropdownClickEvent;
63
+
64
+ export const PrimeCalendar = Calendar;
65
+ export type PrimeCalendarProps = CalendarProps;
66
+ export type PrimeCalendarSelectEvent = CalendarSelectEvent;
67
+ export type PrimeCalendarNavigatorTemplateEvent = CalendarNavigatorTemplateEvent;
68
+ export type PrimeCalendarDateTemplateEvent = CalendarDateTemplateEvent;
69
+ export type PrimeCalendarMonthChangeEvent = CalendarMonthChangeEvent;
70
+ export type PrimeCalendarVisibleChangeEvent = CalendarVisibleChangeEvent;
71
+ export type PrimeCalendarViewChangeEvent = CalendarViewChangeEvent;
72
+ export type PrimeCalendarMonthNavigatorTemplateEvent = CalendarMonthNavigatorTemplateEvent;
73
+ export type PrimeCalendarYearNavigatorTemplateEvent = CalendarYearNavigatorTemplateEvent;
74
+
75
+ export const PrimeCheckbox = Checkbox;
76
+ export type PrimeCheckboxChangeEvent = CheckboxChangeEvent;
77
+ export type PrimeCheckboxPassThroughMethodOptions = CheckboxPassThroughMethodOptions;
78
+ export type PrimeCheckboxPassThroughType<T> = CheckboxPassThroughType<T>;
79
+ export type PrimeCheckboxPassThroughOptions = CheckboxPassThroughOptions;
80
+ export type PrimeCheckboxProps = CheckboxProps;
81
+ export type PrimeCheckboxState = CheckboxState;
82
+ export type PrimeCheckboxContext = CheckboxContext;
83
+
84
+ export const PrimeButton = Button;
85
+ export type PrimeButtonProps = ButtonProps;
86
+
87
+ export const PrimeInputText = InputText;
88
+ export type PrimeInputTextProps = InputTextProps;
89
+
90
+ export const PrimeInputTextarea = InputTextarea;
91
+ export type PrimeInputTextareaProps = InputTextareaProps;
92
+
93
+ export const PrimeIconField = IconField;
94
+ export type PrimeIconFieldProps = IconFieldProps;
95
+
96
+ export const PrimeFloatLabel = FloatLabel;
97
+
98
+ export const PrimeInputIcon = InputIcon;
99
+
100
+ export type PrimeAPIOptions = APIOptions;
101
+
102
+ export const PrimeDropdown = Dropdown;
103
+ export type PrimeDropdownProps = DropdownProps;
104
+ export type PrimeDropdownChangeEvent = DropdownChangeEvent;
105
+ export type PrimeDropdownFilterEvent = DropdownFilterEvent;
106
+
107
+ export const PrimeProvider = PrimeReactProvider;
108
+
109
+ export const PrimeContext = PrimeReactContext;
110
+
111
+ export const PrimePanelMenu = PanelMenu;
112
+
113
+ export const PrimeSidebar = Sidebar;
114
+
115
+ export type PrimeMenuItem = MenuItem;
116
+
117
+ export type PrimeZIndexOptions = ZIndexOptions;
118
+
119
+ export const primeLocale = locale;
120
+ export const primeAddLocale = addLocale;
121
+ export const primeUpdateLocaleOption = updateLocaleOption;
122
+ export const primeUpdateLocaleOptions = updateLocaleOptions;
123
+ export const primeLocaleOption = localeOption;
124
+ export const primeLocaleOptions = localeOptions;
125
+ export const PrimeUniqueComponentId = UniqueComponentId;
126
+ export const primeClassNames = classNames;
@@ -0,0 +1,4 @@
1
+ import {globalState} from "@powell/utils";
2
+ import {PowellConfig} from "@powell/models";
3
+
4
+ export const configService = globalState<PowellConfig>({});
package/api/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './api';
2
+ export * from './configService';
3
+ export * from './powellDefaults';
4
+ export * from './PowellProvider';
@@ -0,0 +1,11 @@
1
+ import {PowellConfig} from "@powell/models";
2
+
3
+ export const powellDefaults: PowellConfig = {
4
+ theme: 'lara-light-cyan',
5
+ rtl: false,
6
+ showRequiredStar: true,
7
+ ripple: true,
8
+ inputSize: 'md',
9
+ labelPosition: 'fix-top',
10
+ fixLabelPosition: 'fix-side'
11
+ }
@@ -0,0 +1,126 @@
1
+ .auto-complete-wrapper {
2
+ .field {
3
+ display: flex;
4
+ gap: 0.25rem 1rem;
5
+
6
+ > div {
7
+ flex-grow: 1;
8
+ }
9
+ }
10
+
11
+ :where(.p-inputtext, .p-autocomplete) {
12
+ width: 100%;
13
+ }
14
+
15
+ .p-icon-field {
16
+ .p-input-icon {
17
+ z-index: 5;
18
+ color: var(--text-color-secondary);
19
+ }
20
+
21
+ &.p-icon-field-right {
22
+ :where(.p-inputtext) {
23
+ padding-right: 2.5rem;
24
+ }
25
+
26
+ .p-input-icon {
27
+ right: 0.75rem;
28
+ left: auto;
29
+ }
30
+ }
31
+
32
+ &.p-icon-field-left {
33
+ :where(.p-inputtext) {
34
+ padding-left: 2.5rem;
35
+ }
36
+
37
+ .p-input-icon {
38
+ left: 0.75rem;
39
+ right: auto;
40
+ }
41
+ }
42
+ }
43
+
44
+ &.label-fix-side .field {
45
+ flex-direction: row;
46
+ align-items: center;
47
+ }
48
+
49
+ &.label-fix-top .field {
50
+ flex-direction: column;
51
+
52
+ label {
53
+ margin-bottom: 0.25rem;
54
+ }
55
+ }
56
+
57
+ &.addon-before {
58
+ [class*="icon-"] {
59
+ :where(.p-inputtext, .p-autocomplete) {
60
+ border-radius: 0 var(--border-radius) var(--border-radius) 0;
61
+ }
62
+ }
63
+ }
64
+
65
+ &.addon-after {
66
+ &.label-float {
67
+ .p-inputgroup-addon {
68
+ border-left: 0;
69
+ }
70
+ }
71
+
72
+ [class*="icon-"] {
73
+ :where(.p-inputtext, .p-autocomplete) {
74
+ border-radius: var(--border-radius) 0 0 var(--border-radius);
75
+ }
76
+ }
77
+ }
78
+
79
+ &[class*="addon-"] {
80
+ .p-inputgroup {
81
+ .p-icon-field,
82
+ .p-float-label {
83
+ flex-grow: 1;
84
+ }
85
+ }
86
+
87
+ &.addon-before :where(.p-inputtext, .p-autocomplete) {
88
+ border-radius: 0 var(--border-radius) var(--border-radius) 0;
89
+ }
90
+
91
+ &.addon-after :where(.p-inputtext, .p-autocomplete) {
92
+ border-radius: var(--border-radius) 0 0 var(--border-radius);
93
+ }
94
+ }
95
+
96
+ &.is-ltr {
97
+ direction: ltr;
98
+
99
+ &.label-float {
100
+ &.icon-left .field label {
101
+ left: 2.5rem;
102
+ }
103
+ }
104
+ }
105
+
106
+ &.is-rtl {
107
+ direction: rtl;
108
+
109
+ &.label-float {
110
+ label {
111
+ left: auto;
112
+ right: 0.75rem;
113
+ }
114
+
115
+ &.icon-right .field label {
116
+ right: 2.5rem;
117
+ }
118
+ }
119
+
120
+ &[class*="addon-"] {
121
+ .p-inputgroup {
122
+ flex-direction: row-reverse;
123
+ }
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,184 @@
1
+ import {ChangeEvent, ReactNode, useCallback, useRef, useState} from "react";
2
+ import {Addon, LabelPosition, Size} from "@powell/models";
3
+ import {
4
+ primeClassNames,
5
+ PrimeFloatLabel,
6
+ PrimeIconField,
7
+ PrimeIconFieldProps,
8
+ PrimeInputIcon,
9
+ PrimeAutoComplete,
10
+ PrimeAutoCompleteProps,
11
+ PrimeUniqueComponentId
12
+ } from "@powell/api";
13
+ import {getAddonTemplate, transformer} from "@powell/utils";
14
+ import {Field, FieldProps} from "formik";
15
+ import {useApplyConfig, useFormContext} from "@powell/hooks";
16
+ import {SafeAny} from "@powell/models/common";
17
+ import {ErrorMessage} from "@powell/components/ErrorMessage";
18
+ import './AutoComplete.scss';
19
+
20
+ interface AutoCompleteProps extends PrimeAutoCompleteProps {
21
+ name?: string;
22
+ parseError?: (error: string) => ReactNode;
23
+ transform?: {
24
+ input?: (value: SafeAny) => string;
25
+ output?: (event: ChangeEvent<HTMLInputElement>) => SafeAny;
26
+ };
27
+ showRequiredStar?: boolean;
28
+ rtl?: boolean;
29
+ label?: string;
30
+ icon?: string | ReactNode;
31
+ hint?: string;
32
+ addon?: Addon;
33
+ inputSize?: Size;
34
+ iconPosition?: PrimeIconFieldProps["iconPosition"];
35
+ labelPosition?: LabelPosition;
36
+ }
37
+
38
+ export const AutoComplete = (props: AutoCompleteProps) => {
39
+ props = useApplyConfig(props);
40
+ const {
41
+ parseError,
42
+ name,
43
+ transform = {},
44
+ iconPosition = 'left',
45
+ labelPosition,
46
+ addon,
47
+ icon,
48
+ rtl,
49
+ showRequiredStar,
50
+ variant,
51
+ inputSize,
52
+ ...rest
53
+ } = props;
54
+
55
+ const inputId = useRef(PrimeUniqueComponentId());
56
+
57
+ // Check if we're in Formik context
58
+ const formContext = useFormContext();
59
+ const withinForm = !!formContext && !!name;
60
+ const isRequired = withinForm && formContext.validationSchema?.fields?.[name].tests?.some((t: SafeAny) => t.OPTIONS.name === 'required');
61
+
62
+ // Internal state for non-Formik usage
63
+ const [internalValue, setInternalValue] = useState(rest.value || '');
64
+
65
+ const inputEl = useCallback(() => {
66
+ const commonProps = {
67
+ ...rest,
68
+ variant,
69
+ id: inputId.current,
70
+ name,
71
+ };
72
+
73
+ if (withinForm) {
74
+ // if in Formik context
75
+ return (
76
+ <Field name={name}>
77
+ {({field, meta}: FieldProps) => {
78
+ const {value, onChange} = transformer({
79
+ value: field.value,
80
+ onChange: (event: string) => formContext.setFieldValue(name, event),
81
+ transform: {
82
+ input: transform.input ?? (value => value),
83
+ output: transform.output ?? (event => event.target.value)
84
+ }
85
+ });
86
+
87
+ return (
88
+ <>
89
+ <PrimeAutoComplete
90
+ {...commonProps}
91
+ value={value}
92
+ onChange={(event) => {
93
+ onChange(event);
94
+ rest.onChange?.(event);
95
+ }}
96
+ onBlur={(event) => {
97
+ field.onBlur(event);
98
+ rest.onBlur?.(event);
99
+ }}
100
+ invalid={!!meta.error}
101
+ />
102
+ <ErrorMessage message={meta.error} parseError={parseError} hint={rest.hint}/>
103
+ </>
104
+ );
105
+ }}
106
+ </Field>
107
+ );
108
+ } else {
109
+ // if outside Formik context
110
+ const {value, onChange} = transformer({
111
+ value: internalValue,
112
+ onChange: (event: string) => setInternalValue(event),
113
+ transform: {
114
+ input: transform.input ?? (value => value),
115
+ output: transform.output ?? (event => event.target.value)
116
+ }
117
+ });
118
+
119
+ return (
120
+ <PrimeAutoComplete
121
+ {...commonProps}
122
+ value={value}
123
+ onChange={(event) => {
124
+ onChange(event);
125
+ rest.onChange?.(event);
126
+ }}
127
+ onBlur={rest.onBlur}
128
+ />
129
+ );
130
+ }
131
+ }, [internalValue]);
132
+
133
+ const labelEl = rest.label && (
134
+ <label htmlFor={inputId.current}>
135
+ {rest.label}
136
+ {isRequired && showRequiredStar ? '*' : ''}
137
+ </label>
138
+ );
139
+
140
+ const iconEl = icon && (
141
+ typeof icon === 'string'
142
+ ? <PrimeInputIcon className={icon}></PrimeInputIcon>
143
+ : <PrimeInputIcon>{icon}</PrimeInputIcon>
144
+ );
145
+
146
+ const withIcon = (
147
+ <PrimeIconField iconPosition={iconPosition}>
148
+ {iconEl}
149
+ {inputEl()}
150
+ </PrimeIconField>
151
+ );
152
+
153
+ return (
154
+ <div className={primeClassNames('auto-complete-wrapper',
155
+ `variant-${variant}`,
156
+ `p-inputtext-${inputSize}`,
157
+ {
158
+ [`label-${labelPosition}`]: rest.label,
159
+ [`icon-${iconPosition}`]: iconEl,
160
+ 'is-rtl': rtl,
161
+ 'is-ltr': !rtl,
162
+ 'addon-before': addon?.before,
163
+ 'addon-after': addon?.after,
164
+ })}>
165
+ <div className="field">
166
+ {labelPosition !== 'float' && labelEl}
167
+ <div className={primeClassNames({"p-inputgroup": addon})}>
168
+ {getAddonTemplate(addon?.before)}
169
+ {
170
+ labelPosition === 'float' ? (
171
+ <PrimeFloatLabel>
172
+ {icon ? withIcon : inputEl()}
173
+ {labelEl}
174
+ </PrimeFloatLabel>
175
+ ) : (
176
+ icon ? withIcon : inputEl()
177
+ )
178
+ }
179
+ {getAddonTemplate(addon?.after)}
180
+ </div>
181
+ </div>
182
+ </div>
183
+ );
184
+ };
@@ -0,0 +1 @@
1
+ export * from "./AutoComplete";
@@ -0,0 +1,85 @@
1
+ import {memo, MouseEvent, useRef, useState} from "react";
2
+ import {PrimeButton, PrimeButtonProps, primeClassNames} from "@powell/api";
3
+ import {ButtonAppearance} from "@powell/models";
4
+
5
+ type ButtonState = 'default' | 'loading' | 'next';
6
+
7
+ interface ButtonProps extends Omit<PrimeButtonProps, "loading" | "link" | "text" | "outlined"> {
8
+ async?: true;
9
+ onClickAsync?: (event: { loadingCallback: (ok?: boolean) => void, event: MouseEvent<HTMLButtonElement> }) => void;
10
+ appearance?: ButtonAppearance;
11
+ nextLabel?: string;
12
+ nextIcon?: string;
13
+ nextRaised?: boolean;
14
+ nextAppearance?: ButtonAppearance;
15
+ nextSeverity?: ButtonProps['severity'];
16
+ state?: ButtonState;
17
+ onStateChange?: (state: ButtonState) => void;
18
+ }
19
+
20
+ type ButtonTempProps = Pick<ButtonProps, "label" | "icon" | "raised" | "appearance" | "severity">;
21
+
22
+ export const Button = memo((props: ButtonProps) => {
23
+ const {
24
+ async,
25
+ onClickAsync,
26
+ onClick,
27
+ nextLabel,
28
+ nextIcon,
29
+ nextRaised,
30
+ nextSeverity,
31
+ nextAppearance,
32
+ state = 'default',
33
+ onStateChange,
34
+ type = 'button',
35
+ ...rest
36
+ } = props;
37
+
38
+ const [_state, _setState] = useState<ButtonState>(state);
39
+
40
+ const getButtonTempProps = (newState: ButtonState) => {
41
+ return {
42
+ label: newState === 'default' ? props.label : (nextLabel ?? props.label),
43
+ icon: newState === 'default' ? props.icon : (nextIcon ?? props.icon),
44
+ appearance: newState === 'default' ? props.appearance : (nextAppearance ?? props.appearance),
45
+ raised: newState === 'default' ? props.raised : (nextRaised ?? props.raised),
46
+ severity: newState === 'default' ? props.severity : (nextSeverity ?? props.severity),
47
+ }
48
+ }
49
+
50
+ const tempProps = useRef<ButtonTempProps>(getButtonTempProps(state));
51
+
52
+ const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
53
+ if (async) {
54
+ onClickAsync?.({event, loadingCallback: removeLoading});
55
+ _setState('loading');
56
+ onStateChange?.('loading');
57
+ } else {
58
+ onClick?.(event);
59
+ }
60
+ }
61
+
62
+ const removeLoading = (toggleState?: boolean) => {
63
+ const newState = toggleState ? 'next' : 'default';
64
+ tempProps.current = getButtonTempProps(newState);
65
+ _setState(newState);
66
+ onStateChange?.(newState);
67
+ }
68
+
69
+ return (
70
+ <PrimeButton
71
+ type={type}
72
+ {...rest}
73
+ onClick={handleClick}
74
+ label={async ? tempProps.current.label : props.label}
75
+ icon={async ? tempProps.current.icon : props.icon}
76
+ severity={async ? tempProps.current.severity : props.severity}
77
+ raised={async ? tempProps.current.raised : props.raised}
78
+ text={async ? tempProps.current.appearance === 'text' : props.appearance === 'text'}
79
+ outlined={async ? tempProps.current.appearance === 'outlined' : props.appearance === 'outlined'}
80
+ link={async ? tempProps.current.appearance === 'link' : props.appearance === 'link'}
81
+ loading={_state === 'loading'}
82
+ className={primeClassNames(props.className, `state-${_state}`)}
83
+ />
84
+ )
85
+ })
@@ -0,0 +1 @@
1
+ export * from "./Button";
@@ -0,0 +1,35 @@
1
+ .checkbox-wrapper {
2
+ .field {
3
+ display: flex;
4
+ gap: 0.25rem 1rem;
5
+
6
+ > .field-inner {
7
+ flex-grow: 1;
8
+ }
9
+ }
10
+
11
+ :where(.p-checkbox) {
12
+ width: 100%;
13
+ }
14
+
15
+ &.label-fix-side .field {
16
+ flex-direction: row;
17
+ align-items: center;
18
+ }
19
+
20
+ &.label-fix-top .field {
21
+ flex-direction: column;
22
+
23
+ label {
24
+ margin-bottom: 0.25rem;
25
+ }
26
+ }
27
+
28
+ &.is-ltr {
29
+ direction: ltr;
30
+ }
31
+
32
+ &.is-rtl {
33
+ direction: rtl;
34
+ }
35
+ }