@udixio/ui-react 2.9.13 → 2.9.14

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 (74) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/index.cjs +3 -3
  3. package/dist/index.js +2259 -1814
  4. package/dist/lib/components/Button.d.ts.map +1 -1
  5. package/dist/lib/components/Card.d.ts +2 -2
  6. package/dist/lib/components/Card.d.ts.map +1 -1
  7. package/dist/lib/components/Checkbox.d.ts +15 -0
  8. package/dist/lib/components/Checkbox.d.ts.map +1 -0
  9. package/dist/lib/components/DatePicker.d.ts +9 -0
  10. package/dist/lib/components/DatePicker.d.ts.map +1 -0
  11. package/dist/lib/components/FabMenu.d.ts.map +1 -1
  12. package/dist/lib/components/IconButton.d.ts.map +1 -1
  13. package/dist/lib/components/TabGroup.d.ts +1 -0
  14. package/dist/lib/components/TabGroup.d.ts.map +1 -1
  15. package/dist/lib/components/TabGroupContext.d.ts +1 -0
  16. package/dist/lib/components/TabGroupContext.d.ts.map +1 -1
  17. package/dist/lib/components/TabPanel.d.ts +1 -0
  18. package/dist/lib/components/TabPanel.d.ts.map +1 -1
  19. package/dist/lib/components/TabPanels.d.ts +1 -0
  20. package/dist/lib/components/TabPanels.d.ts.map +1 -1
  21. package/dist/lib/components/TextField.d.ts +4 -4
  22. package/dist/lib/components/TextField.d.ts.map +1 -1
  23. package/dist/lib/components/index.d.ts +2 -0
  24. package/dist/lib/components/index.d.ts.map +1 -1
  25. package/dist/lib/effects/State.d.ts +3 -1
  26. package/dist/lib/effects/State.d.ts.map +1 -1
  27. package/dist/lib/interfaces/card.interface.d.ts +1 -1
  28. package/dist/lib/interfaces/card.interface.d.ts.map +1 -1
  29. package/dist/lib/interfaces/checkbox.interface.d.ts +38 -0
  30. package/dist/lib/interfaces/checkbox.interface.d.ts.map +1 -0
  31. package/dist/lib/interfaces/date-picker.interface.d.ts +67 -0
  32. package/dist/lib/interfaces/date-picker.interface.d.ts.map +1 -0
  33. package/dist/lib/interfaces/icon-button.interface.d.ts +2 -1
  34. package/dist/lib/interfaces/icon-button.interface.d.ts.map +1 -1
  35. package/dist/lib/interfaces/index.d.ts +1 -0
  36. package/dist/lib/interfaces/index.d.ts.map +1 -1
  37. package/dist/lib/interfaces/text-field.interface.d.ts +7 -4
  38. package/dist/lib/interfaces/text-field.interface.d.ts.map +1 -1
  39. package/dist/lib/styles/card.style.d.ts +3 -3
  40. package/dist/lib/styles/checkbox.style.d.ts +45 -0
  41. package/dist/lib/styles/checkbox.style.d.ts.map +1 -0
  42. package/dist/lib/styles/date-picker.style.d.ts +45 -0
  43. package/dist/lib/styles/date-picker.style.d.ts.map +1 -0
  44. package/dist/lib/styles/icon-button.style.d.ts +10 -4
  45. package/dist/lib/styles/icon-button.style.d.ts.map +1 -1
  46. package/dist/lib/styles/index.d.ts +1 -0
  47. package/dist/lib/styles/index.d.ts.map +1 -1
  48. package/dist/lib/styles/text-field.style.d.ts +18 -9
  49. package/dist/lib/styles/text-field.style.d.ts.map +1 -1
  50. package/package.json +3 -3
  51. package/src/lib/components/Button.tsx +1 -0
  52. package/src/lib/components/Card.tsx +9 -4
  53. package/src/lib/components/Checkbox.tsx +120 -0
  54. package/src/lib/components/DatePicker.tsx +432 -0
  55. package/src/lib/components/FabMenu.tsx +4 -5
  56. package/src/lib/components/IconButton.tsx +9 -7
  57. package/src/lib/components/TabGroup.tsx +8 -6
  58. package/src/lib/components/TabGroupContext.tsx +1 -1
  59. package/src/lib/components/TabPanel.tsx +1 -0
  60. package/src/lib/components/TabPanels.tsx +1 -0
  61. package/src/lib/components/TextField.tsx +95 -108
  62. package/src/lib/components/index.ts +2 -0
  63. package/src/lib/effects/State.tsx +4 -1
  64. package/src/lib/interfaces/card.interface.ts +1 -1
  65. package/src/lib/interfaces/checkbox.interface.ts +39 -0
  66. package/src/lib/interfaces/date-picker.interface.ts +79 -0
  67. package/src/lib/interfaces/icon-button.interface.ts +2 -1
  68. package/src/lib/interfaces/index.ts +1 -0
  69. package/src/lib/interfaces/text-field.interface.ts +7 -4
  70. package/src/lib/styles/checkbox.style.ts +64 -0
  71. package/src/lib/styles/date-picker.style.ts +43 -0
  72. package/src/lib/styles/index.ts +1 -0
  73. package/src/lib/styles/text-field.style.ts +2 -2
  74. package/src/stories/containment/card.stories.tsx +1 -1
