@eifi1/ui-kit 0.35.0 → 0.36.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.
Files changed (265) hide show
  1. package/README.md +35 -5
  2. package/dist/admin/role-select.d.ts +3 -2
  3. package/dist/admin/role-select.js +2 -0
  4. package/dist/admin/role-select.js.map +1 -1
  5. package/dist/components/amount-input.d.ts +2 -2
  6. package/dist/components/amount-input.js.map +1 -1
  7. package/dist/components/autocomplete.d.ts +2 -2
  8. package/dist/components/autocomplete.js +2 -1
  9. package/dist/components/autocomplete.js.map +1 -1
  10. package/dist/components/button-look.d.ts +1 -1
  11. package/dist/components/button-look.js +9 -4
  12. package/dist/components/button-look.js.map +1 -1
  13. package/dist/components/checkbox-group.d.ts +5 -2
  14. package/dist/components/checkbox-group.js +15 -4
  15. package/dist/components/checkbox-group.js.map +1 -1
  16. package/dist/components/column-mapper.d.ts +5 -3
  17. package/dist/components/column-mapper.js +2 -0
  18. package/dist/components/column-mapper.js.map +1 -1
  19. package/dist/components/combobox.d.ts +2 -2
  20. package/dist/components/combobox.js +2 -1
  21. package/dist/components/combobox.js.map +1 -1
  22. package/dist/components/country-select.d.ts +3 -3
  23. package/dist/components/country-select.js +3 -0
  24. package/dist/components/country-select.js.map +1 -1
  25. package/dist/components/currency-select.d.ts +3 -2
  26. package/dist/components/currency-select.js +10 -1
  27. package/dist/components/currency-select.js.map +1 -1
  28. package/dist/components/date-field.d.ts +2 -1
  29. package/dist/components/date-field.js.map +1 -1
  30. package/dist/components/date-picker.js +3 -0
  31. package/dist/components/date-picker.js.map +1 -1
  32. package/dist/components/date-range-picker.js +3 -0
  33. package/dist/components/date-range-picker.js.map +1 -1
  34. package/dist/components/entity-combobox.d.ts +2 -2
  35. package/dist/components/entity-combobox.js +2 -1
  36. package/dist/components/entity-combobox.js.map +1 -1
  37. package/dist/components/field-parts.d.ts +66 -11
  38. package/dist/components/field-parts.js +32 -10
  39. package/dist/components/field-parts.js.map +1 -1
  40. package/dist/components/field-strip.d.ts +3 -2
  41. package/dist/components/field-strip.js +2 -1
  42. package/dist/components/field-strip.js.map +1 -1
  43. package/dist/components/field.d.ts +3 -2
  44. package/dist/components/field.js +24 -15
  45. package/dist/components/field.js.map +1 -1
  46. package/dist/components/help-popover.d.ts +9 -7
  47. package/dist/components/help-popover.js.map +1 -1
  48. package/dist/components/icon-picker.d.ts +3 -2
  49. package/dist/components/icon-picker.js +3 -0
  50. package/dist/components/icon-picker.js.map +1 -1
  51. package/dist/components/inline-entity-combobox.d.ts +2 -2
  52. package/dist/components/inline-entity-combobox.js +2 -1
  53. package/dist/components/inline-entity-combobox.js.map +1 -1
  54. package/dist/components/input.d.ts +2 -2
  55. package/dist/components/input.js +2 -1
  56. package/dist/components/input.js.map +1 -1
  57. package/dist/components/month-picker.d.ts +2 -1
  58. package/dist/components/month-picker.js +8 -1
  59. package/dist/components/month-picker.js.map +1 -1
  60. package/dist/components/multi-entity-combobox.d.ts +2 -2
  61. package/dist/components/multi-entity-combobox.js +2 -1
  62. package/dist/components/multi-entity-combobox.js.map +1 -1
  63. package/dist/components/multi-select.d.ts +2 -2
  64. package/dist/components/multi-select.js +3 -0
  65. package/dist/components/multi-select.js.map +1 -1
  66. package/dist/components/number-input.d.ts +2 -2
  67. package/dist/components/number-input.js.map +1 -1
  68. package/dist/components/numeric-field.d.ts +5 -2
  69. package/dist/components/numeric-field.js +4 -1
  70. package/dist/components/numeric-field.js.map +1 -1
  71. package/dist/components/one-time-code-input.d.ts +2 -1
  72. package/dist/components/one-time-code-input.js +2 -1
  73. package/dist/components/one-time-code-input.js.map +1 -1
  74. package/dist/components/phone-input.d.ts +1 -1
  75. package/dist/components/phone-input.js +4 -0
  76. package/dist/components/phone-input.js.map +1 -1
  77. package/dist/components/popover.js +1 -1
  78. package/dist/components/popover.js.map +1 -1
  79. package/dist/components/select.d.ts +4 -3
  80. package/dist/components/select.js +2 -1
  81. package/dist/components/select.js.map +1 -1
  82. package/dist/components/slider.d.ts +3 -2
  83. package/dist/components/slider.js +7 -1
  84. package/dist/components/slider.js.map +1 -1
  85. package/dist/components/stat-tile.js +2 -11
  86. package/dist/components/stat-tile.js.map +1 -1
  87. package/dist/components/swatch-picker.d.ts +3 -2
  88. package/dist/components/swatch-picker.js +3 -0
  89. package/dist/components/swatch-picker.js.map +1 -1
  90. package/dist/components/text-link.js +3 -1
  91. package/dist/components/text-link.js.map +1 -1
  92. package/dist/components/textarea.d.ts +2 -1
  93. package/dist/components/textarea.js +9 -3
  94. package/dist/components/textarea.js.map +1 -1
  95. package/dist/components/toggle-group.d.ts +2 -2
  96. package/dist/components/toggle-group.js +7 -3
  97. package/dist/components/toggle-group.js.map +1 -1
  98. package/dist/eslint/index.js +1 -1
  99. package/dist/i18n/defaults.js +5 -1
  100. package/dist/i18n/defaults.js.map +1 -1
  101. package/dist/i18n/german.js +97 -1
  102. package/dist/i18n/german.js.map +1 -1
  103. package/dist/i18n/kit-labels.d.ts +15 -0
  104. package/dist/i18n/kit-labels.js +21 -1
  105. package/dist/i18n/kit-labels.js.map +1 -1
  106. package/dist/i18n/locales/en.js +103 -2
  107. package/dist/i18n/locales/en.js.map +3 -3
  108. package/dist/i18n/locales/es.js +95 -1
  109. package/dist/i18n/locales/es.js.map +1 -1
  110. package/dist/i18n/locales/fr.js +96 -1
  111. package/dist/i18n/locales/fr.js.map +1 -1
  112. package/dist/i18n/locales/hu.js +95 -1
  113. package/dist/i18n/locales/hu.js.map +1 -1
  114. package/dist/i18n/locales/it.js +96 -1
  115. package/dist/i18n/locales/it.js.map +1 -1
  116. package/dist/i18n/locales/zh.js +95 -1
  117. package/dist/i18n/locales/zh.js.map +1 -1
  118. package/dist/i18n/review.js +13 -0
  119. package/dist/i18n/review.js.map +1 -1
  120. package/dist/i18n/shared-labels.js +3 -1
  121. package/dist/i18n/shared-labels.js.map +1 -1
  122. package/dist/index.d.ts +21 -0
  123. package/dist/index.js +38 -0
  124. package/dist/index.js.map +1 -1
  125. package/dist/lib/device-settings.d.ts +72 -0
  126. package/dist/lib/device-settings.js +64 -0
  127. package/dist/lib/device-settings.js.map +1 -0
  128. package/dist/lib/plain-text.d.ts +11 -0
  129. package/dist/lib/plain-text.js +16 -0
  130. package/dist/lib/plain-text.js.map +1 -0
  131. package/dist/lib/safe-storage.d.ts +6 -0
  132. package/dist/lib/safe-storage.js +11 -0
  133. package/dist/lib/safe-storage.js.map +1 -1
  134. package/dist/notifications/notification-parts.d.ts +39 -0
  135. package/dist/notifications/notification-parts.js +47 -0
  136. package/dist/notifications/notification-parts.js.map +1 -0
  137. package/dist/notifications/notification-types-setting.d.ts +62 -0
  138. package/dist/notifications/notification-types-setting.js +192 -0
  139. package/dist/notifications/notification-types-setting.js.map +1 -0
  140. package/dist/notifications/notification-types.d.ts +75 -0
  141. package/dist/notifications/notification-types.js +2 -0
  142. package/dist/notifications/notification-types.js.map +1 -0
  143. package/dist/notifications/notifications-labels.d.ts +131 -0
  144. package/dist/notifications/notifications-labels.js +83 -0
  145. package/dist/notifications/notifications-labels.js.map +1 -0
  146. package/dist/notifications/push-device-setting.d.ts +37 -0
  147. package/dist/notifications/push-device-setting.js +164 -0
  148. package/dist/notifications/push-device-setting.js.map +1 -0
  149. package/dist/notifications/push-devices-setting.d.ts +44 -0
  150. package/dist/notifications/push-devices-setting.js +203 -0
  151. package/dist/notifications/push-devices-setting.js.map +1 -0
  152. package/dist/notifications/quiet-hours-setting.d.ts +47 -0
  153. package/dist/notifications/quiet-hours-setting.js +131 -0
  154. package/dist/notifications/quiet-hours-setting.js.map +1 -0
  155. package/dist/notifications/time-zone-select.d.ts +50 -0
  156. package/dist/notifications/time-zone-select.js +76 -0
  157. package/dist/notifications/time-zone-select.js.map +1 -0
  158. package/dist/notifications/unsubscribe-panel.d.ts +53 -0
  159. package/dist/notifications/unsubscribe-panel.js +139 -0
  160. package/dist/notifications/unsubscribe-panel.js.map +1 -0
  161. package/dist/notifications/use-push-device.d.ts +122 -0
  162. package/dist/notifications/use-push-device.js +230 -0
  163. package/dist/notifications/use-push-device.js.map +1 -0
  164. package/dist/rhf/fields.d.ts +26 -19
  165. package/dist/rhf/fields.js +51 -22
  166. package/dist/rhf/fields.js.map +1 -1
  167. package/dist/settings/device-reset-setting-labels.d.ts +3 -0
  168. package/dist/settings/device-reset-setting-labels.js +15 -0
  169. package/dist/settings/device-reset-setting-labels.js.map +1 -0
  170. package/dist/settings/device-reset-setting.d.ts +58 -0
  171. package/dist/settings/device-reset-setting.js +51 -0
  172. package/dist/settings/device-reset-setting.js.map +1 -0
  173. package/dist/shell/app-shell.js +5 -0
  174. package/dist/shell/app-shell.js.map +1 -1
  175. package/dist/theme/contrast-tokens.d.ts +42 -4
  176. package/dist/theme/contrast-tokens.js +56 -9
  177. package/dist/theme/contrast-tokens.js.map +1 -1
  178. package/dist/theme/contrast.d.ts +4 -2
  179. package/dist/theme/contrast.js +13 -0
  180. package/dist/theme/contrast.js.map +1 -1
  181. package/dist/theme/palette-derive.d.ts +15 -1
  182. package/dist/theme/palette-derive.js +37 -8
  183. package/dist/theme/palette-derive.js.map +1 -1
  184. package/dist/theme/palette-presets.d.ts +2 -1
  185. package/dist/theme/palette-presets.js +5 -5
  186. package/dist/theme/palette-presets.js.map +1 -1
  187. package/dist/theme/palette-store.js +6 -0
  188. package/dist/theme/palette-store.js.map +1 -1
  189. package/dist/theme/text-size.js +6 -0
  190. package/dist/theme/text-size.js.map +1 -1
  191. package/dist/theme/theme-store.js +6 -0
  192. package/dist/theme/theme-store.js.map +1 -1
  193. package/package.json +1 -1
  194. package/src/admin/role-select.tsx +4 -1
  195. package/src/components/amount-input.tsx +2 -1
  196. package/src/components/autocomplete.tsx +5 -2
  197. package/src/components/button-look.ts +15 -5
  198. package/src/components/checkbox-group.tsx +22 -4
  199. package/src/components/column-mapper.tsx +6 -2
  200. package/src/components/combobox.tsx +5 -2
  201. package/src/components/country-select.tsx +6 -1
  202. package/src/components/currency-select.tsx +12 -3
  203. package/src/components/date-field.tsx +2 -2
  204. package/src/components/date-picker.tsx +3 -0
  205. package/src/components/date-range-picker.tsx +3 -0
  206. package/src/components/entity-combobox.tsx +5 -2
  207. package/src/components/field-parts.tsx +107 -19
  208. package/src/components/field-strip.tsx +4 -3
  209. package/src/components/field.tsx +28 -15
  210. package/src/components/help-popover.tsx +9 -7
  211. package/src/components/icon-picker.tsx +8 -3
  212. package/src/components/inline-entity-combobox.tsx +5 -2
  213. package/src/components/input.tsx +4 -2
  214. package/src/components/month-picker.tsx +10 -3
  215. package/src/components/multi-entity-combobox.tsx +5 -2
  216. package/src/components/multi-select.tsx +6 -1
  217. package/src/components/number-input.tsx +2 -2
  218. package/src/components/numeric-field.ts +10 -2
  219. package/src/components/one-time-code-input.tsx +5 -3
  220. package/src/components/phone-input.tsx +4 -0
  221. package/src/components/popover.tsx +3 -1
  222. package/src/components/select.tsx +6 -3
  223. package/src/components/slider.tsx +10 -3
  224. package/src/components/stat-tile.tsx +3 -18
  225. package/src/components/swatch-picker.tsx +9 -4
  226. package/src/components/text-link.tsx +3 -1
  227. package/src/components/textarea.tsx +11 -4
  228. package/src/components/toggle-group.tsx +21 -5
  229. package/src/i18n/defaults.ts +4 -0
  230. package/src/i18n/german.ts +113 -0
  231. package/src/i18n/kit-labels.tsx +51 -1
  232. package/src/i18n/locales/en.ts +6 -0
  233. package/src/i18n/locales/es.ts +106 -0
  234. package/src/i18n/locales/fr.ts +106 -0
  235. package/src/i18n/locales/hu.ts +104 -0
  236. package/src/i18n/locales/it.ts +105 -0
  237. package/src/i18n/locales/zh.ts +96 -0
  238. package/src/i18n/review.ts +13 -0
  239. package/src/i18n/shared-labels.ts +2 -0
  240. package/src/index.ts +50 -0
  241. package/src/lib/device-settings.ts +146 -0
  242. package/src/lib/plain-text.ts +22 -0
  243. package/src/lib/safe-storage.ts +16 -0
  244. package/src/notifications/notification-parts.tsx +83 -0
  245. package/src/notifications/notification-types-setting.tsx +309 -0
  246. package/src/notifications/notification-types.ts +80 -0
  247. package/src/notifications/notifications-labels.ts +238 -0
  248. package/src/notifications/push-device-setting.tsx +224 -0
  249. package/src/notifications/push-devices-setting.tsx +306 -0
  250. package/src/notifications/quiet-hours-setting.tsx +185 -0
  251. package/src/notifications/time-zone-select.tsx +126 -0
  252. package/src/notifications/unsubscribe-panel.tsx +203 -0
  253. package/src/notifications/use-push-device.ts +392 -0
  254. package/src/rhf/fields.tsx +77 -29
  255. package/src/settings/device-reset-setting-labels.ts +20 -0
  256. package/src/settings/device-reset-setting.tsx +119 -0
  257. package/src/shell/app-shell.tsx +8 -0
  258. package/src/theme/contrast-tokens.ts +106 -12
  259. package/src/theme/contrast.ts +30 -4
  260. package/src/theme/palette-derive.ts +68 -7
  261. package/src/theme/palette-presets.ts +9 -6
  262. package/src/theme/palette-store.ts +12 -0
  263. package/src/theme/text-size.ts +8 -0
  264. package/src/theme/theme-store.ts +10 -0
  265. package/tokens.css +38 -4
