@opengovsg/oui 0.0.8 → 0.0.9

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 (68) hide show
  1. package/dist/cjs/calendar/calendar-base.cjs +347 -0
  2. package/dist/cjs/calendar/calendar-style-context.cjs +38 -0
  3. package/dist/cjs/calendar/calendar.cjs +16 -0
  4. package/dist/cjs/calendar/index.cjs +22 -0
  5. package/dist/cjs/calendar/types.cjs +3 -0
  6. package/dist/cjs/calendar/utils.cjs +62 -0
  7. package/dist/cjs/index.cjs +20 -2
  8. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/{check.cjs → chevron-left.cjs} +3 -3
  9. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/{chevrons-up-down.cjs → chevron-right.cjs} +3 -6
  10. package/dist/cjs/select/select-item.cjs +11 -24
  11. package/dist/cjs/select/select.cjs +14 -6
  12. package/dist/cjs/system/utils.cjs +9 -6
  13. package/dist/cjs/tag-field/index.cjs +2 -0
  14. package/dist/cjs/tag-field/tag-field-item.cjs +28 -0
  15. package/dist/cjs/tag-field/tag-field-list.cjs +11 -22
  16. package/dist/cjs/tag-field/tag-field-tag-list.cjs +3 -2
  17. package/dist/cjs/tag-field/tag-field.cjs +3 -2
  18. package/dist/esm/calendar/calendar-base.js +343 -0
  19. package/dist/esm/calendar/calendar-style-context.js +34 -0
  20. package/dist/esm/calendar/calendar.js +14 -0
  21. package/dist/esm/calendar/index.js +5 -0
  22. package/dist/esm/calendar/types.js +1 -0
  23. package/dist/esm/calendar/utils.js +57 -0
  24. package/dist/esm/index.js +6 -1
  25. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/{check.js → chevron-left.js} +3 -3
  26. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-right.js +14 -0
  27. package/dist/esm/select/select-item.js +12 -25
  28. package/dist/esm/select/select.js +15 -7
  29. package/dist/esm/system/utils.js +9 -6
  30. package/dist/esm/tag-field/index.js +1 -0
  31. package/dist/esm/tag-field/tag-field-item.js +26 -0
  32. package/dist/esm/tag-field/tag-field-list.js +12 -22
  33. package/dist/esm/tag-field/tag-field-tag-list.js +3 -2
  34. package/dist/esm/tag-field/tag-field.js +4 -3
  35. package/dist/types/button/button.d.ts +5 -0
  36. package/dist/types/button/button.d.ts.map +1 -1
  37. package/dist/types/calendar/calendar-base.d.ts +14 -0
  38. package/dist/types/calendar/calendar-base.d.ts.map +1 -0
  39. package/dist/types/calendar/calendar-style-context.d.ts +1032 -0
  40. package/dist/types/calendar/calendar-style-context.d.ts.map +1 -0
  41. package/dist/types/calendar/calendar.d.ts +5 -0
  42. package/dist/types/calendar/calendar.d.ts.map +1 -0
  43. package/dist/types/calendar/index.d.ts +6 -0
  44. package/dist/types/calendar/index.d.ts.map +1 -0
  45. package/dist/types/calendar/types.d.ts +58 -0
  46. package/dist/types/calendar/types.d.ts.map +1 -0
  47. package/dist/types/calendar/utils.d.ts +13 -0
  48. package/dist/types/calendar/utils.d.ts.map +1 -0
  49. package/dist/types/index.d.mts +1 -0
  50. package/dist/types/index.d.ts +1 -0
  51. package/dist/types/index.d.ts.map +1 -1
  52. package/dist/types/select/select-item.d.ts.map +1 -1
  53. package/dist/types/select/select.d.ts.map +1 -1
  54. package/dist/types/system/utils.d.ts.map +1 -1
  55. package/dist/types/tag-field/index.d.ts +1 -0
  56. package/dist/types/tag-field/index.d.ts.map +1 -1
  57. package/dist/types/tag-field/tag-field-item.d.ts +7 -0
  58. package/dist/types/tag-field/tag-field-item.d.ts.map +1 -0
  59. package/dist/types/tag-field/tag-field-list.d.ts +2 -6
  60. package/dist/types/tag-field/tag-field-list.d.ts.map +1 -1
  61. package/dist/types/tag-field/tag-field-state-context.d.ts +1 -2
  62. package/dist/types/tag-field/tag-field-state-context.d.ts.map +1 -1
  63. package/dist/types/tag-field/tag-field-tag-list.d.ts.map +1 -1
  64. package/dist/types/tag-field/tag-field.d.ts.map +1 -1
  65. package/dist/types/tag-field/types.d.ts +6 -4
  66. package/dist/types/tag-field/types.d.ts.map +1 -1
  67. package/package.json +8 -7
  68. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevrons-up-down.js +0 -17