@@ -1,8 +1,7 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { useEffect, useId, useState } from 'react';
2
2
  import { Icon } from '../icon';
3
3
  import { faCircleExclamation } from '@fortawesome/free-solid-svg-icons';
4
4
  import { motion } from 'motion/react';
5
- import { v4 as uuidv4 } from 'uuid';
6
5
 
7
6
  import TextareaAutosize from 'react-textarea-autosize';
8
7
  import { useTextFieldStyle } from '../styles/text-field.style';
@@ -15,10 +14,10 @@ import { TextFieldInterface } from '../interfaces/text-field.interface';
15
14
  * @status beta
16
15
  * @category Input
17
16
  * @devx
18
- * - `onChange` receives the string value (not the DOM event).
19
- * - `value` syncs internal state; not a fully controlled input.
17
+ * - Supports controlled (`value`) and uncontrolled (`defaultValue`) usage.
18
+ * - `multiline` switches to textarea mode.
20
19
  * @a11y
21
- * - Uses `label` for `aria-label`; no `aria-describedby` for supporting text.
20
+ * - `aria-describedby` links supporting text/error to input.
22
21
  */
23
22
  export const TextField = ({
24
23
  variant = 'filled',
@@ -33,51 +32,35 @@ export const TextField = ({
33
32
  trailingIcon,
34
33
  leadingIcon,
35
34
  type = 'text',
36
- textLine = 'singleLine',
35
+ multiline = false,
37
36
  autoComplete = 'on',
38
37
  onChange,
39
- value: defaultValue,
40
- showSupportingText: defaultShowSupportingText = false,
38
+ value: valueProp,
39
+ defaultValue,
40
+ showSupportingText,
41
+ id: idProp,
42
+ style,
41
43
  ...restProps
42
44
  }: ReactProps<TextFieldInterface>) => {
43
- const [value, setValue] = useState(defaultValue ?? '');
44
- const [isFocused, setIsFocused] = useState(false);
45
- const [showErrorIcon, setShowErrorIcon] = useState(false);
46
- const [showSupportingText, setShowSupportingText] = useState(
47
- defaultShowSupportingText,
48
- );
45
+ const generatedId = useId();
46
+ const id = idProp || generatedId;
47
+ const helperTextId = `${id}-helper`;
49
48
 
50
- useEffect(() => {
51
- setValue(defaultValue ?? '');
52
- }, [defaultValue]);
49
+ const isControlled = valueProp !== undefined;
50
+ const [internalValue, setInternalValue] = useState(defaultValue ?? '');
51
+ const value = isControlled ? valueProp : internalValue;
53
52
 
54
- useEffect(() => {
55
- if (errorText?.length) {
56
- setShowErrorIcon(true);
57
- } else {
58
- setShowErrorIcon(false);
59
- }
60
- }, [errorText]);
53
+ const [isFocused, setIsFocused] = useState(false);
54
+ const [showErrorIcon, setShowErrorIcon] = useState(!!errorText?.length);
61
55
 
62
- useEffect(() => {
63
- if (defaultShowSupportingText) {
64
- setShowSupportingText(defaultShowSupportingText);
65
- } else {
66
- if (supportingText?.length) {
67
- setShowSupportingText(true);
68
- } else {
69
- setShowSupportingText(false);
70
- }
71
- }
72
- }, [showSupportingText, supportingText]);
56
+ const hasSupportingText =
57
+ showSupportingText ?? (!!errorText?.length || !!supportingText?.length);
73
58
 
74
59
  useEffect(() => {
75
- if (isFocused) {
76
- setShowErrorIcon(false);
77
- }
78
- }, [isFocused]);
60
+ setShowErrorIcon(!!errorText?.length);
61
+ }, [errorText]);
79
62
 
80
- const inputRef = React.useRef<HTMLInputElement & HTMLTextAreaElement>(null);
63
+ const inputRef = React.useRef<HTMLInputElement | HTMLTextAreaElement>(null);
81
64
 
82
65
  const focusInput = () => {
83
66
  if (inputRef.current && !isFocused) {
@@ -87,28 +70,34 @@ export const TextField = ({
87
70
 
88
71
  const handleOnFocus = () => {
89
72
  setIsFocused(true);
73
+ setShowErrorIcon(false);
90
74
  };
91
75
 
92
76
  const handleChange = (
93
- event: React.ChangeEvent<HTMLInputElement & HTMLTextAreaElement>,
77
+ event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
94
78
  ) => {
95
79
  const newValue = event.target.value;
96
- setValue(newValue); // Update local state
80
+
81
+ if (!isControlled) {
82
+ setInternalValue(newValue);
83
+ }
97
84
 
98
85
  setShowErrorIcon(false);
99
86
 
100
- // If external onChange prop is provided, call it with the new value
101
- if (typeof onChange === 'function') {
102
- onChange(newValue);
87
+ if (onChange) {
88
+ onChange(event);
103
89
  }
104
90
  };
105
91
 
106
92
  const handleBlur = () => {
107
93
  setIsFocused(false);
94
+ if (errorText?.length) {
95
+ setShowErrorIcon(true);
96
+ }
108
97
  };
109
98
 
110
99
  const styles = useTextFieldStyle({
111
- showSupportingText,
100
+ showSupportingText: hasSupportingText,
112
101
  isFocused,
113
102
  showErrorIcon,
114
103
  disabled,
@@ -124,34 +113,26 @@ export const TextField = ({
124
113
  trailingIcon,
125
114
  variant,
126
115
  errorText,
127
- value,
116
+ value: String(value),
128
117
  suffix,
129
- textLine,
118
+ multiline,
130
119
  });
131
120
 
132
- const [uuid] = useState(uuidv4());
121
+ const TextComponent = multiline ? TextareaAutosize : 'input';
122
+ const textComponentProps = multiline ? {} : { type };
133
123
 
134
- let textComponentProps: object;
135
- let TextComponent;
136
- switch (textLine) {
137
- case 'multiLine':
138
- TextComponent = TextareaAutosize;
139
- textComponentProps = {};
140
- break;
141
- case 'textAreas':
142
- TextComponent = 'textarea';
143
- textComponentProps = {};
144
- break;
145
- case 'singleLine':
146
- default:
147
- TextComponent = 'input';
148
- textComponentProps = { type: type };
149
- break;
150
- }
124
+ const isFloating =
125
+ isFocused || (typeof value === 'string' && value.length > 0);
126
+ const showLegend = isFloating && variant === 'outlined';
127
+ const showLabel = !showLegend;
151
128
 
152
129
  return (
153
- <div className={styles.textField} {...restProps}>
154
- <fieldset onClick={focusInput} className={styles.content}>
130
+ <div className={styles.textField} style={style}>
131
+ <fieldset
132
+ onClick={focusInput}
133
+ className={styles.content}
134
+ role="presentation"
135
+ >
155
136
  <div className={styles.stateLayer}></div>
156
137
  {leadingIcon && (
157
138
  <div className={styles.leadingIcon}>
@@ -163,59 +144,64 @@ export const TextField = ({
163
144
  </div>
164
145
  )}
165
146
 
166
- {!((!isFocused && !value.length) || variant == 'filled') && (
167
- <motion.legend
168
- variants={{
169
- hidden: { width: 0, padding: 0 },
170
- visible: { width: 'auto', padding: '0 8px' },
171
- }}
172
- initial={'hidden'}
173
- animate={!(!isFocused && !value.length) ? 'visible' : 'hidden'}
174
- className={'max-w-full ml-2 px-2 text-body-small h-0'}
175
- transition={{ duration: 0.2 }}
176
- >
177
- <span className={'transform inline-flex -translate-y-1/2'}>
178
- <motion.span
179
- className={styles.label}
180
- transition={{ duration: 0.3 }}
181
- layoutId={uuid}
182
- >
183
- {label}
184
- </motion.span>
185
- </span>
186
- </motion.legend>
187
- )}
147
+ <motion.legend
148
+ aria-hidden="true"
149
+ variants={{
150
+ hidden: { width: 0, padding: 0 },
151
+ visible: { width: 'auto', padding: '0 8px' },
152
+ }}
153
+ initial={showLegend ? 'visible' : 'hidden'}
154
+ animate={showLegend ? 'visible' : 'hidden'}
155
+ className={
156
+ 'max-w-full ml-2 px-2 text-body-small h-0 overflow-hidden whitespace-nowrap'
157
+ }
158
+ transition={{ duration: 0.2 }}
159
+ >
160
+ <span className={'transform inline-flex -translate-y-1/2 opacity-0'}>
161
+ {label}
162
+ </span>
163
+ </motion.legend>
164
+
188
165
  <div className={'flex-1 relative'}>
189
- {((!isFocused && !value.length) || variant == 'filled') && (
166
+ {showLabel && (
190
167
  <motion.label
191
- htmlFor={name}
168
+ htmlFor={id}
192
169
  className={classNames(
193
- 'absolute left-4 transition-all duration-300',
170
+ 'absolute left-4 transition-all duration-300 pointer-events-none',
194
171
  {
195
- 'text-body-small top-2':
196
- variant == 'filled' && !(!isFocused && !value.length),
172
+ 'text-body-small top-2': variant == 'filled' && isFloating,
197
173
  'text-body-large top-1/2 transform -translate-y-1/2': !(
198
- variant == 'filled' && !(!isFocused && !value.length)
174
+ variant == 'filled' && isFloating
199
175
  ),
200
176
  },
201
177
  )}
202
178
  transition={{ duration: 0.3 }}
179
+ layoutId={variant === 'outlined' ? `${id}-label` : undefined}
203
180
  >
204
- <motion.span
205
- className={styles.label}
206
- transition={{ duration: 0.3 }}
207
- layoutId={variant == 'outlined' ? uuid : undefined}
208
- >
209
- {label}
210
- </motion.span>
181
+ <span className={styles.label}>{label}</span>
182
+ </motion.label>
183
+ )}
184
+
185
+ {showLegend && (
186
+ <motion.label
187
+ htmlFor={id}
188
+ className={classNames(
189
+ 'absolute left-2 -top-3 px-1 text-body-small z-10',
190
+ styles.label,
191
+ )}
192
+ layoutId={`${id}-label`}
193
+ transition={{ duration: 0.3 }}
194
+ >
195
+ {label}
211
196
  </motion.label>
212
197
  )}
198
+
213
199
  <TextComponent
214
- ref={inputRef}
200
+ ref={inputRef as any}
215
201
  value={value}
216
202
  onChange={handleChange}
217
203
  className={styles.input}
218
- id={name}
204
+ id={id}
219
205
  name={name}
220
206
  placeholder={isFocused ? (placeholder ?? undefined) : ''}
221
207
  onFocus={handleOnFocus}
@@ -223,8 +209,9 @@ export const TextField = ({
223
209
  disabled={disabled}
224
210
  autoComplete={autoComplete}
225
211
  aria-invalid={!!errorText?.length}
226
- aria-label={label}
212
+ aria-describedby={hasSupportingText ? helperTextId : undefined}
227
213
  {...textComponentProps}
214
+ {...(restProps as any)}
228
215
  />
229
216
  </div>
230
217
 
@@ -265,8 +252,8 @@ export const TextField = ({
265
252
  </div>
266
253
  )}
267
254
  </fieldset>
268
- {showSupportingText && (
269
- <p className={styles.supportingText}>
255
+ {hasSupportingText && (
256
+ <p className={styles.supportingText} id={helperTextId}>
270
257
  {errorText?.length
271
258
  ? errorText
272
259
  : supportingText?.length
@@ -3,6 +3,7 @@ export * from './Card';
3
3
  export * from './Carousel';
4
4
  export * from './CarouselItem';
5
5
  export * from './CarouselItem';
6
+ export * from './Checkbox';
6
7
  export * from './Chip';
7
8
  export * from './Chips';
8
9
  export * from './Divider';
@@ -24,3 +25,4 @@ export * from './TextField';
24
25
  export * from './NavigationRailItem';
25
26
  export * from './NavigationRail';
26
27
  export * from './Tooltip';
28
+ export * from './DatePicker';
@@ -18,6 +18,7 @@ export interface StateInterface {
18
18
  | 'state-layer';
19
19
  className?: string;
20
20
  style?: React.CSSProperties;
21
+ children?: React.ReactNode;
21
22
  };
22
23
  states: { isClient: boolean };
23
24
  elements: ['stateLayer'];
@@ -27,6 +28,7 @@ export const State = ({
27
28
  style,
28
29
  colorName,
29
30
  stateClassName = 'state-ripple-group',
31
+ children,
30
32
  className,
31
33
  }: ReactProps<StateInterface>) => {
32
34
  const ref = useRef<HTMLDivElement>(null);
@@ -67,6 +69,7 @@ export const State = ({
67
69
  }}
68
70
  >
69
71
  {isClient && <RippleEffect triggerRef={groupStateRef} />}
72
+ {children}
70
73
  </div>
71
74
  );
72
75
  };
@@ -76,8 +79,8 @@ const cardConfig: ClassNameComponent<StateInterface> = ({
76
79
  stateClassName,
77
80
  }) => ({
78
81
  stateLayer: classNames([
79
- stateClassName,
80
82
  'w-full top-0 left-0 h-full absolute pointer-events-none overflow-hidden',
83
+ stateClassName,
81
84
  ]),
82
85
  });
83
86
 
@@ -4,7 +4,7 @@ export interface CardInterface {
4
4
  type: 'div';
5
5
  props: {
6
6
  variant?: 'outlined' | 'elevated' | 'filled';
7
- isInteractive?: boolean;
7
+ interactive?: boolean;
8
8
  children: ReactNode;
9
9
  };
10
10
  elements: ['card', 'stateLayer'];
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+
3
+ type Props = {
4
+ checked?: boolean;
5
+ defaultChecked?: boolean;
6
+ indeterminate?: boolean;
7
+ disabled?: boolean;
8
+ error?: boolean;
9
+ onChange?: React.ChangeEventHandler<HTMLInputElement>;
10
+ name?: string;
11
+ id?: string;
12
+ value?: string;
13
+ style?: React.CSSProperties;
14
+ className?: string;
15
+ };
16
+
17
+ export type CheckboxStates = {
18
+ isChecked: boolean;
19
+ isIndeterminate: boolean;
20
+ isDisabled: boolean;
21
+ isError: boolean;
22
+ isFocused: boolean;
23
+ isHovered: boolean;
24
+ };
25
+
26
+ export interface CheckboxInterface {
27
+ type: 'div';
28
+ props: Props;
29
+ states: CheckboxStates;
30
+ elements: [
31
+ 'checkbox',
32
+ 'input',
33
+ 'container',
34
+ 'box',
35
+ 'icon',
36
+ 'stateLayer',
37
+ 'ripple',
38
+ ];
39
+ }
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+
3
+ export type DateRange = [Date | null, Date | null];
4
+
5
+ type Props = {
6
+ /**
7
+ * Selection mode: 'single' for one date, 'range' for start/end period.
8
+ * @default 'single'
9
+ */
10
+ mode?: 'single' | 'range';
11
+
12
+ /**
13
+ * The currently selected date(s).
14
+ * Date for single mode, [start, end] tuple for range mode.
15
+ */
16
+ value?: Date | DateRange | null;
17
+
18
+ /**
19
+ * Default selected date(s) for uncontrolled usage.
20
+ */
21
+ defaultValue?: Date | DateRange | null;
22
+
23
+ /**
24
+ * Callback fired when selection changes.
25
+ * Returns Date in single mode, DateRange in range mode.
26
+ */
27
+ onChange?: (value: any) => void;
28
+
29
+ /**
30
+ * Minimum selectable date.
31
+ */
32
+ minDate?: Date;
33
+
34
+ /**
35
+ * Maximum selectable date.
36
+ */
37
+ maxDate?: Date;
38
+
39
+ /**
40
+ * Disables specific dates.
41
+ */
42
+ shouldDisableDate?: (date: Date) => boolean;
43
+
44
+ /**
45
+ * Locale for formatting dates.
46
+ */
47
+ locale?: string;
48
+
49
+ /**
50
+ * First day of the week (0=Sunday, 1=Monday).
51
+ * @default 0
52
+ */
53
+ weekStartDay?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
54
+
55
+ className?: string;
56
+ style?: React.CSSProperties;
57
+ };
58
+
59
+ export type DatePickerStates = {
60
+ // Can be expanded if we need specific state-driven styles exposed to the config
61
+ hasSelected: boolean;
62
+ };
63
+
64
+ export interface DatePickerInterface {
65
+ type: 'div';
66
+ props: Props;
67
+ states: DatePickerStates;
68
+ elements: [
69
+ 'datePicker',
70
+ 'header',
71
+ 'monthNav',
72
+ 'monthLabel',
73
+ 'weekDays',
74
+ 'weekDay',
75
+ 'daysGrid',
76
+ 'dayCell',
77
+ 'dayButton', // The interactive part of the day
78
+ ];
79
+ }
@@ -7,7 +7,7 @@ import { Icon } from '../icon';
7
7
  type Props = {
8
8
  label?: string;
9
9
  children?: string;
10
- icon: Icon;
10
+ icon?: Icon;
11
11
  size?: 'xSmall' | 'small' | 'medium' | 'large' | 'xLarge';
12
12
  width?: 'default' | 'narrow' | 'wide';
13
13
  iconSelected?: IconDefinition;
@@ -15,6 +15,7 @@ type Props = {
15
15
  variant?: IconButtonVariant;
16
16
  disabled?: boolean;
17
17
  activated?: boolean;
18
+ title?: string | null;
18
19
 
19
20
  /**
20
21
  * The shape of the button defines whether it is squared or rounded.
@@ -2,6 +2,7 @@ export * from './button.interface';
2
2
  export * from './card.interface';
3
3
  export * from './carousel-item.interface';
4
4
  export * from './carousel.interface';
5
+ export * from './checkbox.interface';
5
6
  export * from './chip.interface';
6
7
  export * from './chips.interface';
7
8
  export * from './divider.interface';
@@ -6,22 +6,25 @@ export type TextFieldVariant = 'filled' | 'outlined';
6
6
 
7
7
  type Props = {
8
8
  placeholder?: string;
9
- name: string;
9
+ name?: string;
10
10
  label: string;
11
11
  disabled?: boolean;
12
12
  errorText?: string | null;
13
13
  supportingText?: string;
14
14
  trailingIcon?: React.ReactElement<typeof IconButton> | Icon;
15
15
  leadingIcon?: React.ReactElement<typeof IconButton> | Icon;
16
- onChange?: (value: string) => void;
16
+ onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
17
17
  showSupportingText?: boolean;
18
18
  suffix?: string;
19
19
 
20
- value: string;
20
+ value?: string;
21
+ defaultValue?: string;
22
+ id?: string;
23
+ style?: React.CSSProperties;
21
24
  variant?: TextFieldVariant;
22
25
  type?: 'text' | 'password' | 'number';
23
26
  autoComplete?: 'on' | 'off' | string;
24
- textLine?: 'singleLine' | 'multiLine' | 'textAreas';
27
+ multiline?: boolean;
25
28
  };
26
29
  export type TextFieldStates = {
27
30
  isFocused: boolean;
@@ -0,0 +1,64 @@
1
+ import {
2
+ type ClassNameComponent,
3
+ classNames,
4
+ createUseClassNames,
5
+ defaultClassNames,
6
+ } from '../utils';
7
+ import { CheckboxInterface } from '../interfaces/checkbox.interface';
8
+
9
+ const checkboxConfig: ClassNameComponent<CheckboxInterface> = ({
10
+ isChecked,
11
+ isIndeterminate,
12
+ isDisabled,
13
+ isError,
14
+ isFocused,
15
+ isHovered,
16
+ }) => ({
17
+ checkbox: classNames(
18
+ 'inline-flex items-center justify-center relative size-4.5 ',
19
+ {
20
+ 'pointer-events-none opacity-[0.38]': isDisabled,
21
+ },
22
+ ),
23
+ input: classNames(
24
+ 'absolute inset-0 w-full h-full opacity-0 z-10 cursor-pointer',
25
+ ),
26
+ container: classNames(
27
+ 'relative flex items-center justify-center w-[18px] h-[18px] ',
28
+ ),
29
+ box: classNames(
30
+ 'absolute left-1/2 top-1/2 -translate-1/2 to rounded-[2px] size-4 border-2 transition-colors duration-200',
31
+ // Unchecked state (Border only)
32
+ !isChecked &&
33
+ !isIndeterminate && {
34
+ 'border-on-surface-variant': !isError && !isDisabled,
35
+ 'border-error': isError && !isDisabled,
36
+ 'border-on-surface': isDisabled,
37
+ },
38
+ // Checked or Indeterminate state (Filled)
39
+ (isChecked || isIndeterminate) && {
40
+ 'bg-primary border-primary': !isError && !isDisabled,
41
+ 'bg-error border-error': isError && !isDisabled,
42
+ 'bg-on-surface border-on-surface': isDisabled,
43
+ },
44
+ ),
45
+ icon: classNames(
46
+ 'z-10 relative text-on-primary w-full h-full flex items-center justify-center pointer-events-none',
47
+ {
48
+ 'text-on-error': isError && !isDisabled,
49
+ 'text-surface': isDisabled, // Usually on-surface with opacity against on-surface bg? No, checked disabled is on-surface bg with surface icon usually.
50
+ },
51
+ ),
52
+ stateLayer:
53
+ 'size-10 state-ripple-group-[checkbox] rounded-full cursor-pointer pointer-events-auto absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2',
54
+ });
55
+
56
+ export const checkboxStyle = defaultClassNames<CheckboxInterface>(
57
+ 'checkbox',
58
+ checkboxConfig,
59
+ );
60
+
61
+ export const useCheckboxStyle = createUseClassNames<CheckboxInterface>(
62
+ 'checkbox',
63
+ checkboxConfig,
64
+ );
@@ -0,0 +1,43 @@
1
+ import {
2
+ type ClassNameComponent,
3
+ classNames,
4
+ createUseClassNames,
5
+ defaultClassNames,
6
+ } from '../utils';
7
+ import { DatePickerInterface } from '../interfaces/date-picker.interface';
8
+
9
+ const datePickerConfig: ClassNameComponent<DatePickerInterface> = ({
10
+ hasSelected,
11
+ }) => ({
12
+ datePicker: classNames(
13
+ 'inline-flex flex-col bg-surface-container-high rounded-[28px] p-3 shadow-sm select-none', // Using shadow-sm as placeholder for elevation
14
+ 'min-w-[320px]',
15
+ ),
16
+ header: classNames('flex items-center justify-between h-12 mb-2 px-2'),
17
+ monthNav: classNames(
18
+ 'flex items-center justify-center w-10 h-10 rounded-full text-on-surface-variant hover:bg-on-surface-variant/8 transition-colors cursor-pointer',
19
+ ),
20
+ monthLabel: classNames(
21
+ 'text-label-large text-on-surface font-bold capitalize',
22
+ ),
23
+ weekDays: classNames('grid grid-cols-7 mb-2'),
24
+ weekDay: classNames(
25
+ 'h-10 flex items-center justify-center text-body-small text-on-surface-variant',
26
+ ),
27
+ daysGrid: classNames('grid grid-cols-7 row-auto gap-y-2'),
28
+ dayCell: classNames('flex items-center justify-center h-10 p-0 relative'),
29
+ dayButton: classNames(
30
+ 'w-10 h-10 rounded-full flex items-center justify-center text-body-large transition-all duration-200 relative overflow-hidden z-10 outline-none',
31
+ // Base style is implicit text-on-surface
32
+ ),
33
+ });
34
+
35
+ export const datePickerStyle = defaultClassNames<DatePickerInterface>(
36
+ 'datePicker',
37
+ datePickerConfig,
38
+ );
39
+
40
+ export const useDatePickerStyle = createUseClassNames<DatePickerInterface>(
41
+ 'datePicker',
42
+ datePickerConfig,
43
+ );
@@ -2,6 +2,7 @@ export * from './button.style';
2
2
  export * from './card.style';
3
3
  export * from './carousel-item.style';
4
4
  export * from './carousel.style';
5
+ export * from './checkbox.style';
5
6
  export * from './chip.style';
6
7
  export * from './chips.style';
7
8
  export * from './divider.style';
@@ -16,14 +16,14 @@ const textFieldConfig: ClassNameComponent<TextFieldInterface> = ({
16
16
  isFocused,
17
17
  value,
18
18
  suffix,
19
- textLine,
19
+ multiline,
20
20
  }) => ({
21
21
  textField: classNames({
22
22
  'opacity-[.38]': disabled,
23
23
  }),
24
24
  content: classNames(
25
25
  'group/text-field transition-border duration-200 relative flex items-center ',
26
- { 'h-14': textLine == 'singleLine' },
26
+ { 'h-14': !multiline },
27
27
  {
28
28
  'border-on-surface-variant':
29
29
  !errorText?.length && !isFocused && variant == 'filled',