@@ -0,0 +1,230 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { useMediaQuery } from "../hooks/use-media-query.js";
4
+ import { httpStatusOf } from "../auth/auth-errors.js";
5
+ class PushDeviceError extends Error {
6
+ code;
7
+ constructor(code) {
8
+ super(code);
9
+ this.name = "PushDeviceError";
10
+ this.code = code;
11
+ }
12
+ }
13
+ const PUSH_SUBSCRIPTION_CHANGED = "eifi1:push-subscription-changed";
14
+ function notifyPushSubscriptionChanged() {
15
+ if (typeof window !== "undefined") window.dispatchEvent(new Event(PUSH_SUBSCRIPTION_CHANGED));
16
+ }
17
+ function pushSupported() {
18
+ return typeof window !== "undefined" && typeof navigator !== "undefined" && "serviceWorker" in navigator && "PushManager" in window && "Notification" in window;
19
+ }
20
+ function isIos() {
21
+ if (typeof navigator === "undefined") return false;
22
+ const ua = navigator.userAgent;
23
+ return /iphone|ipad|ipod/i.test(ua) || /Macintosh/.test(ua) && navigator.maxTouchPoints > 1;
24
+ }
25
+ const READY_TIMEOUT_MS = 1e4;
26
+ const PUSH_TIMEOUT_MS = 15e3;
27
+ function within(promise, ms, code) {
28
+ let timer;
29
+ return Promise.race([
30
+ promise,
31
+ new Promise((_, reject) => {
32
+ timer = setTimeout(() => reject(new PushDeviceError(code)), ms);
33
+ })
34
+ ]).finally(() => clearTimeout(timer));
35
+ }
36
+ async function activeRegistration() {
37
+ const existing = await navigator.serviceWorker.getRegistration();
38
+ if (!existing) throw new PushDeviceError("no_service_worker");
39
+ return within(navigator.serviceWorker.ready, READY_TIMEOUT_MS, "no_service_worker");
40
+ }
41
+ function keyBytes(key) {
42
+ const base64 = key.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - key.length % 4) % 4);
43
+ const raw = atob(base64);
44
+ const bytes = new Uint8Array(new ArrayBuffer(raw.length));
45
+ for (let i = 0; i < raw.length; i++) bytes[i] = raw.charCodeAt(i);
46
+ return bytes;
47
+ }
48
+ function inputOf(subscription) {
49
+ const json = subscription.toJSON();
50
+ const p256dh = json.keys?.p256dh;
51
+ const auth = json.keys?.auth;
52
+ if (!json.endpoint || !p256dh || !auth) return null;
53
+ return { endpoint: json.endpoint, keys: { p256dh, auth }, user_agent: navigator.userAgent || null };
54
+ }
55
+ const defaultEndpointTaken = (error) => httpStatusOf(error) === 409;
56
+ function usePushDevice(options) {
57
+ const latest = useRef(options);
58
+ useEffect(() => {
59
+ latest.current = options;
60
+ });
61
+ const supported = pushSupported();
62
+ const ios = isIos();
63
+ const standalone = useMediaQuery("(display-mode: standalone)", false);
64
+ const installed = standalone || typeof navigator !== "undefined" && navigator.standalone === true;
65
+ const [permission, setPermission] = useState(
66
+ () => supported ? Notification.permission : "unsupported"
67
+ );
68
+ const [configured, setConfigured] = useState(void 0);
69
+ const [subscribed, setSubscribed] = useState(false);
70
+ const [foreignSubscription, setForeignSubscription] = useState(false);
71
+ const [currentEndpoint, setCurrentEndpoint] = useState(null);
72
+ const [busy, setBusy] = useState(false);
73
+ const mounted = useRef(true);
74
+ const announcing = useRef(false);
75
+ const announce = useCallback(() => {
76
+ announcing.current = true;
77
+ try {
78
+ notifyPushSubscriptionChanged();
79
+ } finally {
80
+ announcing.current = false;
81
+ }
82
+ latest.current.onChange?.();
83
+ }, []);
84
+ useEffect(() => {
85
+ mounted.current = true;
86
+ return () => {
87
+ mounted.current = false;
88
+ };
89
+ }, []);
90
+ useEffect(() => {
91
+ if (!supported) return;
92
+ let cancelled = false;
93
+ latest.current.pushKey().then(
94
+ (key) => {
95
+ if (!cancelled) setConfigured(key !== "");
96
+ },
97
+ () => {
98
+ }
99
+ );
100
+ return () => {
101
+ cancelled = true;
102
+ };
103
+ }, [supported]);
104
+ useEffect(() => {
105
+ if (!supported) return;
106
+ let cancelled = false;
107
+ const sync = async () => {
108
+ try {
109
+ const registration = await activeRegistration();
110
+ const existing = await registration.pushManager.getSubscription();
111
+ if (cancelled) return;
112
+ setPermission(Notification.permission);
113
+ if (!existing) {
114
+ setSubscribed(false);
115
+ setForeignSubscription(false);
116
+ setCurrentEndpoint(null);
117
+ return;
118
+ }
119
+ let mine;
120
+ try {
121
+ const devices = await latest.current.devices();
122
+ mine = devices.some((device) => device.endpoint === existing.endpoint);
123
+ } catch {
124
+ mine = true;
125
+ }
126
+ if (cancelled) return;
127
+ setCurrentEndpoint(existing.endpoint);
128
+ setSubscribed(mine);
129
+ setForeignSubscription(!mine);
130
+ } catch {
131
+ }
132
+ };
133
+ const heard = () => {
134
+ if (!announcing.current) void sync();
135
+ };
136
+ void sync();
137
+ window.addEventListener(PUSH_SUBSCRIPTION_CHANGED, heard);
138
+ return () => {
139
+ cancelled = true;
140
+ window.removeEventListener(PUSH_SUBSCRIPTION_CHANGED, heard);
141
+ };
142
+ }, [supported]);
143
+ const enable = useCallback(async () => {
144
+ if (!supported) return false;
145
+ const { pushKey, register, isEndpointTaken = defaultEndpointTaken } = latest.current;
146
+ setBusy(true);
147
+ try {
148
+ const granted = await Notification.requestPermission();
149
+ if (mounted.current) setPermission(granted);
150
+ if (granted !== "granted") return false;
151
+ const key = await pushKey();
152
+ if (!key) {
153
+ if (mounted.current) setConfigured(false);
154
+ return false;
155
+ }
156
+ if (mounted.current) setConfigured(true);
157
+ const registration = await activeRegistration();
158
+ const subscribe = (reuse) => within(
159
+ (async () => (reuse ? await registration.pushManager.getSubscription() : null) ?? await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: keyBytes(key) }))(),
160
+ PUSH_TIMEOUT_MS,
161
+ "push_timeout"
162
+ );
163
+ let subscription = await subscribe(true);
164
+ let input = inputOf(subscription);
165
+ if (!input) return false;
166
+ try {
167
+ await register(input);
168
+ } catch (error) {
169
+ if (!isEndpointTaken(error)) throw error;
170
+ await within(subscription.unsubscribe(), PUSH_TIMEOUT_MS, "push_timeout");
171
+ subscription = await subscribe(false);
172
+ input = inputOf(subscription);
173
+ if (!input) return false;
174
+ await register(input);
175
+ }
176
+ if (mounted.current) {
177
+ setSubscribed(true);
178
+ setForeignSubscription(false);
179
+ setCurrentEndpoint(input.endpoint);
180
+ }
181
+ announce();
182
+ return true;
183
+ } finally {
184
+ if (mounted.current) setBusy(false);
185
+ }
186
+ }, [supported, announce]);
187
+ const disable = useCallback(async () => {
188
+ if (!supported) return;
189
+ setBusy(true);
190
+ try {
191
+ const registration = await activeRegistration();
192
+ const subscription = await registration.pushManager.getSubscription();
193
+ if (subscription) {
194
+ await latest.current.unregister(subscription.endpoint);
195
+ await within(subscription.unsubscribe(), PUSH_TIMEOUT_MS, "push_timeout");
196
+ }
197
+ if (mounted.current) {
198
+ setSubscribed(false);
199
+ setForeignSubscription(false);
200
+ setCurrentEndpoint(null);
201
+ }
202
+ announce();
203
+ } finally {
204
+ if (mounted.current) setBusy(false);
205
+ }
206
+ }, [supported, announce]);
207
+ const sendTest = useCallback(() => latest.current.test(), []);
208
+ return {
209
+ supported,
210
+ configured,
211
+ installed,
212
+ ios,
213
+ permission,
214
+ subscribed,
215
+ foreignSubscription,
216
+ currentEndpoint,
217
+ busy,
218
+ enable,
219
+ disable,
220
+ sendTest
221
+ };
222
+ }
223
+ export {
224
+ PUSH_SUBSCRIPTION_CHANGED,
225
+ PushDeviceError,
226
+ notifyPushSubscriptionChanged,
227
+ pushSupported,
228
+ usePushDevice
229
+ };
230
+ //# sourceMappingURL=use-push-device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/notifications/use-push-device.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { useMediaQuery } from \"../hooks/use-media-query\";\nimport { httpStatusOf } from \"../auth/auth-errors\";\n\n/**\n * This browser's Web Push subscription for the signed-in account\n * (docs/notifications-harmonization.md §2.7, §3.5, §4.2) — keksdose's\n * `shared/push/use-push.ts`, lifted. The service worker with its `push` and\n * `notificationclick` handlers stays the app's; this hook owns the browser's side:\n * permission, subscribe with the server's VAPID key, register the subscription, and\n * unsubscribe. The kit makes no request of its own: the app hands it one function per\n * endpoint.\n */\n\n/** The browser's notification permission, or `\"unsupported\"` where it has no push. */\nexport type PushPermission = NotificationPermission | \"unsupported\";\n\n/** Why turning push on or off could not finish — a {@link PushDeviceError}'s `code`. */\nexport type PushDeviceErrorCode = \"no_service_worker\" | \"push_timeout\";\n\n/**\n * The two failures the card has words of its own for: no service worker registered (or\n * one not ready in 10 s) — \"reload and try again\" — and a browser push service that did\n * not answer in 15 s — \"check your connection\". Anything else is the app's request\n * failing, rejected as it came.\n */\nexport class PushDeviceError extends Error {\n readonly code: PushDeviceErrorCode;\n constructor(code: PushDeviceErrorCode) {\n super(code);\n this.name = \"PushDeviceError\";\n this.code = code;\n }\n}\n\n/** What `register` sends: `POST /notifications/devices` (§3.5). */\nexport interface PushSubscriptionInput {\n endpoint: string;\n keys: { p256dh: string; auth: string };\n user_agent: string | null;\n}\n\nexport interface UsePushDeviceOptions {\n /** `GET /notifications/push-key` → its `key`; `\"\"` when push is off on the server. */\n pushKey: () => Promise<string>;\n /** `POST /notifications/devices`. A 409 (another account's endpoint) is recovered\n * once: the hook unsubscribes and registers a fresh endpoint. */\n register: (subscription: PushSubscriptionInput) => Promise<unknown>;\n /** `POST /notifications/devices/unregister {endpoint}` — the endpoint never goes in a\n * URL. */\n unregister: (endpoint: string) => Promise<unknown>;\n /** `GET /notifications/devices`: the account's own list, which says whether THIS\n * account holds this browser's subscription. */\n devices: () => Promise<readonly { endpoint: string }[]>;\n /** `POST /notifications/test` → how many devices the push service accepted it for. */\n test: () => Promise<{ sent: number }>;\n /** Whether `register` refused another account's endpoint. Default: HTTP 409. */\n isEndpointTaken?: (error: unknown) => boolean;\n /** After an enable or a disable: the app refreshes its device queries. */\n onChange?: () => void;\n}\n\n/** What {@link usePushDevice} answers. */\nexport interface PushDevice {\n /** The browser exposes service workers, `PushManager` and `Notification`. */\n supported: boolean;\n /** The server has VAPID keys; `undefined` until `pushKey` answered (or when it failed). */\n configured: boolean | undefined;\n /** Running as an installed app: `display-mode: standalone`, or iOS's\n * `navigator.standalone`. */\n installed: boolean;\n /** iPhone or iPad — where push reaches only the installed app. */\n ios: boolean;\n permission: PushPermission;\n /** THIS account holds this browser's subscription. An unreachable device list falls\n * back to the browser's own answer. */\n subscribed: boolean;\n /** This browser holds a subscription that belongs to another account (two accounts in\n * one browser profile): `subscribed` is false, and turning on mints a fresh one. */\n foreignSubscription: boolean;\n /** This browser's subscription endpoint, or `null` — marks \"This device\" in a list. */\n currentEndpoint: string | null;\n /** An enable or a disable is running. */\n busy: boolean;\n /** Ask for permission (the browser's one prompt), subscribe and register. `false` when\n * the permission was not granted or push is off on the server; rejects with a\n * {@link PushDeviceError} or the app's request's error. */\n enable: () => Promise<boolean>;\n /** Tell the server first, then the browser, so a dropped device stops at once. */\n disable: () => Promise<void>;\n sendTest: () => Promise<{ sent: number }>;\n}\n\n/**\n * The window event every mounted {@link usePushDevice} re-reads its state on. Fired by\n * every enable and disable, and by `PushDevicesSetting` when it removes this device — so\n * an app's own card on the same hook (keksdose's check-up) stays in step. The hook that\n * fires it does not re-read: it knows what it changed. Namespaced for the kit;\n * keksdose's was `\"keksdose:push-subscription-changed\"`.\n */\nexport const PUSH_SUBSCRIPTION_CHANGED = \"eifi1:push-subscription-changed\";\n\n/** Tell every {@link usePushDevice} that this browser's subscription changed. */\nexport function notifyPushSubscriptionChanged(): void {\n if (typeof window !== \"undefined\") window.dispatchEvent(new Event(PUSH_SUBSCRIPTION_CHANGED));\n}\n\n/** Whether this browser has the APIs push needs. iOS exposes them only to an INSTALLED\n * app (Add to Home Screen). */\nexport function pushSupported(): boolean {\n return (\n typeof window !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n \"serviceWorker\" in navigator &&\n \"PushManager\" in window &&\n \"Notification\" in window\n );\n}\n\n/** iPhone or iPad. iPadOS 13+ reports itself as a Mac; the touch points tell it apart. */\nfunction isIos(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const ua = navigator.userAgent;\n return /iphone|ipad|ipod/i.test(ua) || (/Macintosh/.test(ua) && navigator.maxTouchPoints > 1);\n}\n\nconst READY_TIMEOUT_MS = 10_000;\nconst PUSH_TIMEOUT_MS = 15_000;\n\n/** `promise`, or a {@link PushDeviceError} after `ms`. The timer is cleared either way. */\nfunction within<T>(promise: Promise<T>, ms: number, code: PushDeviceErrorCode): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new PushDeviceError(code)), ms);\n }),\n ]).finally(() => clearTimeout(timer));\n}\n\n/**\n * The active registration. `navigator.serviceWorker.ready` never settles while the origin\n * has no registration, so a missing one fails at once, and one stuck installing fails\n * after 10 s (keksdose: enable() hung with the button latched before its worker was\n * served).\n */\nasync function activeRegistration(): Promise<ServiceWorkerRegistration> {\n const existing = await navigator.serviceWorker.getRegistration();\n if (!existing) throw new PushDeviceError(\"no_service_worker\");\n return within(navigator.serviceWorker.ready, READY_TIMEOUT_MS, \"no_service_worker\");\n}\n\n/** A VAPID public key (base64url) as the bytes `PushManager.subscribe` wants. */\nfunction keyBytes(key: string): Uint8Array<ArrayBuffer> {\n const base64 = key.replace(/-/g, \"+\").replace(/_/g, \"/\") + \"=\".repeat((4 - (key.length % 4)) % 4);\n const raw = atob(base64);\n const bytes = new Uint8Array(new ArrayBuffer(raw.length));\n for (let i = 0; i < raw.length; i++) bytes[i] = raw.charCodeAt(i);\n return bytes;\n}\n\n/** A subscription's register body, or `null` when the browser handed back an incomplete\n * one. */\nfunction inputOf(subscription: PushSubscription): PushSubscriptionInput | null {\n const json = subscription.toJSON();\n const p256dh = json.keys?.p256dh;\n const auth = json.keys?.auth;\n if (!json.endpoint || !p256dh || !auth) return null;\n return { endpoint: json.endpoint, keys: { p256dh, auth }, user_agent: navigator.userAgent || null };\n}\n\nconst defaultEndpointTaken = (error: unknown) => httpStatusOf(error) === 409;\n\n/**\n * This browser's push for the signed-in account. Hand it one function per endpoint\n * (§3.8); {@link PushDeviceSetting} draws it, and an app's own card may use it too.\n *\n * **\"Subscribed\" means this account**, not \"this browser holds a subscription\": a\n * browser profile's subscription has no account in it, so a second account in the same\n * profile would read the first's as its own (keksdose). The endpoint is checked against\n * the account's own `devices()`; when that list cannot be read (offline), the browser's\n * answer stands — a wrong \"on\" costs what it did before the check, a wrong \"off\" invites\n * re-subscribing a device that is fine.\n *\n * **A 409 from `register`** — the endpoint belongs to another account, and the server\n * will not re-home what it cannot prove this browser holds — unsubscribes and registers\n * a fresh endpoint, once.\n *\n * **Timeouts:** no registration fails at once and a worker not ready in 10 s fails, both\n * `PushDeviceError(\"no_service_worker\")`; the browser's subscribe and unsubscribe are cut\n * at 15 s, `PushDeviceError(\"push_timeout\")` — so `busy` can never latch.\n *\n * Every mounted hook re-reads its state on {@link PUSH_SUBSCRIPTION_CHANGED}.\n */\nexport function usePushDevice(options: UsePushDeviceOptions): PushDevice {\n // The app's functions are usually new on every render; the effects read the latest.\n const latest = useRef(options);\n useEffect(() => {\n latest.current = options;\n });\n\n const supported = pushSupported();\n const ios = isIos();\n const standalone = useMediaQuery(\"(display-mode: standalone)\", false);\n const installed =\n standalone ||\n (typeof navigator !== \"undefined\" && (navigator as Navigator & { standalone?: boolean }).standalone === true);\n\n const [permission, setPermission] = useState<PushPermission>(() =>\n supported ? Notification.permission : \"unsupported\",\n );\n const [configured, setConfigured] = useState<boolean | undefined>(undefined);\n const [subscribed, setSubscribed] = useState(false);\n const [foreignSubscription, setForeignSubscription] = useState(false);\n const [currentEndpoint, setCurrentEndpoint] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const mounted = useRef(true);\n // Set while this hook fires the event itself: it already knows what changed, and a\n // re-read could only be worse — an app whose `devices()` answers from a cache would\n // hand back the list from before the change.\n const announcing = useRef(false);\n const announce = useCallback(() => {\n announcing.current = true;\n try {\n notifyPushSubscriptionChanged();\n } finally {\n announcing.current = false;\n }\n latest.current.onChange?.();\n }, []);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n // Whether the server has keys (\"\" → push is off there). Once per mount.\n useEffect(() => {\n if (!supported) return;\n let cancelled = false;\n latest.current.pushKey().then(\n (key) => {\n if (!cancelled) setConfigured(key !== \"\");\n },\n () => {\n /* unknown: the card shows the ordinary states */\n },\n );\n return () => {\n cancelled = true;\n };\n }, [supported]);\n\n // What this browser holds, and whether it is this account's — at mount, and whenever\n // a subscription changes anywhere in the app.\n useEffect(() => {\n if (!supported) return;\n let cancelled = false;\n const sync = async () => {\n try {\n const registration = await activeRegistration();\n const existing = await registration.pushManager.getSubscription();\n if (cancelled) return;\n // Read again: the person may have changed it in the browser's settings.\n setPermission(Notification.permission);\n if (!existing) {\n setSubscribed(false);\n setForeignSubscription(false);\n setCurrentEndpoint(null);\n return;\n }\n let mine: boolean;\n try {\n const devices = await latest.current.devices();\n mine = devices.some((device) => device.endpoint === existing.endpoint);\n } catch {\n mine = true;\n }\n if (cancelled) return;\n setCurrentEndpoint(existing.endpoint);\n setSubscribed(mine);\n setForeignSubscription(!mine);\n } catch {\n /* no active service worker yet: not subscribed */\n }\n };\n const heard = () => {\n if (!announcing.current) void sync();\n };\n void sync();\n window.addEventListener(PUSH_SUBSCRIPTION_CHANGED, heard);\n return () => {\n cancelled = true;\n window.removeEventListener(PUSH_SUBSCRIPTION_CHANGED, heard);\n };\n }, [supported]);\n\n const enable = useCallback(async (): Promise<boolean> => {\n if (!supported) return false;\n const { pushKey, register, isEndpointTaken = defaultEndpointTaken } = latest.current;\n setBusy(true);\n try {\n const granted = await Notification.requestPermission();\n if (mounted.current) setPermission(granted);\n if (granted !== \"granted\") return false;\n\n const key = await pushKey();\n if (!key) {\n if (mounted.current) setConfigured(false);\n return false;\n }\n if (mounted.current) setConfigured(true);\n\n const registration = await activeRegistration();\n // The one place the browser is asked for a subscription, so the timeout and the\n // `{userVisibleOnly, applicationServerKey}` literal are on both paths.\n const subscribe = (reuse: boolean) =>\n within(\n (async () =>\n (reuse ? await registration.pushManager.getSubscription() : null) ??\n (await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: keyBytes(key) })))(),\n PUSH_TIMEOUT_MS,\n \"push_timeout\",\n );\n\n let subscription = await subscribe(true);\n let input = inputOf(subscription);\n if (!input) return false;\n try {\n await register(input);\n } catch (error) {\n if (!isEndpointTaken(error)) throw error;\n await within(subscription.unsubscribe(), PUSH_TIMEOUT_MS, \"push_timeout\");\n subscription = await subscribe(false);\n input = inputOf(subscription);\n if (!input) return false;\n await register(input);\n }\n if (mounted.current) {\n setSubscribed(true);\n setForeignSubscription(false);\n setCurrentEndpoint(input.endpoint);\n }\n announce();\n return true;\n } finally {\n if (mounted.current) setBusy(false);\n }\n }, [supported, announce]);\n\n const disable = useCallback(async (): Promise<void> => {\n if (!supported) return;\n setBusy(true);\n try {\n const registration = await activeRegistration();\n const subscription = await registration.pushManager.getSubscription();\n if (subscription) {\n // The server first: a dropped device stops receiving even if the browser's\n // unsubscribe below fails.\n await latest.current.unregister(subscription.endpoint);\n await within(subscription.unsubscribe(), PUSH_TIMEOUT_MS, \"push_timeout\");\n }\n if (mounted.current) {\n setSubscribed(false);\n setForeignSubscription(false);\n setCurrentEndpoint(null);\n }\n announce();\n } finally {\n if (mounted.current) setBusy(false);\n }\n }, [supported, announce]);\n\n const sendTest = useCallback(() => latest.current.test(), []);\n\n return {\n supported,\n configured,\n installed,\n ios,\n permission,\n subscribed,\n foreignSubscription,\n currentEndpoint,\n busy,\n enable,\n disable,\n sendTest,\n };\n}\n"],"mappings":"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","names":[]}
@@ -78,8 +78,14 @@ export interface RhfFieldBaseProps<TFieldValues extends FieldValues = FieldValue
78
78
  label?: ReactNode;
