@opengovsg/oui 0.0.0-snapshot-20250311073924

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 (215) hide show
  1. package/LICENSE.md +13 -0
  2. package/dist/cjs/banner/banner.cjs +118 -0
  3. package/dist/cjs/banner/index.cjs +8 -0
  4. package/dist/cjs/button/button.cjs +86 -0
  5. package/dist/cjs/button/index.cjs +8 -0
  6. package/dist/cjs/combo-box/combo-box-fuzzy.cjs +107 -0
  7. package/dist/cjs/combo-box/combo-box.cjs +277 -0
  8. package/dist/cjs/combo-box/index.cjs +12 -0
  9. package/dist/cjs/field/field.cjs +63 -0
  10. package/dist/cjs/field/index.cjs +11 -0
  11. package/dist/cjs/govt-banner/govt-banner.cjs +259 -0
  12. package/dist/cjs/govt-banner/index.cjs +8 -0
  13. package/dist/cjs/hooks/index.cjs +8 -0
  14. package/dist/cjs/hooks/use-callback-ref.cjs +17 -0
  15. package/dist/cjs/hooks/use-controllable-state.cjs +37 -0
  16. package/dist/cjs/index.cjs +47 -0
  17. package/dist/cjs/input/index.cjs +8 -0
  18. package/dist/cjs/input/input.cjs +28 -0
  19. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/Icon.cjs +48 -0
  20. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/createLucideIcon.cjs +30 -0
  21. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/defaultAttributes.cjs +24 -0
  22. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-down.cjs +19 -0
  23. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-up.cjs +19 -0
  24. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/circle-alert.cjs +23 -0
  25. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/external-link.cjs +23 -0
  26. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/info.cjs +23 -0
  27. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/landmark.cjs +26 -0
  28. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/lock.cjs +22 -0
  29. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/x.cjs +22 -0
  30. package/dist/cjs/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/shared/src/utils.cjs +16 -0
  31. package/dist/cjs/ripple/index.cjs +10 -0
  32. package/dist/cjs/ripple/ripple.cjs +70 -0
  33. package/dist/cjs/ripple/use-ripple.cjs +29 -0
  34. package/dist/cjs/skip-nav-link/index.cjs +8 -0
  35. package/dist/cjs/skip-nav-link/skip-nav-link.cjs +18 -0
  36. package/dist/cjs/spinner/index.cjs +10 -0
  37. package/dist/cjs/spinner/spinner.cjs +17 -0
  38. package/dist/cjs/spinner/use-spinner.cjs +38 -0
  39. package/dist/cjs/system/react-utils/context.cjs +31 -0
  40. package/dist/cjs/system/react-utils/index.cjs +8 -0
  41. package/dist/cjs/system/types.cjs +3 -0
  42. package/dist/cjs/system/utils.cjs +101 -0
  43. package/dist/cjs/tag-field/index.cjs +8 -0
  44. package/dist/cjs/tag-field/tag-field-list.cjs +73 -0
  45. package/dist/cjs/tag-field/tag-field-root.cjs +184 -0
  46. package/dist/cjs/tag-field/tag-field-state-context.cjs +11 -0
  47. package/dist/cjs/tag-field/tag-field-tag-list.cjs +70 -0
  48. package/dist/cjs/tag-field/tag-field-trigger.cjs +27 -0
  49. package/dist/cjs/tag-field/tag-field.cjs +106 -0
  50. package/dist/cjs/tag-field/types.cjs +3 -0
  51. package/dist/cjs/tag-field/use-tag-field-state.cjs +103 -0
  52. package/dist/cjs/tag-field/use-tag-field.cjs +188 -0
  53. package/dist/cjs/text-area/index.cjs +8 -0
  54. package/dist/cjs/text-area/text-area.cjs +28 -0
  55. package/dist/cjs/text-area-field/index.cjs +8 -0
  56. package/dist/cjs/text-area-field/text-area-field.cjs +48 -0
  57. package/dist/cjs/text-field/index.cjs +8 -0
  58. package/dist/cjs/text-field/text-field.cjs +48 -0
  59. package/dist/cjs/toggle/index.cjs +8 -0
  60. package/dist/cjs/toggle/toggle.cjs +48 -0
  61. package/dist/esm/banner/banner.js +116 -0
  62. package/dist/esm/banner/index.js +2 -0
  63. package/dist/esm/button/button.js +84 -0
  64. package/dist/esm/button/index.js +2 -0
  65. package/dist/esm/combo-box/combo-box-fuzzy.js +105 -0
  66. package/dist/esm/combo-box/combo-box.js +273 -0
  67. package/dist/esm/combo-box/index.js +3 -0
  68. package/dist/esm/field/field.js +58 -0
  69. package/dist/esm/field/index.js +2 -0
  70. package/dist/esm/govt-banner/govt-banner.js +257 -0
  71. package/dist/esm/govt-banner/index.js +2 -0
  72. package/dist/esm/hooks/index.js +2 -0
  73. package/dist/esm/hooks/use-callback-ref.js +15 -0
  74. package/dist/esm/hooks/use-controllable-state.js +35 -0
  75. package/dist/esm/index.js +19 -0
  76. package/dist/esm/input/index.js +2 -0
  77. package/dist/esm/input/input.js +26 -0
  78. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/Icon.js +44 -0
  79. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/createLucideIcon.js +26 -0
  80. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/defaultAttributes.js +20 -0
  81. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-down.js +14 -0
  82. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/chevron-up.js +14 -0
  83. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/circle-alert.js +18 -0
  84. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/external-link.js +18 -0
  85. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/info.js +18 -0
  86. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/landmark.js +21 -0
  87. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/lock.js +17 -0
  88. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/x.js +17 -0
  89. package/dist/esm/node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/shared/src/utils.js +13 -0
  90. package/dist/esm/ripple/index.js +3 -0
  91. package/dist/esm/ripple/ripple.js +49 -0
  92. package/dist/esm/ripple/use-ripple.js +27 -0
  93. package/dist/esm/skip-nav-link/index.js +2 -0
  94. package/dist/esm/skip-nav-link/skip-nav-link.js +16 -0
  95. package/dist/esm/spinner/index.js +3 -0
  96. package/dist/esm/spinner/spinner.js +15 -0
  97. package/dist/esm/spinner/use-spinner.js +36 -0
  98. package/dist/esm/system/react-utils/context.js +29 -0
  99. package/dist/esm/system/react-utils/index.js +2 -0
  100. package/dist/esm/system/types.js +1 -0
  101. package/dist/esm/system/utils.js +94 -0
  102. package/dist/esm/tag-field/index.js +2 -0
  103. package/dist/esm/tag-field/tag-field-list.js +69 -0
  104. package/dist/esm/tag-field/tag-field-root.js +182 -0
  105. package/dist/esm/tag-field/tag-field-state-context.js +9 -0
  106. package/dist/esm/tag-field/tag-field-tag-list.js +68 -0
  107. package/dist/esm/tag-field/tag-field-trigger.js +24 -0
  108. package/dist/esm/tag-field/tag-field.js +104 -0
  109. package/dist/esm/tag-field/types.js +1 -0
  110. package/dist/esm/tag-field/use-tag-field-state.js +101 -0
  111. package/dist/esm/tag-field/use-tag-field.js +186 -0
  112. package/dist/esm/text-area/index.js +2 -0
  113. package/dist/esm/text-area/text-area.js +26 -0
  114. package/dist/esm/text-area-field/index.js +2 -0
  115. package/dist/esm/text-area-field/text-area-field.js +46 -0
  116. package/dist/esm/text-field/index.js +2 -0
  117. package/dist/esm/text-field/text-field.js +46 -0
  118. package/dist/esm/toggle/index.js +2 -0
  119. package/dist/esm/toggle/toggle.js +46 -0
  120. package/dist/types/banner/banner.d.ts +19 -0
  121. package/dist/types/banner/banner.d.ts.map +1 -0
  122. package/dist/types/banner/index.d.ts +2 -0
  123. package/dist/types/banner/index.d.ts.map +1 -0
  124. package/dist/types/button/button.d.ts +48 -0
  125. package/dist/types/button/button.d.ts.map +1 -0
  126. package/dist/types/button/index.d.ts +2 -0
  127. package/dist/types/button/index.d.ts.map +1 -0
  128. package/dist/types/combo-box/combo-box-fuzzy.d.ts +11 -0
  129. package/dist/types/combo-box/combo-box-fuzzy.d.ts.map +1 -0
  130. package/dist/types/combo-box/combo-box.d.ts +50 -0
  131. package/dist/types/combo-box/combo-box.d.ts.map +1 -0
  132. package/dist/types/combo-box/index.d.ts +3 -0
  133. package/dist/types/combo-box/index.d.ts.map +1 -0
  134. package/dist/types/field/field.d.ts +14 -0
  135. package/dist/types/field/field.d.ts.map +1 -0
  136. package/dist/types/field/index.d.ts +2 -0
  137. package/dist/types/field/index.d.ts.map +1 -0
  138. package/dist/types/govt-banner/govt-banner.d.ts +39 -0
  139. package/dist/types/govt-banner/govt-banner.d.ts.map +1 -0
  140. package/dist/types/govt-banner/index.d.ts +2 -0
  141. package/dist/types/govt-banner/index.d.ts.map +1 -0
  142. package/dist/types/hooks/index.d.ts +2 -0
  143. package/dist/types/hooks/index.d.ts.map +1 -0
  144. package/dist/types/hooks/use-callback-ref.d.ts +6 -0
  145. package/dist/types/hooks/use-callback-ref.d.ts.map +1 -0
  146. package/dist/types/hooks/use-controllable-state.d.ts +11 -0
  147. package/dist/types/hooks/use-controllable-state.d.ts.map +1 -0
  148. package/dist/types/index.d.mts +16 -0
  149. package/dist/types/index.d.ts +16 -0
  150. package/dist/types/index.d.ts.map +1 -0
  151. package/dist/types/input/index.d.ts +2 -0
  152. package/dist/types/input/index.d.ts.map +1 -0
  153. package/dist/types/input/input.d.ts +9 -0
  154. package/dist/types/input/input.d.ts.map +1 -0
  155. package/dist/types/ripple/index.d.ts +3 -0
  156. package/dist/types/ripple/index.d.ts.map +1 -0
  157. package/dist/types/ripple/ripple.d.ts +10 -0
  158. package/dist/types/ripple/ripple.d.ts.map +1 -0
  159. package/dist/types/ripple/use-ripple.d.ts +15 -0
  160. package/dist/types/ripple/use-ripple.d.ts.map +1 -0
  161. package/dist/types/skip-nav-link/index.d.ts +2 -0
  162. package/dist/types/skip-nav-link/index.d.ts.map +1 -0
  163. package/dist/types/skip-nav-link/skip-nav-link.d.ts +11 -0
  164. package/dist/types/skip-nav-link/skip-nav-link.d.ts.map +1 -0
  165. package/dist/types/spinner/index.d.ts +3 -0
  166. package/dist/types/spinner/index.d.ts.map +1 -0
  167. package/dist/types/spinner/spinner.d.ts +4 -0
  168. package/dist/types/spinner/spinner.d.ts.map +1 -0
  169. package/dist/types/spinner/use-spinner.d.ts +66 -0
  170. package/dist/types/spinner/use-spinner.d.ts.map +1 -0
  171. package/dist/types/system/react-utils/context.d.ts +27 -0
  172. package/dist/types/system/react-utils/context.d.ts.map +1 -0
  173. package/dist/types/system/react-utils/index.d.ts +2 -0
  174. package/dist/types/system/react-utils/index.d.ts.map +1 -0
  175. package/dist/types/system/types.d.ts +63 -0
  176. package/dist/types/system/types.d.ts.map +1 -0
  177. package/dist/types/system/utils.d.ts +856 -0
  178. package/dist/types/system/utils.d.ts.map +1 -0
  179. package/dist/types/tag-field/index.d.ts +2 -0
  180. package/dist/types/tag-field/index.d.ts.map +1 -0
  181. package/dist/types/tag-field/tag-field-list.d.ts +22 -0
  182. package/dist/types/tag-field/tag-field-list.d.ts.map +1 -0
  183. package/dist/types/tag-field/tag-field-root.d.ts +14 -0
  184. package/dist/types/tag-field/tag-field-root.d.ts.map +1 -0
  185. package/dist/types/tag-field/tag-field-state-context.d.ts +12 -0
  186. package/dist/types/tag-field/tag-field-state-context.d.ts.map +1 -0
  187. package/dist/types/tag-field/tag-field-tag-list.d.ts +17 -0
  188. package/dist/types/tag-field/tag-field-tag-list.d.ts.map +1 -0
  189. package/dist/types/tag-field/tag-field-trigger.d.ts +8 -0
  190. package/dist/types/tag-field/tag-field-trigger.d.ts.map +1 -0
  191. package/dist/types/tag-field/tag-field.d.ts +3 -0
  192. package/dist/types/tag-field/tag-field.d.ts.map +1 -0
  193. package/dist/types/tag-field/types.d.ts +71 -0
  194. package/dist/types/tag-field/types.d.ts.map +1 -0
  195. package/dist/types/tag-field/use-tag-field-state.d.ts +35 -0
  196. package/dist/types/tag-field/use-tag-field-state.d.ts.map +1 -0
  197. package/dist/types/tag-field/use-tag-field.d.ts +48 -0
  198. package/dist/types/tag-field/use-tag-field.d.ts.map +1 -0
  199. package/dist/types/text-area/index.d.ts +2 -0
  200. package/dist/types/text-area/index.d.ts.map +1 -0
  201. package/dist/types/text-area/text-area.d.ts +9 -0
  202. package/dist/types/text-area/text-area.d.ts.map +1 -0
  203. package/dist/types/text-area-field/index.d.ts +2 -0
  204. package/dist/types/text-area-field/index.d.ts.map +1 -0
  205. package/dist/types/text-area-field/text-area-field.d.ts +12 -0
  206. package/dist/types/text-area-field/text-area-field.d.ts.map +1 -0
  207. package/dist/types/text-field/index.d.ts +2 -0
  208. package/dist/types/text-field/index.d.ts.map +1 -0
  209. package/dist/types/text-field/text-field.d.ts +12 -0
  210. package/dist/types/text-field/text-field.d.ts.map +1 -0
  211. package/dist/types/toggle/index.d.ts +2 -0
  212. package/dist/types/toggle/index.d.ts.map +1 -0
  213. package/dist/types/toggle/toggle.d.ts +22 -0
  214. package/dist/types/toggle/toggle.d.ts.map +1 -0
  215. package/package.json +93 -0
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var react = require('react');
6
+ var utils$1 = require('@react-aria/utils');
7
+ var lodashEs = require('lodash-es');
8
+ var reactAria = require('react-aria');
9
+ var reactAriaComponents = require('react-aria-components');
10
+ var utils = require('../system/utils.cjs');
11
+ var tagFieldList = require('./tag-field-list.cjs');
12
+ var tagFieldStateContext = require('./tag-field-state-context.cjs');
13
+ var tagFieldTrigger = require('./tag-field-trigger.cjs');
14
+ var useTagField = require('./use-tag-field.cjs');
15
+ var useTagFieldState = require('./use-tag-field-state.cjs');
16
+
17
+ const calculateEstimatedRowHeight = (size) => {
18
+ switch (size) {
19
+ case "xs":
20
+ return 44;
21
+ case "sm":
22
+ return 44;
23
+ case "md":
24
+ return 48;
25
+ }
26
+ };
27
+ function TagFieldRoot({
28
+ children,
29
+ virtualRowHeight: _virtualRowHeight,
30
+ ...props
31
+ }) {
32
+ const { itemToKey: defaultItemToKey, itemToText: defaultItemToText } = props;
33
+ const virtualRowHeight = react.useMemo(
34
+ () => _virtualRowHeight ?? calculateEstimatedRowHeight(props.size ?? "md"),
35
+ [_virtualRowHeight, props.size]
36
+ );
37
+ const { contains } = reactAria.useFilter({ sensitivity: "base" });
38
+ const itemToText = react.useCallback(
39
+ (item) => {
40
+ if (defaultItemToText) return defaultItemToText(item);
41
+ return String(lodashEs.get(item, "textValue") ?? String(item));
42
+ },
43
+ [defaultItemToText]
44
+ );
45
+ const itemToKey = react.useCallback(
46
+ (item) => {
47
+ if (defaultItemToKey) return defaultItemToKey(item);
48
+ return String(lodashEs.get(item, "id") ?? String(item));
49
+ },
50
+ [defaultItemToKey]
51
+ );
52
+ const onSelectionChange = react.useCallback(
53
+ (nextItems) => {
54
+ if (props.onSelectionChange) {
55
+ props.onSelectionChange(new Set(nextItems.map(itemToKey)));
56
+ }
57
+ },
58
+ [props, itemToKey]
59
+ );
60
+ const state = useTagFieldState.useTagFieldState({
61
+ ...props,
62
+ itemToKey,
63
+ itemToText,
64
+ onSelectionChange,
65
+ defaultFilter: props.defaultFilter || contains
66
+ });
67
+ const { validationBehavior: formValidationBehavior } = reactAriaComponents.useSlottedContext(reactAriaComponents.FormContext) || {};
68
+ props.validationBehavior ?? formValidationBehavior ?? "native";
69
+ const fieldRef = react.useRef(null);
70
+ const popoverRef = react.useRef(null);
71
+ const listBoxRef = react.useRef(null);
72
+ const labelRef = react.useRef(null);
73
+ const inputRef = react.useRef(null);
74
+ const buttonRef = react.useRef(null);
75
+ const {
76
+ tagFieldProps,
77
+ buttonProps,
78
+ inputProps,
79
+ labelProps,
80
+ listBoxProps,
81
+ descriptionProps,
82
+ errorMessageProps,
83
+ rowVirtualizer,
84
+ ...validation
85
+ } = useTagField.useTagField(
86
+ {
87
+ ...utils.removeDataAttributes(props),
88
+ virtualRowHeight,
89
+ itemToKey,
90
+ itemToText,
91
+ inputRef,
92
+ listBoxRef,
93
+ labelRef,
94
+ buttonRef},
95
+ state
96
+ );
97
+ const [menuWidth, setMenuWidth] = react.useState(null);
98
+ const onResize = react.useCallback(() => {
99
+ if (fieldRef.current) {
100
+ const fieldRect = fieldRef.current.getBoundingClientRect();
101
+ setMenuWidth(fieldRect.right - fieldRect.left + "px");
102
+ }
103
+ }, []);
104
+ utils$1.useResizeObserver({
105
+ ref: fieldRef,
106
+ onResize
107
+ });
108
+ const renderPropsState = react.useMemo(
109
+ () => ({
110
+ isOpen: tagFieldProps.isOpen,
111
+ isDisabled: props.isDisabled || false,
112
+ isInvalid: validation.isInvalid || false,
113
+ isRequired: props.isRequired || false
114
+ }),
115
+ [
116
+ tagFieldProps.isOpen,
117
+ props.isDisabled,
118
+ props.isRequired,
119
+ validation.isInvalid
120
+ ]
121
+ );
122
+ return /* @__PURE__ */ jsxRuntime.jsx(
123
+ reactAriaComponents.Provider,
124
+ {
125
+ values: [
126
+ [
127
+ tagFieldStateContext.TagFieldStateContext,
128
+ {
129
+ ...state,
130
+ ...tagFieldProps,
131
+ size: props.size,
132
+ variant: props.variant
133
+ }
134
+ ],
135
+ [reactAriaComponents.LabelContext, labelProps],
136
+ [tagFieldList.TagFieldListContext, { ...listBoxProps, rowVirtualizer }],
137
+ [tagFieldTrigger.TagFieldTriggerContext, buttonProps],
138
+ [
139
+ reactAriaComponents.PopoverContext,
140
+ {
141
+ ref: popoverRef,
142
+ triggerRef: fieldRef,
143
+ scrollRef: listBoxRef,
144
+ placement: "bottom start",
145
+ isOpen: tagFieldProps.isOpen,
146
+ isNonModal: true,
147
+ trigger: "TagField",
148
+ style: { "--trigger-width": menuWidth }
149
+ }
150
+ ],
151
+ [reactAriaComponents.InputContext, inputProps],
152
+ [
153
+ reactAriaComponents.TextContext,
154
+ {
155
+ slots: {
156
+ description: descriptionProps,
157
+ errorMessage: errorMessageProps
158
+ }
159
+ }
160
+ ],
161
+ [
162
+ reactAriaComponents.GroupContext,
163
+ {
164
+ isDisabled: props.isDisabled || false,
165
+ isInvalid: validation.isInvalid,
166
+ ref: fieldRef
167
+ }
168
+ ],
169
+ [reactAriaComponents.FieldErrorContext, validation]
170
+ ],
171
+ children: typeof children === "function" ? children({
172
+ ...renderPropsState,
173
+ defaultChildren: null,
174
+ items: state.items,
175
+ selectedItems: state.selectedItems,
176
+ highlightedIndex: tagFieldProps.highlightedIndex,
177
+ getSelectedItemProps: tagFieldProps.getSelectedItemProps,
178
+ removeSelectedItem: tagFieldProps.removeSelectedItem
179
+ }) : children
180
+ }
181
+ );
182
+ }
183
+
184
+ exports.TagFieldRoot = TagFieldRoot;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var react = require('react');
5
+
6
+ const TagFieldStateContext = (
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ react.createContext(null)
9
+ );
10
+
11
+ exports.TagFieldStateContext = TagFieldStateContext;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var react = require('react');
6
+ var tagFieldStateContext = require('./tag-field-state-context.cjs');
7
+ var x = require('../node_modules/.pnpm/lucide-react@0.475.0_react@19.0.0/node_modules/lucide-react/dist/esm/icons/x.cjs');
8
+
9
+ const TagFieldTagList = ({
10
+ classNames,
11
+ ...props
12
+ }) => {
13
+ const {
14
+ selectedItems,
15
+ getSelectedItemProps,
16
+ removeSelectedItem,
17
+ isDisabled,
18
+ isReadOnly
19
+ } = react.useContext(tagFieldStateContext.TagFieldStateContext);
20
+ const handleRemoveSelectedItem = react.useCallback(
21
+ (item) => () => {
22
+ if (isDisabled || isReadOnly) return;
23
+ removeSelectedItem(item);
24
+ },
25
+ [isDisabled, isReadOnly, removeSelectedItem]
26
+ );
27
+ if (props.children !== void 0 && typeof props.children !== "function") {
28
+ return props.children;
29
+ }
30
+ return selectedItems.map((selectedItem, index) => {
31
+ const itemProps = getSelectedItemProps({
32
+ disabled: isDisabled,
33
+ readOnly: isReadOnly,
34
+ selectedItem,
35
+ index
36
+ });
37
+ if (typeof props.children === "function") {
38
+ return props.children({
39
+ item: selectedItem,
40
+ removeSelectedItem: handleRemoveSelectedItem(selectedItem),
41
+ isDisabled,
42
+ isReadOnly,
43
+ itemProps
44
+ });
45
+ }
46
+ return /* @__PURE__ */ jsxRuntime.jsxs(
47
+ "span",
48
+ {
49
+ className: classNames?.tag,
50
+ ...itemProps,
51
+ children: [
52
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.tagText, children: selectedItem.textValue }),
53
+ /* @__PURE__ */ jsxRuntime.jsx(
54
+ x.default,
55
+ {
56
+ className: classNames?.tagIcon,
57
+ onClick: (e) => {
58
+ e.stopPropagation();
59
+ handleRemoveSelectedItem(selectedItem)();
60
+ }
61
+ }
62
+ )
63
+ ]
64
+ },
65
+ `selected-item-${index}`
66
+ );
67
+ });
68
+ };
69
+
70
+ exports.TagFieldTagList = TagFieldTagList;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var react = require('react');
6
+ var reactAriaComponents = require('react-aria-components');
7
+ var utils = require('../system/utils.cjs');
8
+
9
+ const TagFieldTriggerContext = react.createContext({});
10
+ const TagFieldTrigger = utils.forwardRef(
11
+ (props, ref) => {
12
+ [props, ref] = reactAriaComponents.useContextProps(props, ref, TagFieldTriggerContext);
13
+ return /* @__PURE__ */ jsxRuntime.jsx(
14
+ "button",
15
+ {
16
+ "aria-label": "toggle menu",
17
+ type: "button",
18
+ ...props,
19
+ slot: props.slot || void 0,
20
+ ref
21
+ }
22
+ );
23
+ }
24
+ );
25
+
26
+ exports.TagFieldTrigger = TagFieldTrigger;
27
+ exports.TagFieldTriggerContext = TagFieldTriggerContext;
@@ -0,0 +1,106 @@
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 reactAriaComponents = require('react-aria-components');
9
+ var tagFieldList = require('./tag-field-list.cjs');
10
+ var tagFieldRoot = require('./tag-field-root.cjs');
11
+ var tagFieldTagList = require('./tag-field-tag-list.cjs');
12
+ var tagFieldTrigger = require('./tag-field-trigger.cjs');
13
+ 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');
14
+ var field = require('../field/field.cjs');
15
+ var input = require('../input/input.cjs');
16
+
17
+ function TagField({
18
+ classNames,
19
+ children,
20
+ ...props
21
+ }) {
22
+ const styles = ouiTheme.tagFieldStyles(props);
23
+ return /* @__PURE__ */ jsxRuntime.jsxs(tagFieldRoot.TagFieldRoot, { ...props, children: [
24
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.root({ className: classNames?.root }), children: [
25
+ /* @__PURE__ */ jsxRuntime.jsx(
26
+ field.Label,
27
+ {
28
+ size: props.size,
29
+ className: styles.label({ className: classNames?.label }),
30
+ children: props.label
31
+ }
32
+ ),
33
+ /* @__PURE__ */ jsxRuntime.jsxs(
34
+ field.FieldGroup,
35
+ {
36
+ className: reactAriaComponents.composeRenderProps(
37
+ classNames?.group,
38
+ (className, renderProps) => styles.group({ className, ...renderProps })
39
+ ),
40
+ children: [
41
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-row flex-wrap gap-1", children: [
42
+ /* @__PURE__ */ jsxRuntime.jsx(
43
+ tagFieldTagList.TagFieldTagList,
44
+ {
45
+ classNames: {
46
+ tag: styles.tag({ className: classNames?.tag }),
47
+ tagText: styles.tagText({ className: classNames?.tagText }),
48
+ tagIcon: styles.tagIcon({ className: classNames?.tagIcon })
49
+ }
50
+ }
51
+ ),
52
+ /* @__PURE__ */ jsxRuntime.jsx(
53
+ input.Input,
54
+ {
55
+ variant: "unstyled",
56
+ size: props.size,
57
+ className: reactAriaComponents.composeRenderProps(
58
+ classNames?.field,
59
+ (className, renderProps) => styles.field({ className, ...renderProps })
60
+ )
61
+ }
62
+ )
63
+ ] }),
64
+ /* @__PURE__ */ jsxRuntime.jsx(
65
+ tagFieldTrigger.TagFieldTrigger,
66
+ {
67
+ className: styles.trigger({ className: classNames?.trigger }),
68
+ children: /* @__PURE__ */ jsxRuntime.jsx(chevronDown.default, {})
69
+ }
70
+ )
71
+ ]
72
+ }
73
+ ),
74
+ props.description && /* @__PURE__ */ jsxRuntime.jsx(
75
+ field.Description,
76
+ {
77
+ size: props.size,
78
+ className: styles.description({
79
+ className: classNames?.description
80
+ }),
81
+ children: props.description
82
+ }
83
+ ),
84
+ /* @__PURE__ */ jsxRuntime.jsx(
85
+ field.FieldError,
86
+ {
87
+ size: props.size,
88
+ className: styles.error({
89
+ className: classNames?.error
90
+ }),
91
+ children: props.errorMessage
92
+ }
93
+ )
94
+ ] }),
95
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Popover, { children: /* @__PURE__ */ jsxRuntime.jsx(
96
+ tagFieldList.TagFieldList,
97
+ {
98
+ className: styles.list({ className: classNames?.list }),
99
+ itemClassNames: props.itemClassNames,
100
+ children: ({ key, ...props2 }) => children ? children({ key, ...props2 }) : /* @__PURE__ */ react.createElement(tagFieldList.TagFieldListItem, { ...props2, key })
101
+ }
102
+ ) })
103
+ ] });
104
+ }
105
+
106
+ exports.TagField = TagField;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ 'use strict';
3
+
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var react = require('react');
5
+ var form = require('@react-stately/form');
6
+ var utils = require('@react-stately/utils');
7
+ var useControllableState = require('../hooks/use-controllable-state.cjs');
8
+
9
+ function useTagFieldState(props) {
10
+ const { itemToText, itemToKey, defaultFilter } = props;
11
+ const itemsByKey = react.useMemo(() => {
12
+ const items = props.items ?? props.defaultItems ?? [];
13
+ return items.reduce(
14
+ (acc, item) => {
15
+ acc[itemToKey(item)] = item;
16
+ return acc;
17
+ },
18
+ {}
19
+ ) ?? {};
20
+ }, [itemToKey, props.defaultItems, props.items]);
21
+ const getSelectedItemsByKey = react.useCallback(
22
+ (keys) => {
23
+ if (!keys) return;
24
+ return [...keys].map((key) => itemsByKey[key]);
25
+ },
26
+ [itemsByKey]
27
+ );
28
+ const [selectedItems, setSelectedItems] = useControllableState.useControllableState({
29
+ defaultValue: getSelectedItemsByKey(props.defaultSelectedKeys) ?? [],
30
+ value: getSelectedItemsByKey(props.selectedKeys),
31
+ onChange: props.onSelectionChange
32
+ });
33
+ const defaultInputValue = props.defaultInputValue ?? "";
34
+ const [inputValue, setInputValue] = utils.useControlledState(
35
+ props.inputValue,
36
+ defaultInputValue,
37
+ props.onInputChange
38
+ );
39
+ const controlledSelectedKeys = react.useMemo(
40
+ () => new Set(selectedItems.map(itemToKey)),
41
+ [itemToKey, selectedItems]
42
+ );
43
+ const validation = form.useFormValidationState({
44
+ ...props,
45
+ value: react.useMemo(
46
+ () => ({
47
+ inputValue,
48
+ selectedKeys: controlledSelectedKeys
49
+ }),
50
+ [controlledSelectedKeys, inputValue]
51
+ )
52
+ });
53
+ const filteredItems = react.useMemo(
54
+ () => (
55
+ // No default filter if items are controlled.
56
+ !!props.items || !defaultFilter ? props.items ?? [] : filterItems({
57
+ items: props.defaultItems ?? [],
58
+ inputValue,
59
+ itemToText,
60
+ itemToKey,
61
+ selectedKeys: controlledSelectedKeys,
62
+ filter: defaultFilter
63
+ })
64
+ ),
65
+ [
66
+ props.items,
67
+ props.defaultItems,
68
+ defaultFilter,
69
+ inputValue,
70
+ itemToText,
71
+ itemToKey,
72
+ controlledSelectedKeys
73
+ ]
74
+ );
75
+ return {
76
+ items: filteredItems,
77
+ disabledKeys: props.disabledKeys,
78
+ inputValue,
79
+ setInputValue,
80
+ selectedItems,
81
+ setSelectedItems,
82
+ itemToText,
83
+ itemToKey,
84
+ ...validation
85
+ };
86
+ }
87
+ function filterItems({
88
+ items,
89
+ inputValue,
90
+ itemToText,
91
+ itemToKey,
92
+ filter,
93
+ selectedKeys
94
+ }) {
95
+ return items.filter((item) => {
96
+ const isSelected = selectedKeys ? selectedKeys.has(itemToKey(item)) : false;
97
+ if (isSelected) return false;
98
+ const matchesFilter = filter(itemToText(item), inputValue);
99
+ return matchesFilter;
100
+ });
101
+ }
102
+
103
+ exports.useTagFieldState = useTagFieldState;
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var react = require('react');
5
+ var utils = require('@react-aria/utils');
6
+ var reactVirtual = require('@tanstack/react-virtual');
7
+ var downshift = require('downshift');
8
+ var lodashEs = require('lodash-es');
9
+ var reactAria = require('react-aria');
10
+
11
+ function useTagField(props, state) {
12
+ let { buttonRef } = props;
13
+ const {
14
+ inputRef,
15
+ listBoxRef,
16
+ labelRef,
17
+ shouldCloseOnBlur,
18
+ // TODO: Handle these states
19
+ isReadOnly,
20
+ isDisabled,
21
+ itemToKey,
22
+ itemToText,
23
+ label,
24
+ virtualRowHeight = 40
25
+ } = props;
26
+ const backupBtnRef = react.useRef(null);
27
+ buttonRef = buttonRef ?? backupBtnRef;
28
+ const {
29
+ selectedItems,
30
+ setSelectedItems,
31
+ inputValue,
32
+ setInputValue,
33
+ items,
34
+ disabledKeys
35
+ } = state;
36
+ const { getSelectedItemProps, getDropdownProps, removeSelectedItem } = downshift.useMultipleSelection({
37
+ selectedItems,
38
+ onStateChange({ selectedItems: newSelectedItems, type }) {
39
+ switch (type) {
40
+ case downshift.useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace:
41
+ case downshift.useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete:
42
+ case downshift.useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace:
43
+ case downshift.useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem: {
44
+ if (isDisabled) return;
45
+ setSelectedItems(newSelectedItems ?? []);
46
+ break;
47
+ }
48
+ }
49
+ }
50
+ });
51
+ const disabledKeysSet = react.useMemo(() => {
52
+ return new Set(disabledKeys);
53
+ }, [disabledKeys]);
54
+ const rowVirtualizer = reactVirtual.useVirtualizer({
55
+ count: items.length,
56
+ getScrollElement: () => listBoxRef.current,
57
+ estimateSize: () => virtualRowHeight,
58
+ getItemKey: react.useCallback(
59
+ (index) => itemToKey(items[index]),
60
+ [itemToKey, items]
61
+ ),
62
+ overscan: 2
63
+ });
64
+ const {
65
+ isOpen,
66
+ getToggleButtonProps,
67
+ getLabelProps,
68
+ getMenuProps,
69
+ getInputProps,
70
+ highlightedIndex,
71
+ getItemProps
72
+ } = downshift.useCombobox({
73
+ itemToString: (item) => {
74
+ if (!item) {
75
+ return "";
76
+ }
77
+ return itemToText(item);
78
+ },
79
+ isItemDisabled: (item) => isDisabled || isReadOnly || disabledKeysSet.has(itemToKey(item)),
80
+ items,
81
+ scrollIntoView: () => {
82
+ },
83
+ onHighlightedIndexChange: ({ highlightedIndex: highlightedIndex2, type }) => {
84
+ if (type !== downshift.useCombobox.stateChangeTypes.MenuMouseLeave && highlightedIndex2 >= 0) {
85
+ rowVirtualizer.scrollToIndex(highlightedIndex2);
86
+ }
87
+ },
88
+ defaultHighlightedIndex: 0,
89
+ // after selection, highlight the first item.
90
+ selectedItem: null,
91
+ inputValue,
92
+ stateReducer(_state, actionAndChanges) {
93
+ const { changes, type } = actionAndChanges;
94
+ switch (type) {
95
+ case downshift.useCombobox.stateChangeTypes.ItemClick:
96
+ case downshift.useCombobox.stateChangeTypes.InputKeyDownEnter:
97
+ case downshift.useCombobox.stateChangeTypes.InputBlur: {
98
+ return {
99
+ ...changes,
100
+ isOpen: shouldCloseOnBlur === false ? true : changes.isOpen
101
+ };
102
+ }
103
+ default:
104
+ return changes;
105
+ }
106
+ },
107
+ onStateChange({
108
+ inputValue: newInputValue,
109
+ type,
110
+ selectedItem: newSelectedItem
111
+ }) {
112
+ switch (type) {
113
+ case downshift.useCombobox.stateChangeTypes.InputBlur:
114
+ case downshift.useCombobox.stateChangeTypes.InputKeyDownEnter:
115
+ case downshift.useCombobox.stateChangeTypes.ItemClick: {
116
+ if (newSelectedItem) {
117
+ setSelectedItems((prev) => [.../* @__PURE__ */ new Set([...prev, newSelectedItem])]);
118
+ }
119
+ setInputValue("");
120
+ break;
121
+ }
122
+ case downshift.useCombobox.stateChangeTypes.InputChange:
123
+ setInputValue(newInputValue ?? "");
124
+ break;
125
+ }
126
+ }
127
+ });
128
+ const { isInvalid, validationErrors, validationDetails } = state.displayValidation;
129
+ const inputProps = getInputProps({
130
+ ref: inputRef,
131
+ "aria-label": props["aria-label"],
132
+ "aria-labelledby": props["aria-labelledby"],
133
+ ...getDropdownProps({ preventKeyAction: isOpen }),
134
+ // Somehow adding this will allow the input to be updated properly, else
135
+ // it may sometimes lag behind a single state.
136
+ // Was also in the previous downshift docs but they removed it for some reason.
137
+ // See https://github.com/downshift-js/downshift/pull/1576/files#diff-d32b6994832dda99d96f207e964a0ef27102128c532ea9492949f21ec0cf58d3
138
+ onChange: (e) => setInputValue(e.target.value)
139
+ });
140
+ const {
141
+ labelProps,
142
+ inputProps: newInputProps,
143
+ descriptionProps,
144
+ errorMessageProps
145
+ } = reactAria.useTextField(
146
+ {
147
+ isReadOnly,
148
+ isDisabled,
149
+ isInvalid,
150
+ errorMessage: props.errorMessage,
151
+ description: props.description,
152
+ label,
153
+ ...inputProps,
154
+ onChange: () => {
155
+ },
156
+ value: state.inputValue
157
+ },
158
+ inputRef
159
+ );
160
+ return {
161
+ tagFieldProps: {
162
+ isDisabled: newInputProps.disabled ?? false,
163
+ isReadOnly: newInputProps.readOnly ?? false,
164
+ isInvalid,
165
+ getItemProps,
166
+ highlightedIndex,
167
+ isOpen,
168
+ getSelectedItemProps,
169
+ removeSelectedItem
170
+ },
171
+ labelProps: utils.mergeProps(getLabelProps({ ref: labelRef }), labelProps),
172
+ // Remove onKeyDown from newInputProps to prevent it from being called twice, resulting in arrow keys moving two items.
173
+ inputProps: utils.mergeProps(inputProps, lodashEs.omit(newInputProps, "onKeyDown")),
174
+ buttonProps: getToggleButtonProps({
175
+ ref: buttonRef,
176
+ disabled: isDisabled
177
+ }),
178
+ listBoxProps: getMenuProps({ ref: listBoxRef }, { suppressRefError: true }),
179
+ descriptionProps,
180
+ errorMessageProps,
181
+ isInvalid,
182
+ validationErrors,
183
+ validationDetails,
184
+ rowVirtualizer
185
+ };
186
+ }
187
+
188
+ exports.useTagField = useTagField;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ 'use strict';
3
+
4
+ var textArea = require('./text-area.cjs');
5
+
6
+
7
+
8
+ exports.TextArea = textArea.TextArea;