@@ -8,8 +8,8 @@ var reactAriaComponents = require('react-aria-components');
8
8
  var ouiTheme = require('@opengovsg/oui-theme');
9
9
  var utils = require('../system/utils.cjs');
10
10
  var selectVariantContext = require('./select-variant-context.cjs');
11
- var chevronsUpDown = require('../node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevrons-up-down.cjs');
12
11
  var field = require('../field/field.cjs');
12
+ var chevronDown = require('../node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-down.cjs');
13
13
  var button = require('../button/button.cjs');
14
14
 
15
15
  const calculateEstimatedRowHeight = (size) => {
@@ -34,13 +34,13 @@ function Select({
34
34
  );
35
35
  const { items, children, listLayoutOptions, ...props } = _props;
36
36
  const styles = ouiTheme.selectStyles(variantProps);
37
- const layout = react.useMemo(() => {
38
- return new reactAriaComponents.ListLayout({
37
+ const layoutOptions = react.useMemo(() => {
38
+ return {
39
39
  estimatedRowHeight: calculateEstimatedRowHeight(
40
40
  variantProps.size ?? "md"
41
41
  ),
42
42
  ...listLayoutOptions
43
- });
43
+ };
44
44
  }, [listLayoutOptions, variantProps.size]);
45
45
  return /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Provider, { values: [[selectVariantContext.SelectVariantContext, variantProps]], children: /* @__PURE__ */ jsxRuntime.jsxs(
46
46
  reactAriaComponents.Select,
@@ -71,7 +71,14 @@ function Select({
71
71
  })
72
72
  }
73
73
  ),
74
- /* @__PURE__ */ jsxRuntime.jsx(chevronsUpDown.default, { className: "h-4 w-4" })
74
+ /* @__PURE__ */ jsxRuntime.jsx(
75
+ chevronDown.default,
76
+ {
77
+ className: styles.icon({
78
+ className: classNames?.icon
79
+ })
80
+ }
81
+ )
75
82
  ]
76
83
  }
77
84
  ),
@@ -83,9 +90,10 @@ function Select({
83
90
  children: description
84
91
  }
85
92
  ),
86
- /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Popover, { className: styles.popover({ className: classNames?.popover }), children: /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Virtualizer, { layout, children: /* @__PURE__ */ jsxRuntime.jsx(
93
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Popover, { className: styles.popover({ className: classNames?.popover }), children: /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Virtualizer, { layout: reactAriaComponents.ListLayout, layoutOptions, children: /* @__PURE__ */ jsxRuntime.jsx(
87
94
  reactAriaComponents.ListBox,
88
95
  {
96
+ autoFocus: true,
89
97
  items,
90
98
  shouldFocusWrap: true,
91
99
  className: ouiTheme.composeRenderProps(
@@ -13,12 +13,15 @@ const mapPropsVariants = (props, variantKeys, removeVariantProps = true) => {
13
13
  if (!variantKeys) {
14
14
  return [props, {}];
15
15
  }
16
- const picked = variantKeys.reduce((acc, key) => {
17
- if (key in props) {
18
- return { ...acc, [key]: props[key] };
19
- }
20
- return acc;
21
- }, {});
16
+ const picked = variantKeys.reduce(
17
+ (acc, key) => {
18
+ if (key in props) {
19
+ return { ...acc, [key]: props[key] };
20
+ }
21
+ return acc;
22
+ },
23
+ {}
24
+ );
22
25
  if (removeVariantProps) {
23
26
  const omitted = Object.keys(props).filter((key) => !variantKeys.includes(key)).reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});
24
27
  return [omitted, picked];
@@ -2,7 +2,9 @@
2
2
  'use strict';
3
3
 
4
4
  var tagField = require('./tag-field.cjs');
5
+ var tagFieldItem = require('./tag-field-item.cjs');
5
6
 
6
7
 
7
8
 
8
9
  exports.TagField = tagField.TagField;
10
+ exports.TagFieldItem = tagFieldItem.TagFieldItem;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ "use client";
3
+ 'use strict';
4
+
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var react = require('react');
7
+ var ouiTheme = require('@opengovsg/oui-theme');
8
+ var utils = require('../system/utils.cjs');
9
+ var tagFieldStateContext = require('./tag-field-state-context.cjs');
10
+
11
+ const TagFieldItemInner = ({ item, isHighlighted, classNames, ...itemProps }, ref) => {
12
+ const { itemToText, size } = react.useContext(tagFieldStateContext.TagFieldStateContext);
13
+ const styles = ouiTheme.tagFieldItemStyles({ size });
14
+ return /* @__PURE__ */ jsxRuntime.jsx(
15
+ "li",
16
+ {
17
+ ref,
18
+ ...itemProps,
19
+ className: styles.container({ className: classNames?.container }),
20
+ "data-rac": true,
21
+ "data-hovered": ouiTheme.dataAttr(isHighlighted),
22
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.label({ className: classNames?.label }), children: itemToText(item) })
23
+ }
24
+ );
25
+ };
26
+ const TagFieldItem = utils.forwardRefGeneric(TagFieldItemInner);
27
+
28
+ exports.TagFieldItem = TagFieldItem;
@@ -5,27 +5,11 @@
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var react = require('react');
7
7
  var reactAriaComponents = require('react-aria-components');
8
- var ouiTheme = require('@opengovsg/oui-theme');
9
8
  var utils = require('../system/utils.cjs');
9
+ var tagFieldItem = require('./tag-field-item.cjs');
10
10
  var tagFieldStateContext = require('./tag-field-state-context.cjs');
11
11
 
12
12
  const TagFieldListContext = react.createContext(null);
13
- const TagFieldListItemInner = ({ item, isHighlighted, classNames, ...itemProps }, ref) => {
14
- const { itemToText, size } = react.useContext(tagFieldStateContext.TagFieldStateContext);
15
- const styles = ouiTheme.tagFieldItemStyles({ size });
16
- return /* @__PURE__ */ jsxRuntime.jsx(
17
- "li",
18
- {
19
- ref,
20
- ...itemProps,
21
- className: styles.container({ className: classNames?.container }),
22
- "data-rac": true,
23
- "data-hovered": ouiTheme.dataAttr(isHighlighted),
24
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.label({ className: classNames?.label }), children: itemToText(item) })
25
- }
26
- );
27
- };
28
- const TagFieldListItem = utils.forwardRefGeneric(TagFieldListItemInner);
29
13
  const TagFieldListInner = (props, ref) => {
30
14
  [props, ref] = reactAriaComponents.useContextProps(props, ref, TagFieldListContext);
31
15
  const { items, getItemProps, highlightedIndex } = react.useContext(tagFieldStateContext.TagFieldStateContext);
@@ -57,13 +41,19 @@ const TagFieldListInner = (props, ref) => {
57
41
  item,
58
42
  isHighlighted: highlightedIndex === virtualRow.index,
59
43
  key: virtualRow.key,
60
- itemClassNames,
61
- ...itemProps
44
+ classNames: itemClassNames
62
45
  };
63
46
  if (typeof props.children === "function") {
64
- return props.children(childProps);
47
+ return props.children({ ...childProps, itemProps });
65
48
  }
66
- return /* @__PURE__ */ react.createElement(TagFieldListItem, { ...childProps, key: childProps.key });
49
+ return /* @__PURE__ */ react.createElement(
50
+ tagFieldItem.TagFieldItem,
51
+ {
52
+ ...childProps,
53
+ ...itemProps,
54
+ key: childProps.key
55
+ }
56
+ );
67
57
  })
68
58
  ] }) });