79
79
  /** Standing advice under the field ("As printed on the card"), attached to the
80
80
  * control with `aria-describedby`. A `FieldHint` is its words at Large and on a
81
- * touch screen (§4, DUP-2), not a lone "?"; a `HelpPopover` stays a "?". */
81
+ * touch screen (§4, DUP-2), not a lone "?"; a `HelpPopover` stays a "?". Beside a
82
+ * `help` it is that caption at every size. */
82
83
  hint?: ReactNode;
84
+ /** Help the field is usable without — why, how to choose — behind the field's one
85
+ * "?" after the label: a `HelpPopover` named "About <label>" (round 0.36,
86
+ * docs/text-size-harmonization.md §4); pass a `HelpPopover` to name it yourself.
87
+ * `hint` stays the visible fact under the field. */
88
+ help?: ReactNode;
83
89
  /** Draws the label's required mark and sets `aria-required` where the control
84
90
  * takes it. Whether the field IS required is `rules`' or the resolver's to say. */
85
91
  required?: boolean;
@@ -137,7 +143,7 @@ export interface RhfFieldProps<TFieldValues extends FieldValues = FieldValues, T
137
143
  * )} />
138
144
  * ```
139
145
  */
140
- export declare function RhfField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, render, asControl, message, showLabel, }: RhfFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
146
+ export declare function RhfField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, render, asControl, message, showLabel, }: RhfFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
141
147
  type OwnInputProps = Omit<InputProps, "name" | "value" | "defaultValue" | "onChange" | "onBlur" | "ref" | "label" | "error" | "invalid" | "className" | "disabled" | "required" | "inputClassName"> & {
142
148
  /**
143
149
  * Classes for the `<input>` — `className` is the item's box (kastlan 42: a
@@ -150,14 +156,14 @@ type OwnInputProps = Omit<InputProps, "name" | "value" | "defaultValue" | "onCha
150
156
  };
151
157
  export type RhfTextFieldProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & OwnInputProps;
152
158
  /** A text {@link Input} — `type` for email, tel, password, url. Stores the string. */
153
- export declare function RhfTextField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, ...inputProps }: RhfTextFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
159
+ export declare function RhfTextField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, ...inputProps }: RhfTextFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
154
160
  type OwnTextareaProps = Omit<TextareaProps, "name" | "value" | "defaultValue" | "onChange" | "onBlur" | "ref" | "label" | "error" | "invalid" | "className" | "disabled" | "required"> & {
155
161
  /** Classes for the `<textarea>`. */
156
162
  inputClassName?: string;
157
163
  };
158
164
  export type RhfTextareaProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & OwnTextareaProps;
159
165
  /** A multi-line {@link Textarea}; takes `rows`. Stores the string. */
160
- export declare function RhfTextarea<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, inputClassName, ...areaProps }: RhfTextareaProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
166
+ export declare function RhfTextarea<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, inputClassName, ...areaProps }: RhfTextareaProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
161
167
  /** What a twin sets on its field itself — the value and its change, what the form
162
168
  * decides (`disabled`, `invalid`, the error, the ids) and what the shell draws (the
163
169
  * label, the hint, the item's `className`). Everything else of the field's passes
@@ -177,7 +183,7 @@ export type RhfNumberFieldProps<TFieldValues extends FieldValues = FieldValues,
177
183
  * `max`) number, committed on blur or Enter in the locale's decimal mark. Stores a
178
184
  * number, or `emptyValue` when emptied.
179
185
  */
180
- export declare function RhfNumberField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, emptyValue, nullable, ...numberProps }: RhfNumberFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
186
+ export declare function RhfNumberField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, emptyValue, nullable, ...numberProps }: RhfNumberFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
181
187
  export type RhfIntegerFieldProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfNumberFieldProps<TFieldValues, TName, TTransformed>;
182
188
  /**
183
189
  * {@link RhfNumberField} for a whole number — a floor, a room count, a year, a
@@ -212,7 +218,7 @@ export type RhfMoneyFieldProps<TFieldValues extends FieldValues = FieldValues, T
212
218
  * calculator ("1200+80" resolves on blur or Enter). Stores a number by default — see
213
219
  * `valueAs`.
214
220
  */
215
- export declare function RhfMoneyField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, ...amountProps }: RhfMoneyFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
221
+ export declare function RhfMoneyField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, ...amountProps }: RhfMoneyFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
216
222
  export type RhfDateFieldProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & Omit<DatePickerProps, "value" | "onChange" | "label" | "invalid" | "disabled" | "className" | "id" | "error"> & {
217
223
  /** Classes for the picker. Default `w-full`. */
218
224
  inputClassName?: string;
@@ -221,7 +227,7 @@ export type RhfDateFieldProps<TFieldValues extends FieldValues = FieldValues, TN
221
227
  emptyValue?: "" | null;
222
228
  };
223
229
  /** The kit's {@link DatePicker}, holding an ISO `"YYYY-MM-DD"` string. */
224
- export declare function RhfDateField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, inputClassName, emptyValue, ...pickerProps }: RhfDateFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
230
+ export declare function RhfDateField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, inputClassName, emptyValue, ...pickerProps }: RhfDateFieldProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
225
231
  type OwnDateRangeProps = Omit<DateRangePickerProps, "from" | "to" | "onChange" | "label" | "invalid" | "disabled" | "className" | "id" | "error">;
226
232
  export type RhfDateRangePickerProps<TFieldValues extends FieldValues = FieldValues, TFromName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TToName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = Omit<RhfFieldBaseProps<TFieldValues, TFromName, TTransformed>, "name" | "rules"> & OwnDateRangeProps & {
227
233
  /** The form field holding the range's first day, an ISO `"YYYY-MM-DD"`. */
@@ -277,7 +283,7 @@ export type RhfDateRangePickerProps<TFieldValues extends FieldValues = FieldValu
277
283
  * The common props (`label`, `hint`, `required`, `disabled`, `excludeWhenDisabled`,
278
284
  * `control`, `className`) apply to the pair; `rules` are per field.
279
285
  */
280
- export declare function RhfDateRangePicker<TFieldValues extends FieldValues = FieldValues, TFromName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TToName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ fromName, toName, control, fromRules, toRules, label, hint, required, disabled, excludeWhenDisabled, className, inputClassName, emptyValue, ...pickerProps }: RhfDateRangePickerProps<TFieldValues, TFromName, TToName, TTransformed>): import("react").JSX.Element;
286
+ export declare function RhfDateRangePicker<TFieldValues extends FieldValues = FieldValues, TFromName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TToName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ fromName, toName, control, fromRules, toRules, label, hint, help, required, disabled, excludeWhenDisabled, className, inputClassName, emptyValue, ...pickerProps }: RhfDateRangePickerProps<TFieldValues, TFromName, TToName, TTransformed>): import("react").JSX.Element;
281
287
  export type RhfTimeInputProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & Omit<TimeInputProps, "name" | "value" | "defaultValue" | "onChange" | "onValueChange" | "onBlur" | "label" | "error" | "invalid" | "className" | "disabled" | "required"> & {
282
288
  /** What a cleared time stores. Default `""`; `null` for a nullable schema. */
283
289
  emptyValue?: "" | null;
@@ -294,7 +300,7 @@ export type RhfTimeInputProps<TFieldValues extends FieldValues = FieldValues, TN
294
300
  * validation stays the schema's or `rules`'. `rules={{ validate: (v) =>
295
301
  * isTimeInRange(v, min, max) || "…" }}` says it with the same window.
296
302
  */
297
- export declare function RhfTimeInput<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, emptyValue, ...timeProps }: RhfTimeInputProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
303
+ export declare function RhfTimeInput<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, emptyValue, ...timeProps }: RhfTimeInputProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
298
304
  type OwnTextishProps<P> = Omit<P, "name" | "value" | "defaultValue" | "onChange" | "onValueChange" | "onBlur" | "label" | "error" | "invalid" | "className" | "disabled" | "required">;
299
305
  export type RhfIbanInputProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & OwnTextishProps<IbanInputProps>;
300
306
  /**
@@ -304,7 +310,7 @@ export type RhfIbanInputProps<TFieldValues extends FieldValues = FieldValues, TN
304
310
  * or `rules`') replaces them, as a caller's `error` does on the bare field. kastlan
305
311
  * asked for the field; it binds everything through react-hook-form.
306
312
  */
307
- export declare function RhfIbanInput<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, ...ibanProps }: RhfIbanInputProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
313
+ export declare function RhfIbanInput<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, ...ibanProps }: RhfIbanInputProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
308
314
  export type RhfPhoneInputProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & OwnTextishProps<PhoneInputProps>;
309
315
  /**
310
316
  * {@link PhoneInput} bound to one field, which stores E.164 when the number reads as
@@ -312,7 +318,7 @@ export type RhfPhoneInputProps<TFieldValues extends FieldValues = FieldValues, T
312
318
  * text until someone edits it. Validation (required, a pattern for E.164 only) is the
313
319
  * schema's or `rules`'.
314
320
  */
315
- export declare function RhfPhoneInput<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, ...phoneProps }: RhfPhoneInputProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
321
+ export declare function RhfPhoneInput<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, ...phoneProps }: RhfPhoneInputProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
316
322
  type OwnCountrySelectProps = Omit<CountrySelectProps<boolean>, "value" | "onChange" | "onBlur" | "label" | "hint" | "error" | "invalid" | "disabled" | "className" | "id" | "ref" | "clearable">;
317
323
  export type RhfCountrySelectProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & OwnCountrySelectProps & {
318
324
  /** Offer the picker's clear "×" (and Delete on the trigger) while a country is
@@ -346,7 +352,7 @@ export type RhfCountrySelectProps<TFieldValues extends FieldValues = FieldValues
346
352
  * preferred={["CH", "LI", "DE", "AT", "FR", "IT"]} rules={{ required: "Choose a country" }} />
347
353
  * ```
