@majoo-ui/react 2.1.3 → 2.2.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.
- package/components/dropdownMenu/DropdownMenu.esm.js +153 -23
- package/components/periodSelect/PeriodSelect.esm.js +212 -0
- package/index.esm.js +2 -1
- package/package.json +1 -1
- package/src/components/index.d.ts +1 -0
- package/src/components/periodSelect/PeriodSelect.d.ts +83 -0
- package/src/components/periodSelect/index.d.ts +2 -0
- package/utils/calendar.esm.js +5 -1
|
@@ -47,9 +47,7 @@ const slideLeftAndFade = keyframes({
|
|
|
47
47
|
transform: 'translateX(0)'
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
|
-
const
|
|
51
|
-
width: 143,
|
|
52
|
-
maxWidth: 243,
|
|
50
|
+
const contentStyles = {
|
|
53
51
|
backgroundColor: '$bgWhite',
|
|
54
52
|
borderRadius: 4,
|
|
55
53
|
padding: 8,
|
|
@@ -75,6 +73,19 @@ const StyledContent = styled(DropdownMenuPrimitive.Content, {
|
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
}
|
|
76
|
+
};
|
|
77
|
+
const StyledContent = styled(DropdownMenuPrimitive.Content, {
|
|
78
|
+
width: 143,
|
|
79
|
+
maxWidth: 243,
|
|
80
|
+
...contentStyles
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Submenus size to their own content instead of inheriting the trigger-sized width above.
|
|
84
|
+
const StyledSubContent = styled(DropdownMenuPrimitive.SubContent, {
|
|
85
|
+
width: 'max-content',
|
|
86
|
+
minWidth: 180,
|
|
87
|
+
maxWidth: 320,
|
|
88
|
+
...contentStyles
|
|
78
89
|
});
|
|
79
90
|
const itemStyles = {
|
|
80
91
|
all: 'unset',
|
|
@@ -97,24 +108,105 @@ const itemStyles = {
|
|
|
97
108
|
'&:active': {
|
|
98
109
|
backgroundColor: '$gray150'
|
|
99
110
|
},
|
|
100
|
-
|
|
111
|
+
// Radix moves focus to the highlighted item, but data-highlighted is the attribute it
|
|
112
|
+
// guarantees — keep both so hover and keyboard land on the same style.
|
|
113
|
+
'&:focus, &[data-highlighted]': {
|
|
101
114
|
backgroundColor: '$gray100'
|
|
102
115
|
}
|
|
103
116
|
};
|
|
117
|
+
const selectedItemStyles = {
|
|
118
|
+
backgroundColor: '$bgSelectedLight',
|
|
119
|
+
color: '$textBrand',
|
|
120
|
+
fontWeight: 600
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Space reserved for the indicator drawn in the item's left gutter.
|
|
124
|
+
const INDICATOR_GUTTER = 28;
|
|
104
125
|
const StyledItem = styled(DropdownMenuPrimitive.Item, {
|
|
105
|
-
...itemStyles
|
|
126
|
+
...itemStyles,
|
|
127
|
+
variants: {
|
|
128
|
+
selected: {
|
|
129
|
+
true: selectedItemStyles
|
|
130
|
+
}
|
|
131
|
+
}
|
|
106
132
|
});
|
|
107
133
|
StyledItem.propTypes = {
|
|
108
134
|
asChild: PropTypes.bool,
|
|
109
135
|
disabled: PropTypes.bool,
|
|
110
|
-
onSelect: PropTypes.func
|
|
136
|
+
onSelect: PropTypes.func,
|
|
137
|
+
selected: PropTypes.bool
|
|
111
138
|
};
|
|
112
139
|
const StyledCheckboxItem = styled(DropdownMenuPrimitive.CheckboxItem, {
|
|
113
|
-
...itemStyles
|
|
140
|
+
...itemStyles,
|
|
141
|
+
paddingLeft: INDICATOR_GUTTER,
|
|
142
|
+
'&[data-state="checked"]': {
|
|
143
|
+
color: '$textPrimary',
|
|
144
|
+
fontWeight: 600
|
|
145
|
+
}
|
|
114
146
|
});
|
|
147
|
+
|
|
148
|
+
// The ring and dot are drawn here rather than in ItemIndicator because Radix only mounts
|
|
149
|
+
// ItemIndicator while checked — the unchecked ring has to come from the item itself.
|
|
115
150
|
const StyledRadioItem = styled(DropdownMenuPrimitive.RadioItem, {
|
|
116
|
-
...itemStyles
|
|
151
|
+
...itemStyles,
|
|
152
|
+
paddingLeft: INDICATOR_GUTTER,
|
|
153
|
+
'&::before': {
|
|
154
|
+
content: '',
|
|
155
|
+
position: 'absolute',
|
|
156
|
+
left: 0,
|
|
157
|
+
top: '50%',
|
|
158
|
+
boxSizing: 'border-box',
|
|
159
|
+
width: 18,
|
|
160
|
+
height: 18,
|
|
161
|
+
borderRadius: '50%',
|
|
162
|
+
border: '1.5px solid $colors$formDefault',
|
|
163
|
+
transform: 'translateY(-50%)',
|
|
164
|
+
transition: 'border-color 120ms ease'
|
|
165
|
+
},
|
|
166
|
+
'&::after': {
|
|
167
|
+
content: '',
|
|
168
|
+
position: 'absolute',
|
|
169
|
+
left: 5,
|
|
170
|
+
top: '50%',
|
|
171
|
+
width: 8,
|
|
172
|
+
height: 8,
|
|
173
|
+
borderRadius: '50%',
|
|
174
|
+
backgroundColor: '$iconBrand',
|
|
175
|
+
transform: 'translateY(-50%) scale(0)',
|
|
176
|
+
transition: 'transform 120ms ease'
|
|
177
|
+
},
|
|
178
|
+
'&[data-state="checked"]': {
|
|
179
|
+
color: '$textPrimary',
|
|
180
|
+
fontWeight: 600,
|
|
181
|
+
'&::before': {
|
|
182
|
+
borderColor: '$formActive'
|
|
183
|
+
},
|
|
184
|
+
'&::after': {
|
|
185
|
+
transform: 'translateY(-50%) scale(1)'
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
'&[data-disabled]': {
|
|
189
|
+
'&::before': {
|
|
190
|
+
borderColor: '$formDisable'
|
|
191
|
+
},
|
|
192
|
+
'&::after': {
|
|
193
|
+
backgroundColor: '$iconDisable'
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
const StyledSubTrigger = styled(DropdownMenuPrimitive.SubTrigger, {
|
|
198
|
+
...itemStyles,
|
|
199
|
+
'&[data-state="open"]': selectedItemStyles,
|
|
200
|
+
variants: {
|
|
201
|
+
selected: {
|
|
202
|
+
true: selectedItemStyles
|
|
203
|
+
}
|
|
204
|
+
}
|
|
117
205
|
});
|
|
206
|
+
StyledSubTrigger.propTypes = {
|
|
207
|
+
disabled: PropTypes.bool,
|
|
208
|
+
selected: PropTypes.bool
|
|
209
|
+
};
|
|
118
210
|
const StyledLabel = styled(DropdownMenuPrimitive.Label, {
|
|
119
211
|
padding: '8px 0',
|
|
120
212
|
fontSize: 12,
|
|
@@ -129,7 +221,10 @@ const StyledSeparator = styled(DropdownMenuPrimitive.Separator, {
|
|
|
129
221
|
const StyledItemIndicator = styled(DropdownMenuPrimitive.ItemIndicator, {
|
|
130
222
|
position: 'absolute',
|
|
131
223
|
left: 0,
|
|
132
|
-
|
|
224
|
+
top: '50%',
|
|
225
|
+
width: 18,
|
|
226
|
+
height: 18,
|
|
227
|
+
transform: 'translateY(-50%)',
|
|
133
228
|
display: 'inline-flex',
|
|
134
229
|
alignItems: 'center',
|
|
135
230
|
justifyContent: 'center'
|
|
@@ -159,7 +254,7 @@ DropdownMenuContext.propTypes = {
|
|
|
159
254
|
align: PropTypes.oneOf(['start', 'center', 'end'])
|
|
160
255
|
};
|
|
161
256
|
const DropdownMenuContentContext = ({
|
|
162
|
-
theme,
|
|
257
|
+
theme = 'default',
|
|
163
258
|
...props
|
|
164
259
|
}) => {
|
|
165
260
|
const {
|
|
@@ -191,21 +286,43 @@ DropdownMenuContentContext.propTypes = {
|
|
|
191
286
|
alignOffset: PropTypes.number,
|
|
192
287
|
asChild: PropTypes.bool
|
|
193
288
|
};
|
|
194
|
-
|
|
289
|
+
|
|
290
|
+
// Radix positions submenus itself, so this only carries the theme class across the portal.
|
|
291
|
+
const DropdownMenuSubContentContext = ({
|
|
292
|
+
theme = 'default',
|
|
195
293
|
children,
|
|
196
294
|
...props
|
|
295
|
+
}) => {
|
|
296
|
+
const themeProvider = useThemeProvider(theme);
|
|
297
|
+
return /*#__PURE__*/jsx(StyledSubContent, {
|
|
298
|
+
className: `dropdown-content ${themeProvider?.theme || ''}`,
|
|
299
|
+
...props,
|
|
300
|
+
children: children
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
DropdownMenuSubContentContext.propTypes = {
|
|
304
|
+
sideOffset: PropTypes.number,
|
|
305
|
+
alignOffset: PropTypes.number,
|
|
306
|
+
asChild: PropTypes.bool
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* @type {React.ForwardRefExoticComponent<
|
|
311
|
+
* React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger> & React.RefAttributes<HTMLButtonElement>
|
|
312
|
+
* >}
|
|
313
|
+
*/
|
|
314
|
+
const DropdownTrigger = /*#__PURE__*/React__default.forwardRef(({
|
|
315
|
+
children,
|
|
316
|
+
asChild,
|
|
317
|
+
...rest
|
|
197
318
|
}, ref) => {
|
|
198
|
-
const {
|
|
199
|
-
asChild,
|
|
200
|
-
...rest
|
|
201
|
-
} = props;
|
|
202
319
|
return /*#__PURE__*/jsx(DropdownMenuPrimitive.Trigger, {
|
|
203
320
|
...rest,
|
|
204
321
|
asChild: asChild,
|
|
205
322
|
ref: ref,
|
|
206
|
-
children: children
|
|
323
|
+
children: /*#__PURE__*/React__default.isValidElement(children) ? /*#__PURE__*/React__default.cloneElement(children, {
|
|
207
324
|
...rest
|
|
208
|
-
})
|
|
325
|
+
}) : children
|
|
209
326
|
});
|
|
210
327
|
});
|
|
211
328
|
DropdownTrigger.propTypes = {
|
|
@@ -213,11 +330,20 @@ DropdownTrigger.propTypes = {
|
|
|
213
330
|
};
|
|
214
331
|
const RightSlot = styled('div', {
|
|
215
332
|
marginLeft: 'auto',
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
333
|
+
paddingLeft: 16,
|
|
334
|
+
display: 'inline-flex',
|
|
335
|
+
alignItems: 'center',
|
|
219
336
|
'[data-disabled] &': {
|
|
220
337
|
color: '$gray400'
|
|
338
|
+
},
|
|
339
|
+
variants: {
|
|
340
|
+
// Secondary text (a hint or shortcut) rather than an icon.
|
|
341
|
+
muted: {
|
|
342
|
+
true: {
|
|
343
|
+
color: '$textDisable',
|
|
344
|
+
fontSize: 12
|
|
345
|
+
}
|
|
346
|
+
}
|
|
221
347
|
}
|
|
222
348
|
});
|
|
223
349
|
const StyledDropdown = styled(Button, {
|
|
@@ -261,7 +387,9 @@ const DropdownMenuCheckboxItem = StyledCheckboxItem;
|
|
|
261
387
|
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
262
388
|
const DropdownMenuRadioItem = StyledRadioItem;
|
|
263
389
|
const DropdownMenuItemIndicator = StyledItemIndicator;
|
|
264
|
-
|
|
390
|
+
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
391
|
+
const DropdownMenuSubTrigger = StyledSubTrigger;
|
|
392
|
+
const DropdownMenuSubContent = DropdownMenuSubContentContext;
|
|
265
393
|
const DropdownMenuLabel = StyledLabel;
|
|
266
394
|
const DropdownMenuSeparator = StyledSeparator;
|
|
267
395
|
const DropdownMenuArrow = StyledArrow;
|
|
@@ -273,9 +401,11 @@ DropdownMenuCheckboxItem.displayName = 'DropdownMenuCheckboxItem';
|
|
|
273
401
|
DropdownMenuRadioGroup.displayName = 'DropdownMenuRadioGroup';
|
|
274
402
|
DropdownMenuRadioItem.displayName = 'DropdownMenuRadioItem';
|
|
275
403
|
DropdownMenuItemIndicator.displayName = 'DropdownMenuItemIndicator';
|
|
276
|
-
|
|
404
|
+
DropdownMenuSub.displayName = 'DropdownMenuSub';
|
|
405
|
+
DropdownMenuSubTrigger.displayName = 'DropdownMenuSubTrigger';
|
|
406
|
+
DropdownMenuSubContent.displayName = 'DropdownMenuSubContent';
|
|
277
407
|
DropdownMenuLabel.displayName = 'DropdownMenuLabel';
|
|
278
408
|
DropdownMenuSeparator.displayName = 'DropdownMenuSeparator';
|
|
279
409
|
DropdownMenuArrow.displayName = 'DropdownMenuArrow';
|
|
280
410
|
|
|
281
|
-
export { ButtonDropdown, DropdownMenu, DropdownMenuArrow, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemIndicator, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, RightSlot, StyledDropdown };
|
|
411
|
+
export { ButtonDropdown, DropdownMenu, DropdownMenuArrow, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemIndicator, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, RightSlot, StyledDropdown };
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import 'core-js/modules/es.iterator.constructor.js';
|
|
2
|
+
import 'core-js/modules/es.iterator.map.js';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
import React__default, { useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { CaretDownOutline, ChevronRightOutline } from '@majoo-ui/icons';
|
|
7
|
+
import { styled, colors } from '../../config/stitches.config.esm.js';
|
|
8
|
+
import { weekdayNamesFullEng, weekdayNamesFullId } from '../../utils/calendar.esm.js';
|
|
9
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSub, DropdownMenuSubTrigger, RightSlot, DropdownMenuSubContent, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem } from '../dropdownMenu/DropdownMenu.esm.js';
|
|
10
|
+
|
|
11
|
+
const Trigger = styled('button', {
|
|
12
|
+
all: 'unset',
|
|
13
|
+
boxSizing: 'border-box',
|
|
14
|
+
display: 'inline-flex',
|
|
15
|
+
alignItems: 'center',
|
|
16
|
+
gap: '$spacing-02',
|
|
17
|
+
padding: '0 $spacing-04',
|
|
18
|
+
border: '1px solid $bgOutline',
|
|
19
|
+
borderRadius: '$lg',
|
|
20
|
+
backgroundColor: '$bgWhite',
|
|
21
|
+
color: '$textPrimary',
|
|
22
|
+
fontFamily: 'inherit',
|
|
23
|
+
fontSize: '$short-content-regular',
|
|
24
|
+
lineHeight: '$short-content-regular',
|
|
25
|
+
letterSpacing: '$short-content-regular',
|
|
26
|
+
cursor: 'pointer',
|
|
27
|
+
'&:hover': {
|
|
28
|
+
borderColor: '$primary600'
|
|
29
|
+
},
|
|
30
|
+
'&[data-state="open"]': {
|
|
31
|
+
borderColor: '$primary400'
|
|
32
|
+
},
|
|
33
|
+
variants: {
|
|
34
|
+
size: {
|
|
35
|
+
sm: {
|
|
36
|
+
height: 32
|
|
37
|
+
},
|
|
38
|
+
lg: {
|
|
39
|
+
height: 40
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
// Named apart from the DOM attribute so Stitches does not swallow it as a variant —
|
|
43
|
+
// the button still needs a real `disabled` to block the menu from opening.
|
|
44
|
+
isDisabled: {
|
|
45
|
+
true: {
|
|
46
|
+
backgroundColor: '$formDisable',
|
|
47
|
+
color: '$textDisable',
|
|
48
|
+
cursor: 'not-allowed',
|
|
49
|
+
'&:hover': {
|
|
50
|
+
borderColor: '$bgOutline'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
defaultVariants: {
|
|
56
|
+
size: 'lg'
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const TriggerLabel = styled('span', {
|
|
60
|
+
fontWeight: 600
|
|
61
|
+
});
|
|
62
|
+
const TriggerRange = styled('span', {
|
|
63
|
+
color: '$textDisable'
|
|
64
|
+
});
|
|
65
|
+
const MENU_ITEM_CSS = {
|
|
66
|
+
paddingLeft: '$spacing-04',
|
|
67
|
+
paddingRight: '$spacing-04'
|
|
68
|
+
};
|
|
69
|
+
const DEFAULT_PERIODS = ['day', 'week', 'month'];
|
|
70
|
+
// Listed Monday first, the way the week reads in Indonesian — not in Date#getDay order.
|
|
71
|
+
const START_DAY_ORDER = [1, 2, 3, 4, 5, 6, 0];
|
|
72
|
+
const PeriodSelect = /*#__PURE__*/React__default.forwardRef(({
|
|
73
|
+
value,
|
|
74
|
+
onChange,
|
|
75
|
+
startDay,
|
|
76
|
+
onStartDayChange,
|
|
77
|
+
defaultStartDay = 1,
|
|
78
|
+
resetStartDayOnPeriodChange = true,
|
|
79
|
+
periods = DEFAULT_PERIODS,
|
|
80
|
+
showRange = true,
|
|
81
|
+
disabled = false,
|
|
82
|
+
size = 'lg',
|
|
83
|
+
side = 'bottom',
|
|
84
|
+
align = 'start',
|
|
85
|
+
periodLabels,
|
|
86
|
+
startWeekLabel,
|
|
87
|
+
formatWeekRange,
|
|
88
|
+
css
|
|
89
|
+
}, ref) => {
|
|
90
|
+
const {
|
|
91
|
+
t,
|
|
92
|
+
i18n: {
|
|
93
|
+
language
|
|
94
|
+
}
|
|
95
|
+
} = useTranslation(['MajooUI/periodSelect', 'translation']);
|
|
96
|
+
const [open, setOpen] = useState(false);
|
|
97
|
+
const [internalStartDay, setInternalStartDay] = useState(defaultStartDay);
|
|
98
|
+
const activeStartDay = startDay !== null && startDay !== void 0 ? startDay : internalStartDay;
|
|
99
|
+
const weekdayNames = language === 'en' ? weekdayNamesFullEng : weekdayNamesFullId;
|
|
100
|
+
// A week always spans 7 days, so the last one is always 6 days after the first.
|
|
101
|
+
const rangeLabel = (day, place) => {
|
|
102
|
+
const endDay = (day + 6) % 7;
|
|
103
|
+
const range = {
|
|
104
|
+
startDay: day,
|
|
105
|
+
endDay,
|
|
106
|
+
startName: weekdayNames[day],
|
|
107
|
+
endName: weekdayNames[endDay],
|
|
108
|
+
place
|
|
109
|
+
};
|
|
110
|
+
return formatWeekRange ? formatWeekRange(range) : `${range.startName} - ${range.endName}`;
|
|
111
|
+
};
|
|
112
|
+
const showWeekRange = showRange && value === 'week';
|
|
113
|
+
const defaultPeriodLabels = {
|
|
114
|
+
day: t('day', 'Hari'),
|
|
115
|
+
week: t('week', 'Minggu'),
|
|
116
|
+
month: t('month', 'Bulan')
|
|
117
|
+
};
|
|
118
|
+
const periodLabel = period => {
|
|
119
|
+
var _a;
|
|
120
|
+
return (_a = periodLabels === null || periodLabels === void 0 ? void 0 : periodLabels[period]) !== null && _a !== void 0 ? _a : defaultPeriodLabels[period];
|
|
121
|
+
};
|
|
122
|
+
const applyStartDay = day => {
|
|
123
|
+
setInternalStartDay(day);
|
|
124
|
+
onStartDayChange === null || onStartDayChange === void 0 ? void 0 : onStartDayChange(day);
|
|
125
|
+
};
|
|
126
|
+
const selectPeriod = period => {
|
|
127
|
+
onChange(period);
|
|
128
|
+
if (resetStartDayOnPeriodChange && period !== 'week' && activeStartDay !== defaultStartDay) {
|
|
129
|
+
applyStartDay(defaultStartDay);
|
|
130
|
+
}
|
|
131
|
+
setOpen(false);
|
|
132
|
+
};
|
|
133
|
+
const renderPeriodItem = period => {
|
|
134
|
+
if (period !== 'week') {
|
|
135
|
+
return jsx(DropdownMenuItem, {
|
|
136
|
+
selected: value === period,
|
|
137
|
+
onSelect: () => selectPeriod(period),
|
|
138
|
+
css: MENU_ITEM_CSS,
|
|
139
|
+
children: periodLabel(period)
|
|
140
|
+
}, period);
|
|
141
|
+
}
|
|
142
|
+
return jsxs(DropdownMenuSub, {
|
|
143
|
+
children: [jsxs(DropdownMenuSubTrigger, {
|
|
144
|
+
selected: value === 'week',
|
|
145
|
+
onClick: () => selectPeriod('week'),
|
|
146
|
+
css: MENU_ITEM_CSS,
|
|
147
|
+
children: [periodLabel('week'), jsx(RightSlot, {
|
|
148
|
+
children: jsx(ChevronRightOutline, {
|
|
149
|
+
size: "16",
|
|
150
|
+
color: "currentColor"
|
|
151
|
+
})
|
|
152
|
+
})]
|
|
153
|
+
}), jsxs(DropdownMenuSubContent, {
|
|
154
|
+
sideOffset: 8,
|
|
155
|
+
alignOffset: -8,
|
|
156
|
+
css: {
|
|
157
|
+
padding: '$spacing-04 $spacing-05'
|
|
158
|
+
},
|
|
159
|
+
children: [jsx(DropdownMenuLabel, {
|
|
160
|
+
children: startWeekLabel !== null && startWeekLabel !== void 0 ? startWeekLabel : t('startWeekFrom', 'Mulai minggu dari:')
|
|
161
|
+
}), jsx(DropdownMenuRadioGroup, {
|
|
162
|
+
value: String(activeStartDay),
|
|
163
|
+
onValueChange: day => {
|
|
164
|
+
applyStartDay(Number(day));
|
|
165
|
+
onChange('week');
|
|
166
|
+
},
|
|
167
|
+
children: START_DAY_ORDER.map(day => jsx(DropdownMenuRadioItem, {
|
|
168
|
+
value: String(day),
|
|
169
|
+
children: rangeLabel(day, 'option')
|
|
170
|
+
}, day))
|
|
171
|
+
})]
|
|
172
|
+
})]
|
|
173
|
+
}, period);
|
|
174
|
+
};
|
|
175
|
+
return jsxs(DropdownMenu, {
|
|
176
|
+
open: open,
|
|
177
|
+
onOpenChange: setOpen,
|
|
178
|
+
side: side,
|
|
179
|
+
align: align,
|
|
180
|
+
modal: false,
|
|
181
|
+
children: [jsx(DropdownMenuTrigger, {
|
|
182
|
+
asChild: true,
|
|
183
|
+
children: jsxs(Trigger, {
|
|
184
|
+
ref: ref,
|
|
185
|
+
size: size,
|
|
186
|
+
isDisabled: disabled,
|
|
187
|
+
disabled: disabled,
|
|
188
|
+
css: css,
|
|
189
|
+
type: "button",
|
|
190
|
+
children: [jsxs(TriggerLabel, {
|
|
191
|
+
children: [periodLabel(value), showWeekRange && ',']
|
|
192
|
+
}), showWeekRange && jsx(TriggerRange, {
|
|
193
|
+
children: rangeLabel(activeStartDay, 'trigger')
|
|
194
|
+
}), jsx(CaretDownOutline, {
|
|
195
|
+
size: "16",
|
|
196
|
+
color: disabled ? colors.iconDisable : colors.iconPrimary
|
|
197
|
+
})]
|
|
198
|
+
})
|
|
199
|
+
}), jsx(DropdownMenuContent, {
|
|
200
|
+
sideOffset: 4,
|
|
201
|
+
css: {
|
|
202
|
+
width: 'max-content',
|
|
203
|
+
minWidth: 160,
|
|
204
|
+
maxWidth: 'none'
|
|
205
|
+
},
|
|
206
|
+
children: periods.map(renderPeriodItem)
|
|
207
|
+
})]
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
PeriodSelect.displayName = 'PeriodSelect';
|
|
211
|
+
|
|
212
|
+
export { PeriodSelect as default };
|
package/index.esm.js
CHANGED
|
@@ -57,6 +57,7 @@ export { default as Skeleton } from './components/skeleton/Skeleton.esm.js';
|
|
|
57
57
|
export { default as TagList } from './components/tagList/TagList.esm.js';
|
|
58
58
|
export { ScrollSync } from './components/scrollSync/ScrollSync.esm.js';
|
|
59
59
|
export { ScrollSyncNode } from './components/scrollSync/ScrollSyncNode.esm.js';
|
|
60
|
+
export { default as PeriodSelect } from './components/periodSelect/PeriodSelect.esm.js';
|
|
60
61
|
export { useListOption } from './hooks/useListOption/useListOption.esm.js';
|
|
61
62
|
export { useToggle } from './hooks/useToggle/useToggle.esm.js';
|
|
62
63
|
export { Avatar } from './components/avatar/Avatar.esm.js';
|
|
@@ -94,7 +95,7 @@ export { default as Upload } from './components/upload/Upload.esm.js';
|
|
|
94
95
|
export { AlertDialog, AlertDialogCancel, AlertDialogConfirm, AlertDialogContent, AlertDialogDescription, AlertDialogFunction, AlertDialogRoot, AlertDialogTitle, AlertDialogTrigger } from './components/alertDialog/AlertDialog.esm.js';
|
|
95
96
|
export { BOTTOM_LEFT_POSITION, BOTTOM_RIGHT_POSITION, TOP_LEFT_POSITION, TOP_RIGHT_POSITION } from './components/toast/Toast.esm.js';
|
|
96
97
|
export { BreadcrumbItem } from './components/breadcrumb/Breadcrumb.esm.js';
|
|
97
|
-
export { ButtonDropdown, DropdownMenu, DropdownMenuArrow, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemIndicator, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, RightSlot, StyledDropdown } from './components/dropdownMenu/DropdownMenu.esm.js';
|
|
98
|
+
export { ButtonDropdown, DropdownMenu, DropdownMenuArrow, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemIndicator, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, RightSlot, StyledDropdown } from './components/dropdownMenu/DropdownMenu.esm.js';
|
|
98
99
|
export { ButtonGroup, ButtonGroupItem } from './components/buttonGroup/ButtonGroup.esm.js';
|
|
99
100
|
export { default as ColorPicker } from './components/colorPicker/ColorPicker.esm.js';
|
|
100
101
|
export { Drawer, DrawerBody, DrawerClose, DrawerCloseButton, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger } from './components/drawer/Drawer.esm.js';
|
package/package.json
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CSS } from '../../config/stitches.config';
|
|
3
|
+
export type PeriodValue = 'day' | 'week' | 'month';
|
|
4
|
+
export interface PeriodSelectProps {
|
|
5
|
+
/**
|
|
6
|
+
* The selected period.
|
|
7
|
+
*/
|
|
8
|
+
value: PeriodValue;
|
|
9
|
+
/**
|
|
10
|
+
* Called when the user picks a period. Picking a start day also reports `'week'`.
|
|
11
|
+
*/
|
|
12
|
+
onChange: (value: PeriodValue) => void;
|
|
13
|
+
/**
|
|
14
|
+
* First day of the week, indexed like `Date#getDay` (0 = Sunday, 1 = Monday).
|
|
15
|
+
* Leave undefined to let the component hold it internally.
|
|
16
|
+
*/
|
|
17
|
+
startDay?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Called when the user picks a different first day of the week.
|
|
20
|
+
*/
|
|
21
|
+
onStartDayChange?: (startDay: number) => void;
|
|
22
|
+
/**
|
|
23
|
+
* First day of the week before the user changes anything.
|
|
24
|
+
*/
|
|
25
|
+
defaultStartDay?: number;
|
|
26
|
+
/**
|
|
27
|
+
* If true, leaving the weekly period reports `defaultStartDay` back through
|
|
28
|
+
* `onStartDayChange`, so returning to weekly starts from the default again.
|
|
29
|
+
*/
|
|
30
|
+
resetStartDayOnPeriodChange?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Periods offered, in the order they are listed.
|
|
33
|
+
*/
|
|
34
|
+
periods?: PeriodValue[];
|
|
35
|
+
/**
|
|
36
|
+
* If false, the trigger shows the period alone, without the day range.
|
|
37
|
+
*/
|
|
38
|
+
showRange?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* If true, the component is disabled.
|
|
41
|
+
*/
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Specify the trigger size.
|
|
45
|
+
*/
|
|
46
|
+
size?: 'sm' | 'lg';
|
|
47
|
+
/**
|
|
48
|
+
* The preferred side of the trigger to render the menu against.
|
|
49
|
+
*/
|
|
50
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
51
|
+
/**
|
|
52
|
+
* The preferred alignment against the trigger.
|
|
53
|
+
*/
|
|
54
|
+
align?: 'start' | 'center' | 'end';
|
|
55
|
+
/**
|
|
56
|
+
* Replaces the label of one or more periods. Anything left out keeps its default
|
|
57
|
+
* (`Hari`, `Minggu`, `Bulan`), which already goes through i18n.
|
|
58
|
+
*/
|
|
59
|
+
periodLabels?: Partial<Record<PeriodValue, React.ReactNode>>;
|
|
60
|
+
/**
|
|
61
|
+
* Replaces the submenu heading above the start-day options.
|
|
62
|
+
*/
|
|
63
|
+
startWeekLabel?: React.ReactNode;
|
|
64
|
+
/**
|
|
65
|
+
* Replaces the default `Senin - Minggu` label, both on the trigger and on each option.
|
|
66
|
+
* `place` says which of the two is being rendered, so the two can read differently.
|
|
67
|
+
* Days are indexed like `Date#getDay`.
|
|
68
|
+
*/
|
|
69
|
+
formatWeekRange?: (range: WeekRange) => React.ReactNode;
|
|
70
|
+
/**
|
|
71
|
+
* Additional CSS trigger styles.
|
|
72
|
+
*/
|
|
73
|
+
css?: CSS;
|
|
74
|
+
}
|
|
75
|
+
export interface WeekRange {
|
|
76
|
+
startDay: number;
|
|
77
|
+
endDay: number;
|
|
78
|
+
startName: string;
|
|
79
|
+
endName: string;
|
|
80
|
+
place: 'trigger' | 'option';
|
|
81
|
+
}
|
|
82
|
+
declare const PeriodSelect: React.ForwardRefExoticComponent<PeriodSelectProps & React.RefAttributes<HTMLButtonElement>>;
|
|
83
|
+
export default PeriodSelect;
|
package/utils/calendar.esm.js
CHANGED
|
@@ -6,6 +6,10 @@ const monthNamesFullId = ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni'
|
|
|
6
6
|
const monthNamesFullEng = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
7
7
|
const weekdayNamesShortId = ['Min', 'Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab'];
|
|
8
8
|
const weekdayNamesShortEng = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
9
|
+
|
|
10
|
+
// Indexed like Date#getDay: 0 = Sunday.
|
|
11
|
+
const weekdayNamesFullId = ['Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu'];
|
|
12
|
+
const weekdayNamesFullEng = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
9
13
|
const yearRangesList = rangeStart => {
|
|
10
14
|
let start = rangeStart;
|
|
11
15
|
let end = start + 9;
|
|
@@ -23,4 +27,4 @@ const getCalendarStartYear = year => year - year % 10 + 1;
|
|
|
23
27
|
const getCalendarStartYearRange = year => year - year % 100 + 1;
|
|
24
28
|
const toDateFormat = (date, locale = 'id') => moment(date).locale(locale).format('DD MMMM YYYY');
|
|
25
29
|
|
|
26
|
-
export { getCalendarStartYear, getCalendarStartYearRange, monthNamesFullEng, monthNamesFullId, toDateFormat, weekdayNamesShortEng, weekdayNamesShortId, yearRangesList };
|
|
30
|
+
export { getCalendarStartYear, getCalendarStartYearRange, monthNamesFullEng, monthNamesFullId, toDateFormat, weekdayNamesFullEng, weekdayNamesFullId, weekdayNamesShortEng, weekdayNamesShortId, yearRangesList };
|