@soul-refiner/design-system 0.2.88 → 0.2.90

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.
@@ -15,9 +15,13 @@ export interface DropdownProps extends NativeProps, React.PropsWithChildren {
15
15
  options?: (Omit<DropdownOptionProps, 'selected' | 'onClick'> | 'break')[];
16
16
  sx?: string;
17
17
  trigger: React.ReactElement;
18
+ containerSx?: string;
19
+ additionalOptions?: Omit<DropdownOptionProps, 'selected' | 'onClick'>[];
20
+ additionalOnChange?: (value: string) => void;
21
+ defaultAdditionalValue?: string;
18
22
  }
19
23
  declare const Dropdown: {
20
- ({ checkbox, children, closeOnChange, closeOnBlur, defaultValue, disabled, hasArrow, maintainState, multiple, offset, onChange, open: openDirection, options, sx, trigger, ...rest }: DropdownProps): React.JSX.Element;
24
+ ({ checkbox, children, closeOnChange, closeOnBlur, defaultValue, disabled, hasArrow, maintainState, multiple, offset, onChange, open: openDirection, options, sx, trigger, containerSx, additionalOptions, additionalOnChange, defaultAdditionalValue, ...rest }: DropdownProps): React.JSX.Element;
21
25
  Option: {
22
26
  ({ checkbox, disabled, icon, label, onClick, selected, sublabel, sx, value, color, }: DropdownOptionProps): React.JSX.Element;
23
27
  displayName: string;
@@ -2,12 +2,13 @@
2
2
  import React from 'react';
3
3
  import styled from 'styled-components';
4
4
  import { Box, Checkbox, P } from '../../';
5
- const Dropdown = ({ checkbox, children, closeOnChange = true, closeOnBlur = true, defaultValue = '', disabled = false, hasArrow, maintainState = true, multiple, offset = [0, 16], onChange, open: openDirection = 'right', options, sx, trigger, ...rest }) => {
5
+ const Dropdown = ({ checkbox, children, closeOnChange = true, closeOnBlur = true, defaultValue = '', disabled = false, hasArrow, maintainState = true, multiple, offset = [0, 16], onChange, open: openDirection = 'right', options, sx, trigger, containerSx, additionalOptions, additionalOnChange, defaultAdditionalValue, ...rest }) => {
6
6
  const id = React.useId();
7
7
  const wrapperRef = React.useRef(null);
8
8
  const optionsRef = React.useRef(null);
9
9
  const [open, setOpen] = React.useState(false);
10
10
  const [selected, setSelected] = React.useState(() => defaultValue ? defaultValue : multiple ? [] : '');
11
+ const [additionalSelected, setAdditionalSelected] = React.useState(defaultAdditionalValue || '');
11
12
  React.useEffect(() => {
12
13
  if (disabled) {
13
14
  setOpen(false);
@@ -57,6 +58,18 @@ const Dropdown = ({ checkbox, children, closeOnChange = true, closeOnBlur = true
57
58
  onChange(event);
58
59
  };
59
60
  const handleChange = multiple ? handleChangeMultiple : handleChangeSingle;
61
+ const handleAdditionalChange = (event) => {
62
+ event.stopPropagation();
63
+ const value = event.target.getAttribute('data-value') ?? '';
64
+ if (additionalSelected !== value) {
65
+ setAdditionalSelected(value);
66
+ }
67
+ else {
68
+ setAdditionalSelected('');
69
+ }
70
+ if (additionalOnChange)
71
+ additionalOnChange(value);
72
+ };
60
73
  const isSelected = (value) => maintainState && (multiple ? selected.includes(value) : value === selected);
61
74
  /**
62
75
  * allow for the API to accept children as options
@@ -91,7 +104,10 @@ const Dropdown = ({ checkbox, children, closeOnChange = true, closeOnBlur = true
91
104
  trigger.type?.name !== 'Button')
92
105
  ? { onClick: handleOpen }
93
106
  : { isDropdownOpen: open, onClick: handleOpen }),
94
- open && (React.createElement(Container, { "$hasArrow": hasArrow, "$offset": offset, "$openDirection": openDirection, ref: optionsRef }, dropdownOptions))));
107
+ open && (React.createElement(Container, { "$hasArrow": hasArrow, "$offset": offset, "$openDirection": openDirection, ref: optionsRef, "$sx": containerSx },
108
+ React.createElement("div", { style: { display: 'flex' } },
109
+ React.createElement("div", { style: { display: 'flex', flexDirection: 'column' } }, dropdownOptions),
110
+ !!additionalOptions?.length && (React.createElement("div", { style: { display: 'flex', flexDirection: 'column' } }, additionalOptions.map((additionalOption) => (React.createElement(Option, { key: additionalOption.value, onClick: handleAdditionalChange, selected: additionalSelected === additionalOption.value, label: additionalOption.label, value: additionalOption.value }))))))))));
95
111
  };
96
112
  const Wrapper = styled.div `
97
113
  position: relative;
@@ -109,6 +125,7 @@ const Container = styled.div `
109
125
  cursor: pointer;
110
126
  box-shadow: var(--elevation-2);
111
127
  border-radius: 8px;
128
+ overflow: scroll;
112
129
 
113
130
  & > div:first-of-type {
114
131
  border-radius: 8px 8px 0px 0px;
@@ -118,6 +135,8 @@ const Container = styled.div `
118
135
  border-radius: 0px 0px 8px 8px;
119
136
  }
120
137
 
138
+ ${({ $sx }) => ($sx ? $sx : '')}
139
+
121
140
  ${({ $openDirection }) => ($openDirection === 'left' ? 'right: 100%;' : '')}
122
141
 
123
142
  ${({ $hasArrow, $offset }) => $hasArrow
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export interface CalendarInputProps {
3
+ selectedDate: Date;
4
+ onSelect: (value: Date) => void;
5
+ }
6
+ export declare const CalendarInput: ({ selectedDate, onSelect: parentOnSelect, }: CalendarInputProps) => React.JSX.Element;
@@ -0,0 +1,250 @@
1
+ 'use client';
2
+ import React from 'react';
3
+ import styled from 'styled-components';
4
+ import { MONTHS, WEEKDAYS } from '../../../common';
5
+ import { Button, P } from '../..';
6
+ import { ChevronLeft, ChevronRight } from '../../../icons';
7
+ import { buildCalendar, zeroPad } from '../../../utils';
8
+ import { Icons } from 'index';
9
+ export const CalendarInput = ({ selectedDate, onSelect: parentOnSelect, }) => {
10
+ const today = new Date();
11
+ today.setHours(0);
12
+ today.setMinutes(0);
13
+ today.setSeconds(0);
14
+ today.setMilliseconds(0);
15
+ const firstOfMonth = new Date(today);
16
+ firstOfMonth.setDate(1);
17
+ const pickerRef = React.useRef(null);
18
+ const [show, setShow] = React.useState(false);
19
+ const [displayDate, setDisplayDate] = React.useState(() => selectedDate.toDateString());
20
+ const [componentSelectedDate, setComponentSelectedDate] = React.useState(() => selectedDate.toDateString());
21
+ React.useEffect(() => {
22
+ setComponentSelectedDate(selectedDate.toDateString());
23
+ }, [selectedDate]);
24
+ const handleShow = () => setShow((prev) => !prev);
25
+ const handleBlur = (event) => {
26
+ if (pickerRef?.current &&
27
+ !pickerRef?.current?.contains(event.relatedTarget)) {
28
+ setShow(false);
29
+ }
30
+ };
31
+ const handlePreviousMonth = () => {
32
+ setDisplayDate((prev) => {
33
+ const newDate = new Date(prev);
34
+ newDate.setMonth(newDate.getMonth() - 1);
35
+ return newDate.toDateString();
36
+ });
37
+ };
38
+ const handleNextMonth = () => {
39
+ setDisplayDate((prev) => {
40
+ const newDate = new Date(prev);
41
+ newDate.setMonth(newDate.getMonth() + 1);
42
+ return newDate.toDateString();
43
+ });
44
+ };
45
+ const onSelect = (newDate) => {
46
+ setComponentSelectedDate(newDate.toDateString());
47
+ };
48
+ const handleApply = () => {
49
+ parentOnSelect(new Date(componentSelectedDate));
50
+ setShow(false);
51
+ };
52
+ const handleClick = (event) => {
53
+ const target = event.target;
54
+ const day = target.getAttribute('data-day');
55
+ const month = target.getAttribute('data-month');
56
+ const year = target.getAttribute('data-year');
57
+ onSelect(new Date(`${month}-${day}-${year}`));
58
+ };
59
+ const handleCancel = () => {
60
+ setComponentSelectedDate(selectedDate.toDateString());
61
+ setShow(false);
62
+ };
63
+ const calendar = buildCalendar(new Date(displayDate).getMonth() + 1, new Date(displayDate).getFullYear());
64
+ const [month, day, year] = selectedDate
65
+ .toLocaleString('default', {
66
+ year: '2-digit',
67
+ month: '2-digit',
68
+ day: '2-digit',
69
+ })
70
+ .split('/');
71
+ return (React.createElement(Wrapper, { onBlurCapture: handleBlur, ref: pickerRef, tabIndex: 0 },
72
+ React.createElement(InputWrapper, null,
73
+ React.createElement(Input, { value: `${month} / ${day} / ${year}`, onFocus: handleShow, style: { letterSpacing: '1px', fontSize: '16px' }, readOnly: true }),
74
+ React.createElement(Icons.Calendar, null)),
75
+ show && (React.createElement(DateSelector, null,
76
+ React.createElement(InnerWrapper, null,
77
+ React.createElement("div", null,
78
+ React.createElement(MonthBar, null,
79
+ React.createElement(Arrow, { onClick: handlePreviousMonth },
80
+ React.createElement(ChevronLeft, { size: 24 })),
81
+ React.createElement(P, null, `${Object.values(MONTHS)[Math.max(0, Math.min(new Date(displayDate).getMonth(), 11))]} ${new Date(displayDate).getFullYear()}`),
82
+ React.createElement(Arrow, { onClick: handleNextMonth },
83
+ React.createElement(ChevronRight, { size: 24 }))),
84
+ React.createElement(WeekdayWrapper, null, Object.values(WEEKDAYS).map((day) => (React.createElement(P, { key: day }, day)))),
85
+ React.createElement(Calendar, null, calendar.map((week, index) => {
86
+ return (React.createElement(Week, { key: 'week-' + index.toString(36) }, week.map((day, dayIndex) => {
87
+ const isCurrMonth = day[1] !==
88
+ zeroPad(new Date(displayDate).getMonth() + 1, 2);
89
+ const dateObj = new Date(`${day[1]}-${day[2]}-${day[0]}`);
90
+ const isToday = Math.abs(dateObj.getTime() - today.getTime()) < 0.5;
91
+ const isSelected = new Date(componentSelectedDate).getTime() ===
92
+ dateObj.getTime();
93
+ return (React.createElement(Day, { className: `${isToday ? 'today' : ''}${isCurrMonth ? ' not-current' : ''}${isSelected ? ' selected' : ''}`.trim(), "data-day": day[2], "data-month": day[1], "data-year": day[0], key: 'day-' + dayIndex.toString(36), onClick: handleClick }, `${day[2]}`.startsWith('0')
94
+ ? `${day[2]}`[1]
95
+ : day[2]));
96
+ })));
97
+ })),
98
+ React.createElement(BottomWrapper, null,
99
+ React.createElement(Button, { onClick: handleCancel, size: "small", sx: "width: 80px;", type: "outlined" }, "Cancel"),
100
+ React.createElement(Button, { onClick: handleApply, size: "small", sx: "width: 80px;" }, "Apply"))))))));
101
+ };
102
+ const Wrapper = styled.div `
103
+ position: relative;
104
+ width: fit-content;
105
+ font-family: var(--font-inter);
106
+ `;
107
+ const DateSelector = styled.div `
108
+ transform: translateY(26px);
109
+ position: absolute;
110
+ z-index: 5;
111
+ background-color: #ffffff;
112
+ border-radius: 25px;
113
+ box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.25);
114
+ `;
115
+ const InnerWrapper = styled.div `
116
+ display: flex;
117
+ gap: 31px;
118
+ padding: 30px;
119
+ position: relative;
120
+ border-radius: 25px;
121
+
122
+ &::before {
123
+ position: absolute;
124
+ content: '';
125
+ width: 24px;
126
+ height: 24px;
127
+ top: -12px;
128
+ left: 48px;
129
+ background-color: #ffffff;
130
+ transform: rotate(45deg);
131
+ box-shadow: -3px -3px 5px rgba(0, 0, 0, 0.1);
132
+ }
133
+ `;
134
+ const MonthBar = styled.div `
135
+ display: flex;
136
+ justify-content: space-between;
137
+ align-items: center;
138
+ margin-bottom: 32px;
139
+ user-select: none;
140
+ `;
141
+ const Arrow = styled.button `
142
+ appearance: none;
143
+ border: none;
144
+ outline: none;
145
+ padding: 12px;
146
+ display: flex;
147
+ justify-content: center;
148
+ align-items: center;
149
+ border-radius: 50%;
150
+ cursor: pointer;
151
+ background-color: transparent;
152
+
153
+ &:hover {
154
+ background-color: var(--color-primary-blue-2);
155
+ border-color: #ffffff;
156
+ svg {
157
+ fill: #ffffff;
158
+ }
159
+ }
160
+ `;
161
+ const WeekdayWrapper = styled.div `
162
+ display: flex;
163
+ gap: 32px;
164
+ user-select: none;
165
+ `;
166
+ const Calendar = styled.div `
167
+ display: flex;
168
+ flex-direction: column;
169
+ gap: 32px;
170
+ margin: 32px 0px;
171
+ user-select: none;
172
+ `;
173
+ const Week = styled.div `
174
+ display: flex;
175
+ gap: 32px;
176
+ border-radius: 24px;
177
+ `;
178
+ const Day = styled.button `
179
+ outline: none;
180
+ border: none;
181
+ background: transparent;
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: center;
185
+ width: 32px;
186
+ height: 32px;
187
+ border-radius: 50%;
188
+ cursor: pointer;
189
+ font-family: var(--font-inter);
190
+ font-size: 16px;
191
+ line-height: 24px;
192
+
193
+ &.today {
194
+ color: var(--color-primary-blue-2);
195
+ font-weight: 600;
196
+ }
197
+
198
+ &.not-current {
199
+ color: var(--color-grey-9);
200
+ cursor: default;
201
+ pointer-events: none;
202
+ }
203
+
204
+ &.selected {
205
+ background-color: var(--color-primary-blue-2);
206
+ color: #ffffff;
207
+
208
+ &.not-current {
209
+ background-color: var(--color-blue-9);
210
+ }
211
+ }
212
+ `;
213
+ const BottomWrapper = styled.div `
214
+ display: flex;
215
+ justify-content: flex-end;
216
+ gap: 18px;
217
+ `;
218
+ const Input = styled.input `
219
+ padding: 0px;
220
+ flex: 1;
221
+ font-family: var(--font-inter);
222
+ font-size: 14px;
223
+ color: var(--color-grey-3);
224
+ border: none;
225
+ outline: none;
226
+ border-radius: 8px;
227
+ background-color: transparent;
228
+
229
+ &::placeholder {
230
+ color: var(--color-grey-6);
231
+ }
232
+ `;
233
+ const InputWrapper = styled.div `
234
+ display: flex;
235
+ gap: 8px;
236
+ align-items: center;
237
+ box-sizing: border-box;
238
+ padding: 12px;
239
+ background-color: var(--color-blue-10);
240
+ border-radius: 8px;
241
+ border: 1px solid transparent;
242
+
243
+ &:hover {
244
+ border-color: var(--color-grey-8);
245
+ }
246
+
247
+ &:focus-within {
248
+ border-color: var(--color-primary-blue-2);
249
+ }
250
+ `;
@@ -0,0 +1,2 @@
1
+ export { CalendarInput } from './calendar';
2
+ export type { CalendarInputProps } from './calendar';
@@ -0,0 +1 @@
1
+ export { CalendarInput } from './calendar';
@@ -14,3 +14,7 @@ export { TextArea } from './text_area';
14
14
  export type { TextAreaProps } from './text_area';
15
15
  export { TextInput } from './text_input';
16
16
  export type { TextInputProps } from './text_input';
17
+ export { CalendarInput } from './calendar';
18
+ export type { CalendarInputProps } from './calendar';
19
+ export { Time } from './time';
20
+ export type { TimeProps } from './time';
@@ -6,3 +6,5 @@ export { Search } from './search';
6
6
  export { Select } from './select';
7
7
  export { TextArea } from './text_area';
8
8
  export { TextInput } from './text_input';
9
+ export { CalendarInput } from './calendar';
10
+ export { Time } from './time';
@@ -0,0 +1,2 @@
1
+ export { Time } from './time';
2
+ export type { TimeProps } from './time';
@@ -0,0 +1 @@
1
+ export { Time } from './time';
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export type TimeProps = {
3
+ selectedTime: string;
4
+ setTime: (value: string) => void;
5
+ selectedPeriod: string;
6
+ setPeriod: (value: string) => void;
7
+ };
8
+ export declare const Time: ({ selectedTime, setTime, selectedPeriod, setPeriod, }: TimeProps) => React.JSX.Element;
@@ -0,0 +1,69 @@
1
+ 'use client';
2
+ import { Dropdown } from 'components/actions/dropdown/dropdown';
3
+ import { Icons } from 'index';
4
+ import React from 'react';
5
+ import styled from 'styled-components';
6
+ export const Time = ({ selectedTime, setTime, selectedPeriod, setPeriod, }) => {
7
+ const hours = React.useMemo(() => {
8
+ const hours = [];
9
+ for (let i = 1; i <= 12; i++) {
10
+ hours.push(`${i}:00`);
11
+ hours.push(`${i}:15`);
12
+ hours.push(`${i}:30`);
13
+ hours.push(`${i}:45`);
14
+ }
15
+ return hours;
16
+ }, []);
17
+ return (React.createElement(Dropdown, { options: hours.map((hour) => ({
18
+ value: hour,
19
+ label: hour,
20
+ })), containerSx: "height: 440px;", trigger: React.createElement(InputWrapper, null,
21
+ React.createElement(Input, { readOnly: true, value: `${selectedTime} ${selectedPeriod}` }),
22
+ React.createElement(Icons.Clock, null)), additionalOptions: [
23
+ {
24
+ label: 'AM',
25
+ value: 'AM',
26
+ },
27
+ {
28
+ label: 'PM',
29
+ value: 'PM',
30
+ },
31
+ ], onChange: (event) => {
32
+ const value = event.target.getAttribute('data-value') ?? '';
33
+ setTime(value);
34
+ }, additionalOnChange: setPeriod, defaultValue: selectedTime, defaultAdditionalValue: selectedPeriod }));
35
+ };
36
+ const InputWrapper = styled.div `
37
+ display: flex;
38
+ gap: 8px;
39
+ align-items: center;
40
+ box-sizing: border-box;
41
+ padding: 12px;
42
+ background-color: var(--color-blue-10);
43
+ border-radius: 8px;
44
+ border: 1px solid transparent;
45
+
46
+ &:hover {
47
+ border-color: var(--color-grey-8);
48
+ }
49
+
50
+ &:focus-within {
51
+ border-color: var(--color-primary-blue-2);
52
+ }
53
+ `;
54
+ const Input = styled.input `
55
+ padding: 0px;
56
+ flex: 1;
57
+ font-family: var(--font-inter);
58
+ font-size: 16px;
59
+ line-height: 24px;
60
+ color: var(--color-grey-3);
61
+ border: none;
62
+ outline: none;
63
+ border-radius: 8px;
64
+ background-color: transparent;
65
+
66
+ &::placeholder {
67
+ color: var(--color-grey-6);
68
+ }
69
+ `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soul-refiner/design-system",
3
- "version": "0.2.88",
3
+ "version": "0.2.90",
4
4
  "main": "dist/index.js",
5
5
  "license": "MIT",
6
6
  "publishConfig": {