348
354
  */
349
- export declare function RhfCountrySelect<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, clearable, clearValue, selectClassName, labels, ...countryProps }: RhfCountrySelectProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
355
+ export declare function RhfCountrySelect<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, clearable, clearValue, selectClassName, labels, ...countryProps }: RhfCountrySelectProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
350
356
  type OwnMonthPickerProps = Omit<MonthPickerProps, "value" | "onChange" | "onBlur" | "label" | "hint" | "error" | "invalid" | "disabled" | "className" | "id" | "mode">;
351
357
  /** `mode` picks what the form stores, and `valueAsNumber` is only offered for a year. */
352
358
  type RhfMonthPickerMode = {
@@ -383,7 +389,7 @@ export type RhfMonthPickerProps<TFieldValues extends FieldValues = FieldValues,
383
389
  * min="2020" max="2029" rules={{ required: "Choose a year" }} />
384
390
  * ```
385
391
  */
386
- export declare function RhfMonthPicker<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, inputClassName, mode, valueAsNumber, ...pickerProps }: RhfMonthPickerProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
392
+ export declare function RhfMonthPicker<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, inputClassName, mode, valueAsNumber, ...pickerProps }: RhfMonthPickerProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
387
393
  export interface RhfSelectOption {
388
394
  value: string | number;
389
395
  label: ReactNode;
@@ -402,8 +408,9 @@ export type RhfSelectProps<TFieldValues extends FieldValues = FieldValues, TName
402
408
  selectClassName?: string;
403
409
  };
404
410
  /** A native {@link Select}, from `options` or `<option>` children. */
405
- export declare function RhfSelect<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, options, children, placeholder, valueAsNumber, selectClassName, ...selectProps }: RhfSelectProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
406
- export type RhfCheckboxProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & Omit<CheckboxProps, BoundByForm | "checked" | "defaultChecked" | "onCheckedChange" | "description">;
411
+ export declare function RhfSelect<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, options, children, placeholder, valueAsNumber, selectClassName, ...selectProps }: RhfSelectProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
412
+ export type RhfCheckboxProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = // No `help` (0.36): a box has no label line — its label sits beside it, inside the
413
+ Omit<RhfFieldBaseProps<TFieldValues, TName, TTransformed>, "help"> & Omit<CheckboxProps, BoundByForm | "checked" | "defaultChecked" | "onCheckedChange" | "description">;
407
414
  /**
408
415
  * The kit's {@link Checkbox}, label beside the box and `hint` under it (the
409
416
  * checkbox's own `description`). Stores a boolean. `required` is the native one here
@@ -451,7 +458,7 @@ export type RhfToggleGroupProps<TFieldValues extends FieldValues = FieldValues,
451
458
  * value that matches no option (an empty default) leaves nothing pressed; that the
452
459
  * field still needs answering is the schema's or `rules`' to say.
453
460
  */
454
- export declare function RhfToggleGroup<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, T extends string = string, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, ...groupProps }: RhfToggleGroupProps<TFieldValues, TName, T, TTransformed>): import("react").JSX.Element;
461
+ export declare function RhfToggleGroup<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, T extends string = string, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, ...groupProps }: RhfToggleGroupProps<TFieldValues, TName, T, TTransformed>): import("react").JSX.Element;
455
462
  export type RhfComboboxProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, V extends string | number = string | number, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & Omit<EntityComboboxProps<V>, BoundByForm | "id" | "clearValue"> & {
456
463
  /** What a clear stores — the picker's `clearValue`. Default `null`; `""` for a
457
464
  * schema that spells "no choice" as an empty string. */
@@ -472,7 +479,7 @@ export type RhfComboboxProps<TFieldValues extends FieldValues = FieldValues, TNa
472
479
  * placeholder. For the INLINE picker — a text input, the account field typed into —
473
480
  * see {@link RhfInlineEntityCombobox}.
474
481
  */
475
- export declare function RhfCombobox<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, V extends string | number = string | number, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, clearValue, comboClassName, ...comboProps }: RhfComboboxProps<TFieldValues, TName, V, TTransformed>): import("react").JSX.Element;
482
+ export declare function RhfCombobox<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, V extends string | number = string | number, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, clearValue, comboClassName, ...comboProps }: RhfComboboxProps<TFieldValues, TName, V, TTransformed>): import("react").JSX.Element;
476
483
  type OwnInlineEntityComboboxProps<V extends string | number> = Omit<InlineEntityComboboxProps<V, ComboClearValue>, "value" | "defaultValue" | "onChange" | "onBlur" | "label" | "hint" | "error" | "invalid" | "disabled" | "className" | "id" | "ref" | "clearValue">;
477
484
  export type RhfInlineEntityComboboxProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, V extends string | number = string | number, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & OwnInlineEntityComboboxProps<V> & {
478
485
  /** What a clear stores — emptying the text, or the "×" with `clearable`. Default
@@ -517,7 +524,7 @@ export type RhfInlineEntityComboboxProps<TFieldValues extends FieldValues = Fiel
517
524
  *
518
525
  * For the button-shaped picker with an async `loadOptions`, see {@link RhfCombobox}.
519
526
  */
520
- export declare function RhfInlineEntityCombobox<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, V extends string | number = string | number, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, clearValue, comboClassName, ...comboProps }: RhfInlineEntityComboboxProps<TFieldValues, TName, V, TTransformed>): import("react").JSX.Element;
527
+ export declare function RhfInlineEntityCombobox<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, V extends string | number = string | number, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, clearValue, comboClassName, ...comboProps }: RhfInlineEntityComboboxProps<TFieldValues, TName, V, TTransformed>): import("react").JSX.Element;
521
528
  export type RhfTextComboboxProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & Omit<ComboboxProps, BoundByForm | "id"> & {
522
529
  /** Classes for the combobox. */
523
530
  comboClassName?: string;
@@ -526,5 +533,5 @@ export type RhfTextComboboxProps<TFieldValues extends FieldValues = FieldValues,
526
533
  * The kit's free-text {@link Combobox}: type anything, or pick one of `options`.
527
534
  * Stores the string.
528
535
  */
529
- export declare function RhfTextCombobox<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, required, disabled, excludeWhenDisabled, className, comboClassName, ...comboProps }: RhfTextComboboxProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
536
+ export declare function RhfTextCombobox<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, label, hint, help, required, disabled, excludeWhenDisabled, className, comboClassName, ...comboProps }: RhfTextComboboxProps<TFieldValues, TName, TTransformed>): import("react").JSX.Element;
530
537
  export {};