69
59
  };
@@ -71,4 +61,3 @@ const TagFieldList = utils.forwardRefGeneric(TagFieldListInner);
71
61
 
72
62
  exports.TagFieldList = TagFieldList;
73
63
  exports.TagFieldListContext = TagFieldListContext;
74
- exports.TagFieldListItem = TagFieldListItem;
@@ -15,7 +15,8 @@ const TagFieldTagList = ({
15
15
  getSelectedItemProps,
16
16
  removeSelectedItem,
17
17
  isDisabled,
18
- isReadOnly
18
+ isReadOnly,
19
+ itemToText
19
20
  } = react.useContext(tagFieldStateContext.TagFieldStateContext);
20
21
  const handleRemoveSelectedItem = react.useCallback(
21
22
  (item) => () => {
@@ -49,7 +50,7 @@ const TagFieldTagList = ({
49
50
  className: classNames?.tag,
50
51
  ...itemProps,
51
52
  children: [
52
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.tagText, children: selectedItem.textValue }),
53
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.tagText, children: itemToText(selectedItem) }),
53
54
  /* @__PURE__ */ jsxRuntime.jsx(
54
55
  x.default,
55
56
  {
@@ -6,13 +6,14 @@ var jsxRuntime = require('react/jsx-runtime');
6
6
  var react = require('react');
7
7
  var reactAriaComponents = require('react-aria-components');
8
8
  var ouiTheme = require('@opengovsg/oui-theme');
9
- var input = require('../input/input.cjs');
9
+ var tagFieldItem = require('./tag-field-item.cjs');
10
10
  var tagFieldList = require('./tag-field-list.cjs');
11
11
  var tagFieldRoot = require('./tag-field-root.cjs');
12
12
  var tagFieldTagList = require('./tag-field-tag-list.cjs');
13
13
  var tagFieldTrigger = require('./tag-field-trigger.cjs');
14
14
  var chevronDown = require('../node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-down.cjs');
15
15
  var field = require('../field/field.cjs');
16
+ var input = require('../input/input.cjs');
16
17
 
17
18
  function TagField({
18
19
  classNames,
@@ -97,7 +98,7 @@ function TagField({
97
98
  {
98
99
  className: styles.list({ className: classNames?.list }),
99
100
  itemClassNames: props.itemClassNames,
100
- children: ({ key, ...props2 }) => children ? children({ key, ...props2 }) : /* @__PURE__ */ react.createElement(tagFieldList.TagFieldListItem, { ...props2, key })
101
+ children: ({ key, itemProps, ...props2 }) => children ? children({ key, itemProps, ...props2 }) : /* @__PURE__ */ react.createElement(tagFieldItem.TagFieldItem, { ...props2, ...itemProps, key })
101
102
  }
102
103
  ) })
103
104
  ] });
@@ -0,0 +1,343 @@
1
+ "use strict";
2
+ "use client";
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import { useMemo, useContext } from 'react';
5
+ import { today, getLocalTimeZone, CalendarDate } from '@internationalized/date';
6
+ import { useMessageFormatter, useDateFormatter } from 'react-aria';
7
+ import { Calendar, composeRenderProps, CalendarGrid, CalendarGridBody, CalendarCell, useLocale, CalendarStateContext, Group, Heading, CalendarGridHeader as CalendarGridHeader$1, CalendarHeaderCell } from 'react-aria-components';
8
+ import { cn } from '@opengovsg/oui-theme';
9
+ import { Button } from '../button/button.js';
10
+ import { useCalendarStyleContext } from './calendar-style-context.js';
11
+ import { useLocalizedMonthYear, useGenerateLocalizedMonths, useGenerateLocalizedYears } from './utils.js';
12
+ import ChevronRight from '../node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-right.js';
13
+ import ChevronLeft from '../node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-left.js';
14
+ import { Select } from '../select/select.js';
15
+ import { SelectItem } from '../select/select-item.js';
16
+
17
+ const useCalendarSelectors = (state) => {
18
+ const yearRange = useMemo(() => {
19
+ const start = state.minValue.year ?? 1900;
20
+ const end = state.maxValue.year ?? 2100;
21
+ return { start, end };
22
+ }, [state.maxValue, state.minValue]);
23
+ const dateFormatter = useDateFormatter(state);
24
+ const datePartOrder = useMemo(() => {
25
+ const parts = dateFormatter.formatToParts(
26
+ state.visibleRange.start.toDate(state.timeZone)
27
+ );
28
+ const filteredParts = parts.filter(
29
+ (part) => ["year", "month"].includes(part.type)
30
+ );
31
+ const filteredPartNames = filteredParts.map((part) => part.type);
32
+ return filteredPartNames;
33
+ }, [dateFormatter, state.timeZone, state.visibleRange.start]);
34
+ const months = useGenerateLocalizedMonths(state.timeZone);
35
+ const years = useGenerateLocalizedYears(
36
+ yearRange.start,
37
+ yearRange.end,
38
+ state.timeZone
39
+ );
40
+ return useMemo(() => {
41
+ return {
42
+ months,
43
+ years,
44
+ datePartOrder
45
+ };
46
+ }, [datePartOrder, months, years]);
47
+ };
48
+ const i18nStrings = {
49
+ "en-SG": {
50
+ selectMonth: "Select month",
51
+ selectYear: "Select year",
52
+ today: "Today"
53
+ },
54
+ "zh-SG": {
55
+ selectMonth: "\u9009\u62E9\u6708\u4EFD",
56
+ selectYear: "\u9009\u62E9\u5E74\u4EFD",
57
+ today: "\u4ECA\u5929"
58
+ },
59
+ "ms-SG": {
60
+ selectMonth: "Pilih bulan",
61
+ selectYear: "Pilih tahun",
62
+ today: "Hari ini"
63
+ },
64
+ "ta-SG": {
65
+ selectMonth: "\u0BAE\u0BBE\u0BA4\u0BA4\u0BCD\u0BA4\u0BC8 \u0BA4\u0BC7\u0BB0\u0BCD\u0BA8\u0BCD\u0BA4\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD",
66
+ selectYear: "\u0B86\u0BA3\u0BCD\u0B9F\u0BC8 \u0BA4\u0BC7\u0BB0\u0BCD\u0BA8\u0BCD\u0BA4\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD",
67
+ today: "\u0B87\u0BA9\u0BCD\u0BB1\u0BC1"
68
+ }
69
+ };
70
+ const CalendarBottomContent = ({
71
+ bottomContent,
72
+ showTodayButton
73
+ }) => {
74
+ const state = useContext(CalendarStateContext);
75
+ const { slots, classNames, size } = useCalendarStyleContext();
76
+ const formatMessage = useMessageFormatter(i18nStrings);
77
+ if (bottomContent) {
78
+ return bottomContent;
79
+ }
80
+ if (!showTodayButton) {
81
+ return null;
82
+ }
83
+ return /* @__PURE__ */ jsx(
84
+ "div",
85
+ {
86
+ className: slots.bottomContentWrapper({
87
+ className: classNames?.bottomContentWrapper
88
+ }),
89
+ children: /* @__PURE__ */ jsx(
90
+ Button,
91
+ {
92
+ isDisabled: state.isDisabled,
93
+ variant: "clear",
94
+ color: "sub",
95
+ size,
96
+ slot: null,
97
+ className: slots.todayButton({ className: classNames?.todayButton }),
98
+ onPress: () => {
99
+ state.setFocusedDate(today(getLocalTimeZone()));
100
+ },
101
+ children: formatMessage("today")
102
+ }
103
+ )
104
+ }
105
+ );
106
+ };
107
+ function CalendarBase({
108
+ weekdayStyle = "narrow",
109
+ calendarRef,
110
+ minValue = new CalendarDate(1900, 0, 1),
111
+ maxValue = new CalendarDate(2100, 12, 31),
112
+ bottomContent,
113
+ showTodayButton = true,
114
+ ...props
115
+ }) {
116
+ const { slots, className, classNames } = useCalendarStyleContext();
117
+ const numberOfVisibleMonths = props.visibleDuration?.months ?? 1;
118
+ const dateToHighlight = useMemo(() => {
119
+ return props.defaultFocusedValue ?? today(getLocalTimeZone());
120
+ }, [props.defaultFocusedValue]);
121
+ return /* @__PURE__ */ jsxs(
122
+ Calendar,
123
+ {
124
+ pageBehavior: "single",
125
+ ...props,
126
+ ref: calendarRef,
127
+ minValue,
128
+ maxValue,
129
+ className: composeRenderProps(
130
+ className,
131
+ (className2, renderProps) => slots.base({
132
+ className: cn(classNames?.base, className2),
133
+ ...renderProps
134
+ })
135
+ ),
136
+ children: [
137
+ /* @__PURE__ */ jsx(
138
+ "div",
139
+ {
140
+ className: slots.gridWrapper({
141
+ className: classNames?.gridWrapper
142
+ }),
143
+ children: Array.from({ length: numberOfVisibleMonths }).map((_, index) => /* @__PURE__ */ jsxs(
144
+ "div",
145
+ {
146
+ className: slots.calendar({ className: classNames?.calendar }),
147
+ children: [
148
+ /* @__PURE__ */ jsx(CalendarHeader, { offsetMonths: index }),
149
+ /* @__PURE__ */ jsxs(
150
+ CalendarGrid,
151
+ {
152
+ className: slots.grid({ className: classNames?.grid }),
153
+ weekdayStyle,
154
+ offset: { months: index },
155
+ children: [
156
+ /* @__PURE__ */ jsx(CalendarGridHeader, {}),
157
+ /* @__PURE__ */ jsx(
158
+ CalendarGridBody,
159
+ {
160
+ className: slots.gridBody({ className: classNames?.gridBody }),
161
+ children: (date) => /* @__PURE__ */ jsx(
162
+ CalendarCell,
163
+ {
164
+ className: composeRenderProps(
165
+ classNames?.cell,
166
+ (className2, renderProps) => slots.cell({
167
+ className: className2,
168
+ isMultipleMonths: numberOfVisibleMonths >= 2,
169
+ isDateHighlighted: date.compare(dateToHighlight) === 0,
170
+ ...renderProps
171
+ })
172
+ ),
173
+ date
174
+ }
175
+ )
176
+ }
177
+ )
178
+ ]
179
+ }
180
+ )
181
+ ]
182
+ },
183
+ index
184
+ ))
185
+ }
186
+ ),
187
+ /* @__PURE__ */ jsx(
188
+ CalendarBottomContent,
189
+ {
190
+ bottomContent,
191
+ showTodayButton
192
+ }
193
+ )
194
+ ]
195
+ }
196
+ );
197
+ }
198
+ const CalendarMonthDaySelector = () => {
199
+ const { slots, size, classNames } = useCalendarStyleContext();
200
+ const state = useContext(CalendarStateContext);
201
+ const { months, years, datePartOrder } = useCalendarSelectors(state);
202
+ const formatMessage = useMessageFormatter(i18nStrings);
203
+ return /* @__PURE__ */ jsx(Group, { className: slots.selectors({ className: classNames?.selectors }), children: datePartOrder.map((part) => {
204
+ if (part === "month") {
205
+ return /* @__PURE__ */ jsx(
206
+ Select,
207
+ {
208
+ isDisabled: state.isDisabled,
209
+ size,
210
+ items: months,
211
+ variant: "clear",
212
+ classNames: {
213
+ trigger: slots.monthSelector({
214
+ className: classNames?.monthSelector
215
+ }),
216
+ list: slots.monthList({ className: classNames?.monthList }),
217
+ selectedText: slots.selectorText({
218
+ className: classNames?.selectorText
219
+ }),
220
+ popover: "min-w-[12ch]"
221
+ },
222
+ selectedKey: state.visibleRange.start.month,
223
+ "aria-label": formatMessage("selectMonth"),
224
+ onSelectionChange: (month) => {
225
+ state.setFocusedDate(
226
+ new CalendarDate(state.focusedDate.year, Number(month), 1)
227
+ );
228
+ },
229
+ children: (month) => /* @__PURE__ */ jsx(SelectItem, { children: month.textValue })
230
+ },
231
+ part
232
+ );
233
+ }
234
+ return /* @__PURE__ */ jsx(
235
+ Select,
236
+ {
237
+ isDisabled: state.isDisabled,
238
+ size,
239
+ variant: "clear",
240
+ items: years,
241
+ classNames: {
242
+ trigger: slots.yearSelector({
243
+ className: classNames?.yearSelector
244
+ }),
245
+ list: slots.yearList({ className: classNames?.yearList }),
246
+ selectedText: slots.selectorText({
247
+ className: classNames?.selectorText
248
+ })
249
+ },
250
+ selectedKey: state.visibleRange.start.year,
251
+ "aria-label": formatMessage("selectYear"),
252
+ onSelectionChange: (year) => {
253
+ state.setFocusedDate(
254
+ new CalendarDate(
255
+ Number(year),
256
+ state.focusedDate.month,
257
+ state.focusedDate.day
258
+ )
259
+ );
260
+ },
261
+ children: (year) => /* @__PURE__ */ jsx(SelectItem, { children: year.textValue })
262
+ },
263
+ part
264
+ );
265
+ }) });
266
+ };
267
+ function CalendarHeader({ offsetMonths = 0 }) {
268
+ const { direction } = useLocale();
269
+ const { slots, classNames, size } = useCalendarStyleContext();
270
+ const state = useContext(CalendarStateContext);
271
+ const monthYearTitle = useLocalizedMonthYear(
272
+ state.visibleRange.start.add({ months: offsetMonths }),
273
+ state.timeZone
274
+ );
275
+ if (offsetMonths === 0) {
276
+ return /* @__PURE__ */ jsxs("div", { className: slots.header({ className: classNames?.header }), children: [
277
+ /* @__PURE__ */ jsx(CalendarMonthDaySelector, {}),
278
+ /* @__PURE__ */ jsxs(
279
+ Group,
280
+ {
281
+ className: slots.buttonGroup({ className: classNames?.buttonGroup }),
282
+ children: [
283
+ /* @__PURE__ */ jsx(
284
+ Button,
285
+ {
286
+ size,
287
+ isIconOnly: true,
288
+ variant: "clear",
289
+ color: "sub",
290
+ slot: "previous",
291
+ className: slots.prevButton({ className: classNames?.prevButton }),
292
+ children: direction === "rtl" ? /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": true })
293
+ }
294
+ ),
295
+ /* @__PURE__ */ jsx(
296
+ Button,
297
+ {
298
+ size,
299
+ variant: "clear",
300
+ color: "sub",
301
+ isIconOnly: true,
302
+ slot: "next",
303
+ className: slots.nextButton({
304
+ className: classNames?.nextButton
305
+ }),
306
+ children: direction === "rtl" ? /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true })
307
+ }
308
+ )
309
+ ]
310
+ }
311
+ )
312
+ ] });
313
+ }
314
+ return /* @__PURE__ */ jsx(
315
+ Heading,
316
+ {
317
+ className: slots.header({ className: classNames?.header }),
318
+ "aria-hidden": true,
319
+ level: 2,
320
+ children: monthYearTitle
321
+ }
322
+ );
323
+ }
324
+ function CalendarGridHeader() {
325
+ const { slots, classNames } = useCalendarStyleContext();
326
+ return /* @__PURE__ */ jsx(
327
+ CalendarGridHeader$1,
328
+ {
329
+ className: slots.gridHeader({ className: classNames?.gridHeader }),
330
+ children: (day) => /* @__PURE__ */ jsx(
331
+ CalendarHeaderCell,
332
+ {
333
+ className: slots.gridHeaderCell({
334
+ className: classNames?.gridHeaderCell
335
+ }),
336
+ children: day
337
+ }
338
+ )
339
+ }
340
+ );
341
+ }
342
+
343
+ export { CalendarBase, CalendarGridHeader, CalendarHeader };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ "use client";
3
+ import { useDeepCompareMemo } from 'use-deep-compare';
4
+ import { calendarStyles } from '@opengovsg/oui-theme';
5
+ import { mapPropsVariants } from '../system/utils.js';
6
+ import { createContext } from '../system/react-utils/context.js';
7
+
8
+ function useProvideCalendarStyles(originalProps) {
9
+ const [props, variantProps] = mapPropsVariants(
10
+ originalProps,
11
+ calendarStyles.variantKeys
12
+ );
13
+ const { errorMessage, className, classNames, ...restProps } = props;
14
+ const slots = useDeepCompareMemo(
15
+ () => calendarStyles(variantProps),
16
+ [variantProps]
17
+ );
18
+ return {
19
+ context: {
20
+ slots,
21
+ classNames,
22
+ className,
23
+ size: variantProps.size ?? calendarStyles.defaultVariants.size,
24
+ errorMessage
25
+ },
26
+ calendarProps: { ...restProps, onChange: restProps.onChange }
27
+ };
28
+ }
29
+ const [CalendarStyleContext, useCalendarStyleContext] = createContext({
30
+ name: "CalendarStyleContext",
31
+ strict: true
32
+ });
33
+
34
+ export { CalendarStyleContext, useCalendarStyleContext, useProvideCalendarStyles };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ "use client";
3
+ import { jsx } from 'react/jsx-runtime';
4
+ import { Provider } from 'react-aria-components';
5
+ import { forwardRef } from '../system/utils.js';
6
+ import { CalendarBase } from './calendar-base.js';
7
+ import { useProvideCalendarStyles, CalendarStyleContext } from './calendar-style-context.js';
8
+
9
+ const Calendar = forwardRef(function Calendar2(props, ref) {
10
+ const { calendarProps, context } = useProvideCalendarStyles(props);
11
+ return /* @__PURE__ */ jsx(Provider, { values: [[CalendarStyleContext, context]], children: /* @__PURE__ */ jsx(CalendarBase, { calendarRef: ref, ...calendarProps }) });
12
+ });
13
+
14
+ export { Calendar };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ export { Calendar } from './calendar.js';
3
+ export { CalendarStyleContext, useCalendarStyleContext, useProvideCalendarStyles } from './calendar-style-context.js';
4
+ export { getEraFormat, useGenerateLocalizedMonths, useGenerateLocalizedYears, useLocalizedMonthYear } from './utils.js';
5
+ export { CalendarDate } from '@internationalized/date';
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ import { useMemo } from 'react';
3
+ import { CalendarDate } from '@internationalized/date';
4
+ import { useDateFormatter } from '@react-aria/i18n';
5
+
6
+ function getEraFormat(date) {
7
+ return date?.calendar.identifier === "gregory" && date.era === "BC" ? "short" : void 0;
8
+ }
9
+ function useLocalizedMonthYear(date, timeZone) {
10
+ const era = getEraFormat(date);
11
+ const monthFormatter = useDateFormatter({
12
+ month: "long",
13
+ year: "numeric",
14
+ era,
15
+ calendar: date.calendar.identifier,
16
+ timeZone
17
+ });
18
+ return monthFormatter.format(date.toDate(timeZone));
19
+ }
20
+ function useGenerateLocalizedMonths(timeZone, formatterOptions) {
21
+ const formatter = useDateFormatter({
22
+ month: "long",
23
+ timeZone,
24
+ ...formatterOptions
25
+ });
26
+ return useMemo(() => {
27
+ return Array.from({ length: 12 }, (_, i) => {
28
+ const id = i + 1;
29
+ return {
30
+ id,
31
+ textValue: formatter.format(
32
+ new CalendarDate(2020, id, 1).toDate(timeZone)
33
+ )
34
+ };
35
+ });
36
+ }, [formatter, timeZone]);
37
+ }
38
+ function useGenerateLocalizedYears(yearStart, yearEnd, timeZone, formatterOptions) {
39
+ const formatter = useDateFormatter({
40
+ year: "numeric",
41
+ timeZone,
42
+ ...formatterOptions
43
+ });
44
+ return useMemo(() => {
45
+ return Array.from({ length: yearEnd - yearStart + 1 }, (_, i) => {
46
+ const year = yearStart + i;
47
+ return {
48
+ id: year,
49
+ textValue: formatter.format(
50
+ new CalendarDate(year, 1, 1).toDate(timeZone)
51
+ )
52
+ };
53
+ });
54
+ }, [formatter, yearStart, yearEnd, timeZone]);
55
+ }
56
+
57
+ export { getEraFormat, useGenerateLocalizedMonths, useGenerateLocalizedYears, useLocalizedMonthYear };