@use-voltra/android 2.0.0 → 2.1.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 (81) hide show
  1. package/build/commonjs/index.js +20 -0
  2. package/build/commonjs/index.js.map +1 -1
  3. package/build/module/index.js +6 -0
  4. package/build/module/index.js.map +1 -1
  5. package/build/typescript/commonjs/index.d.ts +3 -0
  6. package/build/typescript/commonjs/index.d.ts.map +1 -1
  7. package/build/typescript/module/index.d.ts +3 -0
  8. package/build/typescript/module/index.d.ts.map +1 -1
  9. package/package.json +3 -2
  10. package/src/dynamic-colors.ts +33 -0
  11. package/src/index.ts +99 -0
  12. package/src/internal.ts +2 -0
  13. package/src/jsx/AreaMark.tsx +16 -0
  14. package/src/jsx/BarMark.tsx +18 -0
  15. package/src/jsx/Box.tsx +5 -0
  16. package/src/jsx/Button.tsx +5 -0
  17. package/src/jsx/Chart.tsx +123 -0
  18. package/src/jsx/CheckBox.tsx +5 -0
  19. package/src/jsx/CircleIconButton.tsx +14 -0
  20. package/src/jsx/CircularProgressIndicator.tsx +7 -0
  21. package/src/jsx/Column.tsx +5 -0
  22. package/src/jsx/FilledButton.tsx +14 -0
  23. package/src/jsx/Image.tsx +21 -0
  24. package/src/jsx/LazyColumn.tsx +5 -0
  25. package/src/jsx/LazyVerticalGrid.tsx +45 -0
  26. package/src/jsx/LineMark.tsx +17 -0
  27. package/src/jsx/LinearProgressIndicator.tsx +7 -0
  28. package/src/jsx/OutlineButton.tsx +14 -0
  29. package/src/jsx/PointMark.tsx +16 -0
  30. package/src/jsx/RadioButton.tsx +5 -0
  31. package/src/jsx/Row.tsx +5 -0
  32. package/src/jsx/RuleMark.tsx +15 -0
  33. package/src/jsx/Scaffold.tsx +5 -0
  34. package/src/jsx/SectorMark.tsx +17 -0
  35. package/src/jsx/Spacer.tsx +5 -0
  36. package/src/jsx/SquareIconButton.tsx +14 -0
  37. package/src/jsx/Switch.tsx +5 -0
  38. package/src/jsx/Text.tsx +10 -0
  39. package/src/jsx/TitleBar.tsx +18 -0
  40. package/src/jsx/baseProps.tsx +13 -0
  41. package/src/jsx/chart-types.ts +2 -0
  42. package/src/jsx/createVoltraComponent.ts +2 -0
  43. package/src/jsx/index.ts +1 -0
  44. package/src/jsx/primitives.ts +28 -0
  45. package/src/jsx/props/.generated +15 -0
  46. package/src/jsx/props/AndroidBox.ts +19 -0
  47. package/src/jsx/props/AndroidButton.ts +10 -0
  48. package/src/jsx/props/AndroidChart.ts +20 -0
  49. package/src/jsx/props/AndroidCheckBox.ts +20 -0
  50. package/src/jsx/props/AndroidCircleIconButton.ts +18 -0
  51. package/src/jsx/props/AndroidCircularProgressIndicator.ts +10 -0
  52. package/src/jsx/props/AndroidColumn.ts +12 -0
  53. package/src/jsx/props/AndroidFilledButton.ts +20 -0
  54. package/src/jsx/props/AndroidImage.ts +26 -0
  55. package/src/jsx/props/AndroidLazyColumn.ts +10 -0
  56. package/src/jsx/props/AndroidLazyVerticalGrid.ts +12 -0
  57. package/src/jsx/props/AndroidLinearProgressIndicator.ts +14 -0
  58. package/src/jsx/props/AndroidOutlineButton.ts +18 -0
  59. package/src/jsx/props/AndroidRadioButton.ts +22 -0
  60. package/src/jsx/props/AndroidRow.ts +12 -0
  61. package/src/jsx/props/AndroidScaffold.ts +12 -0
  62. package/src/jsx/props/AndroidSpacer.ts +7 -0
  63. package/src/jsx/props/AndroidSquareIconButton.ts +18 -0
  64. package/src/jsx/props/AndroidSwitch.ts +24 -0
  65. package/src/jsx/props/AndroidText.ts +14 -0
  66. package/src/jsx/props/AndroidTitleBar.ts +18 -0
  67. package/src/live-update/renderer.ts +36 -0
  68. package/src/live-update/types.ts +44 -0
  69. package/src/ongoing-notification/components.tsx +49 -0
  70. package/src/ongoing-notification/renderer.ts +360 -0
  71. package/src/ongoing-notification/types.ts +199 -0
  72. package/src/payload/component-ids.ts +89 -0
  73. package/src/preload-utils.ts +78 -0
  74. package/src/renderer/index.ts +6 -0
  75. package/src/renderer/renderer.ts +25 -0
  76. package/src/server.ts +19 -0
  77. package/src/styles/types.ts +114 -0
  78. package/src/types.ts +38 -0
  79. package/src/utils/index.ts +0 -0
  80. package/src/widgets/renderer.ts +90 -0
  81. package/src/widgets/types.ts +62 -0
@@ -0,0 +1,49 @@
1
+ import type { ComponentType } from 'react'
2
+
3
+ import type {
4
+ AndroidOngoingNotificationActionProps,
5
+ AndroidOngoingNotificationBigTextProps,
6
+ AndroidOngoingNotificationProgressProps,
7
+ } from './types.js'
8
+
9
+ export const ANDROID_ONGOING_NOTIFICATION_COMPONENT_TAG = Symbol.for('VOLTRA_ANDROID_ONGOING_NOTIFICATION_COMPONENT')
10
+
11
+ type AndroidOngoingNotificationComponentKind = 'progress' | 'bigText' | 'action'
12
+
13
+ type AndroidOngoingNotificationComponent<TProps extends Record<string, unknown>> = ComponentType<TProps> & {
14
+ displayName: string
15
+ [ANDROID_ONGOING_NOTIFICATION_COMPONENT_TAG]: AndroidOngoingNotificationComponentKind
16
+ }
17
+
18
+ const createAndroidOngoingNotificationComponent = <TProps extends Record<string, unknown>>(
19
+ displayName: string,
20
+ kind: AndroidOngoingNotificationComponentKind
21
+ ): AndroidOngoingNotificationComponent<TProps> => {
22
+ const Component = (_props: TProps) => null
23
+
24
+ Component.displayName = displayName
25
+ ;(Component as AndroidOngoingNotificationComponent<TProps>)[ANDROID_ONGOING_NOTIFICATION_COMPONENT_TAG] = kind
26
+
27
+ return Component as AndroidOngoingNotificationComponent<TProps>
28
+ }
29
+
30
+ export const Progress = createAndroidOngoingNotificationComponent<AndroidOngoingNotificationProgressProps>(
31
+ 'AndroidOngoingNotification.Progress',
32
+ 'progress'
33
+ )
34
+
35
+ export const BigText = createAndroidOngoingNotificationComponent<AndroidOngoingNotificationBigTextProps>(
36
+ 'AndroidOngoingNotification.BigText',
37
+ 'bigText'
38
+ )
39
+
40
+ export const Action = createAndroidOngoingNotificationComponent<AndroidOngoingNotificationActionProps>(
41
+ 'AndroidOngoingNotification.Action',
42
+ 'action'
43
+ )
44
+
45
+ export const AndroidOngoingNotification = {
46
+ Progress,
47
+ BigText,
48
+ Action,
49
+ } as const
@@ -0,0 +1,360 @@
1
+ import { Children, Fragment, isValidElement, type ReactElement, type ReactNode } from 'react'
2
+
3
+ import type { ImageSource } from '../jsx/Image.js'
4
+ import { getAndroidComponentId } from '../payload/component-ids.js'
5
+ import { ANDROID_ONGOING_NOTIFICATION_COMPONENT_TAG } from './components.js'
6
+ import type {
7
+ AndroidOngoingNotificationActionPayload,
8
+ AndroidOngoingNotificationActionProps,
9
+ AndroidOngoingNotificationBigTextPayload,
10
+ AndroidOngoingNotificationBigTextProps,
11
+ AndroidOngoingNotificationContent,
12
+ AndroidOngoingNotificationPayload,
13
+ AndroidOngoingNotificationProgressPayload,
14
+ AndroidOngoingNotificationProgressPoint,
15
+ AndroidOngoingNotificationProgressProps,
16
+ AndroidOngoingNotificationProgressSegment,
17
+ } from './types.js'
18
+
19
+ void getAndroidComponentId
20
+
21
+ const PAYLOAD_VERSION = 1 as const
22
+
23
+ const flattenChildren = (node: ReactNode): ReactNode[] => {
24
+ if (node === null || node === undefined || typeof node === 'boolean') {
25
+ return []
26
+ }
27
+
28
+ if (Array.isArray(node)) {
29
+ return node.flatMap((child) => flattenChildren(child))
30
+ }
31
+
32
+ return [node]
33
+ }
34
+
35
+ const getSingleRootElement = (content: ReactNode): ReactElement<Record<string, unknown>> => {
36
+ const children = flattenChildren(content)
37
+
38
+ if (children.length !== 1) {
39
+ throw new Error('[Voltra] [Android] Ongoing notification content must contain exactly one root element.')
40
+ }
41
+
42
+ const [root] = children
43
+
44
+ if (!isValidElement(root)) {
45
+ throw new Error(
46
+ '[Voltra] [Android] Ongoing notification content must be a valid AndroidOngoingNotification element.'
47
+ )
48
+ }
49
+
50
+ if (root.type === Fragment) {
51
+ return getSingleRootElement((root.props as { children?: ReactNode }).children)
52
+ }
53
+
54
+ return root as ReactElement<Record<string, unknown>>
55
+ }
56
+
57
+ const assertString = (value: unknown, propName: string): string => {
58
+ if (typeof value !== 'string' || value.length === 0) {
59
+ throw new Error(`[Voltra] [Android] Ongoing notification prop "${propName}" must be a non-empty string.`)
60
+ }
61
+
62
+ return value
63
+ }
64
+
65
+ const assertOptionalNonEmptyString = (value: unknown, propName: string): string | undefined => {
66
+ if (value === undefined) {
67
+ return undefined
68
+ }
69
+
70
+ if (typeof value !== 'string' || value.length === 0) {
71
+ throw new Error(
72
+ `[Voltra] [Android] Ongoing notification prop "${propName}" must be a non-empty string when provided.`
73
+ )
74
+ }
75
+
76
+ return value
77
+ }
78
+
79
+ const assertOptionalString = (value: unknown, propName: string): string | undefined => {
80
+ if (value === undefined) {
81
+ return undefined
82
+ }
83
+
84
+ if (typeof value !== 'string') {
85
+ throw new Error(`[Voltra] [Android] Ongoing notification prop "${propName}" must be a string.`)
86
+ }
87
+
88
+ return value
89
+ }
90
+
91
+ const isImageSource = (value: unknown): value is ImageSource => {
92
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
93
+ return false
94
+ }
95
+
96
+ const keys = Object.keys(value)
97
+ if (keys.length !== 1) {
98
+ return false
99
+ }
100
+
101
+ if ('assetName' in value) {
102
+ return typeof value.assetName === 'string' && value.assetName.length > 0
103
+ }
104
+
105
+ if ('base64' in value) {
106
+ return typeof value.base64 === 'string' && value.base64.length > 0
107
+ }
108
+
109
+ return false
110
+ }
111
+
112
+ const assertOptionalImageSource = (value: unknown, propName: string): ImageSource | undefined => {
113
+ if (value === undefined) {
114
+ return undefined
115
+ }
116
+
117
+ if (!isImageSource(value)) {
118
+ throw new Error(
119
+ `[Voltra] [Android] Ongoing notification prop "${propName}" must be an image source with either assetName or base64.`
120
+ )
121
+ }
122
+
123
+ return value
124
+ }
125
+
126
+ const assertBoolean = (value: unknown, propName: string): boolean | undefined => {
127
+ if (value === undefined) {
128
+ return undefined
129
+ }
130
+
131
+ if (typeof value !== 'boolean') {
132
+ throw new Error(`[Voltra] [Android] Ongoing notification prop "${propName}" must be a boolean.`)
133
+ }
134
+
135
+ return value
136
+ }
137
+
138
+ const assertFiniteNumber = (value: unknown, propName: string): number => {
139
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
140
+ throw new Error(`[Voltra] [Android] Ongoing notification prop "${propName}" must be a finite number.`)
141
+ }
142
+
143
+ return value
144
+ }
145
+
146
+ const assertOptionalColorString = (value: unknown, propName: string): string | undefined => {
147
+ if (value === undefined) {
148
+ return undefined
149
+ }
150
+
151
+ if (typeof value !== 'string' || value.trim().length === 0) {
152
+ throw new Error(`[Voltra] [Android] Ongoing notification prop "${propName}" must be a non-empty color string.`)
153
+ }
154
+
155
+ return value
156
+ }
157
+
158
+ const normalizeProgressSegments = (value: unknown): AndroidOngoingNotificationProgressSegment[] | undefined => {
159
+ if (value === undefined) {
160
+ return undefined
161
+ }
162
+
163
+ if (!Array.isArray(value)) {
164
+ throw new Error('[Voltra] [Android] Ongoing notification prop "segments" must be an array.')
165
+ }
166
+
167
+ return value.map((segment, index) => {
168
+ if (!segment || typeof segment !== 'object' || Array.isArray(segment)) {
169
+ throw new Error(`[Voltra] [Android] Ongoing notification prop "segments[${index}]" must be an object.`)
170
+ }
171
+
172
+ const length = assertFiniteNumber((segment as { length?: unknown }).length, `segments[${index}].length`)
173
+ if (length <= 0) {
174
+ throw new Error(
175
+ `[Voltra] [Android] Ongoing notification prop "segments[${index}].length" must be greater than 0.`
176
+ )
177
+ }
178
+
179
+ return {
180
+ length,
181
+ color: assertOptionalColorString((segment as { color?: unknown }).color, `segments[${index}].color`),
182
+ }
183
+ })
184
+ }
185
+
186
+ const normalizeProgressPoints = (value: unknown): AndroidOngoingNotificationProgressPoint[] | undefined => {
187
+ if (value === undefined) {
188
+ return undefined
189
+ }
190
+
191
+ if (!Array.isArray(value)) {
192
+ throw new Error('[Voltra] [Android] Ongoing notification prop "points" must be an array.')
193
+ }
194
+
195
+ return value.map((point, index) => {
196
+ if (!point || typeof point !== 'object' || Array.isArray(point)) {
197
+ throw new Error(`[Voltra] [Android] Ongoing notification prop "points[${index}]" must be an object.`)
198
+ }
199
+
200
+ const position = assertFiniteNumber((point as { position?: unknown }).position, `points[${index}].position`)
201
+ if (position < 0) {
202
+ throw new Error(
203
+ `[Voltra] [Android] Ongoing notification prop "points[${index}].position" must be greater than or equal to 0.`
204
+ )
205
+ }
206
+
207
+ return {
208
+ position,
209
+ color: assertOptionalColorString((point as { color?: unknown }).color, `points[${index}].color`),
210
+ }
211
+ })
212
+ }
213
+
214
+ const normalizeWhen = (value: unknown): number | undefined => {
215
+ if (value === undefined) {
216
+ return undefined
217
+ }
218
+
219
+ if (value instanceof Date) {
220
+ const timestamp = value.getTime()
221
+ if (!Number.isFinite(timestamp)) {
222
+ throw new Error('[Voltra] [Android] Ongoing notification prop "when" must be a valid Date or timestamp.')
223
+ }
224
+
225
+ return timestamp
226
+ }
227
+
228
+ if (typeof value === 'number' && Number.isFinite(value)) {
229
+ return value
230
+ }
231
+
232
+ throw new Error('[Voltra] [Android] Ongoing notification prop "when" must be a valid Date or timestamp.')
233
+ }
234
+
235
+ const getElementKind = (element: ReactElement<Record<string, unknown>>) => {
236
+ const elementType = element.type as unknown
237
+
238
+ return typeof elementType === 'function' || (typeof elementType === 'object' && elementType !== null)
239
+ ? (elementType as Record<PropertyKey, unknown>)[ANDROID_ONGOING_NOTIFICATION_COMPONENT_TAG]
240
+ : undefined
241
+ }
242
+
243
+ const normalizeActionPayload = (
244
+ props: AndroidOngoingNotificationActionProps
245
+ ): AndroidOngoingNotificationActionPayload => {
246
+ return {
247
+ title: assertString(props.title, 'title'),
248
+ deepLinkUrl: assertString(props.deepLinkUrl, 'deepLinkUrl'),
249
+ icon: assertOptionalImageSource(props.icon, 'icon'),
250
+ }
251
+ }
252
+
253
+ const normalizeActions = (value: ReactNode): AndroidOngoingNotificationActionPayload[] | undefined => {
254
+ const actions: AndroidOngoingNotificationActionPayload[] = []
255
+
256
+ Children.forEach(value, (child) => {
257
+ if (!isValidElement(child)) {
258
+ return
259
+ }
260
+
261
+ if (child.type === Fragment) {
262
+ const fragmentChildren = normalizeActions((child.props as { children?: ReactNode }).children)
263
+ if (fragmentChildren) {
264
+ actions.push(...fragmentChildren)
265
+ }
266
+ return
267
+ }
268
+
269
+ if (getElementKind(child as ReactElement<Record<string, unknown>>) !== 'action') {
270
+ return
271
+ }
272
+
273
+ actions.push(normalizeActionPayload(child.props as AndroidOngoingNotificationActionProps))
274
+ })
275
+
276
+ return actions.length > 0 ? actions : undefined
277
+ }
278
+
279
+ const normalizeProgressPayload = (
280
+ props: AndroidOngoingNotificationProgressProps
281
+ ): AndroidOngoingNotificationProgressPayload => {
282
+ const value = assertFiniteNumber(props.value, 'value')
283
+ const max = assertFiniteNumber(props.max, 'max')
284
+
285
+ if (max <= 0) {
286
+ throw new Error('[Voltra] [Android] Ongoing notification prop "max" must be greater than 0.')
287
+ }
288
+
289
+ if (value < 0 || value > max) {
290
+ throw new Error('[Voltra] [Android] Ongoing notification prop "value" must be between 0 and max.')
291
+ }
292
+
293
+ return {
294
+ v: PAYLOAD_VERSION,
295
+ kind: 'progress',
296
+ title: assertOptionalNonEmptyString(props.title, 'title'),
297
+ subText: assertOptionalString(props.subText, 'subText'),
298
+ text: assertOptionalString(props.text, 'text'),
299
+ value,
300
+ max,
301
+ indeterminate: assertBoolean(props.indeterminate, 'indeterminate'),
302
+ shortCriticalText: assertOptionalString(props.shortCriticalText, 'shortCriticalText'),
303
+ when: normalizeWhen(props.when),
304
+ chronometer: assertBoolean(props.chronometer, 'chronometer'),
305
+ largeIcon: assertOptionalImageSource(props.largeIcon, 'largeIcon'),
306
+ progressTrackerIcon: assertOptionalImageSource(props.progressTrackerIcon, 'progressTrackerIcon'),
307
+ progressStartIcon: assertOptionalImageSource(props.progressStartIcon, 'progressStartIcon'),
308
+ progressEndIcon: assertOptionalImageSource(props.progressEndIcon, 'progressEndIcon'),
309
+ segments: normalizeProgressSegments(props.segments),
310
+ points: normalizeProgressPoints(props.points),
311
+ actions: normalizeActions(props.children),
312
+ }
313
+ }
314
+
315
+ const normalizeBigTextPayload = (
316
+ props: AndroidOngoingNotificationBigTextProps
317
+ ): AndroidOngoingNotificationBigTextPayload => {
318
+ const text = assertString(props.text, 'text')
319
+
320
+ return {
321
+ v: PAYLOAD_VERSION,
322
+ kind: 'bigText',
323
+ title: assertOptionalNonEmptyString(props.title, 'title'),
324
+ subText: assertOptionalString(props.subText, 'subText'),
325
+ text,
326
+ bigText: assertOptionalString(props.bigText, 'bigText') ?? text,
327
+ shortCriticalText: assertOptionalString(props.shortCriticalText, 'shortCriticalText'),
328
+ when: normalizeWhen(props.when),
329
+ chronometer: assertBoolean(props.chronometer, 'chronometer'),
330
+ largeIcon: assertOptionalImageSource(props.largeIcon, 'largeIcon'),
331
+ actions: normalizeActions(props.children),
332
+ }
333
+ }
334
+
335
+ export const renderAndroidOngoingNotificationPayloadToJson = (
336
+ content: ReactNode
337
+ ): AndroidOngoingNotificationPayload => {
338
+ const element = getSingleRootElement(content)
339
+ const kind = getElementKind(element)
340
+
341
+ if (kind === 'progress') {
342
+ return normalizeProgressPayload(element.props as AndroidOngoingNotificationProgressProps)
343
+ }
344
+
345
+ if (kind === 'bigText') {
346
+ return normalizeBigTextPayload(element.props as AndroidOngoingNotificationBigTextProps)
347
+ }
348
+
349
+ throw new Error(
350
+ '[Voltra] [Android] Ongoing notification content must use AndroidOngoingNotification.Progress or AndroidOngoingNotification.BigText.'
351
+ )
352
+ }
353
+
354
+ export const renderAndroidOngoingNotificationPayload = (content: ReactNode): string => {
355
+ return JSON.stringify(renderAndroidOngoingNotificationPayloadToJson(content))
356
+ }
357
+
358
+ export const renderAndroidOngoingNotificationContent = (content: AndroidOngoingNotificationContent): string => {
359
+ return renderAndroidOngoingNotificationPayload(content)
360
+ }
@@ -0,0 +1,199 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import type { ImageSource } from '../jsx/Image.js'
4
+
5
+ export type AndroidOngoingNotificationFallbackBehavior = 'standard' | 'error'
6
+
7
+ export type AndroidOngoingNotificationCommonDisplayProps = {
8
+ title?: string
9
+ subText?: string
10
+ shortCriticalText?: string
11
+ when?: Date | number
12
+ chronometer?: boolean
13
+ }
14
+
15
+ export type AndroidOngoingNotificationProgressSegment = {
16
+ length: number
17
+ color?: string
18
+ }
19
+
20
+ export type AndroidOngoingNotificationProgressPoint = {
21
+ position: number
22
+ color?: string
23
+ }
24
+
25
+ export type AndroidOngoingNotificationActionProps = {
26
+ title: string
27
+ deepLinkUrl: string
28
+ icon?: ImageSource
29
+ }
30
+
31
+ export type AndroidOngoingNotificationActionPayload = {
32
+ title: string
33
+ deepLinkUrl: string
34
+ icon?: ImageSource
35
+ }
36
+
37
+ export type AndroidOngoingNotificationProgressProps = AndroidOngoingNotificationCommonDisplayProps & {
38
+ text?: string
39
+ value: number
40
+ max: number
41
+ indeterminate?: boolean
42
+ largeIcon?: ImageSource
43
+ progressTrackerIcon?: ImageSource
44
+ progressStartIcon?: ImageSource
45
+ progressEndIcon?: ImageSource
46
+ segments?: AndroidOngoingNotificationProgressSegment[]
47
+ points?: AndroidOngoingNotificationProgressPoint[]
48
+ children?: ReactNode
49
+ }
50
+
51
+ export type AndroidOngoingNotificationBigTextProps = AndroidOngoingNotificationCommonDisplayProps & {
52
+ text: string
53
+ bigText?: string
54
+ largeIcon?: ImageSource
55
+ children?: ReactNode
56
+ }
57
+
58
+ export type AndroidOngoingNotificationProgressPayload = {
59
+ v: 1
60
+ kind: 'progress'
61
+ title?: string
62
+ subText?: string
63
+ text?: string
64
+ value: number
65
+ max: number
66
+ indeterminate?: boolean
67
+ shortCriticalText?: string
68
+ when?: number
69
+ chronometer?: boolean
70
+ largeIcon?: ImageSource
71
+ progressTrackerIcon?: ImageSource
72
+ progressStartIcon?: ImageSource
73
+ progressEndIcon?: ImageSource
74
+ segments?: AndroidOngoingNotificationProgressSegment[]
75
+ points?: AndroidOngoingNotificationProgressPoint[]
76
+ actions?: AndroidOngoingNotificationActionPayload[]
77
+ }
78
+
79
+ export type AndroidOngoingNotificationBigTextPayload = {
80
+ v: 1
81
+ kind: 'bigText'
82
+ title?: string
83
+ subText?: string
84
+ text: string
85
+ bigText?: string
86
+ shortCriticalText?: string
87
+ when?: number
88
+ chronometer?: boolean
89
+ largeIcon?: ImageSource
90
+ actions?: AndroidOngoingNotificationActionPayload[]
91
+ }
92
+
93
+ export type AndroidOngoingNotificationPayload =
94
+ | AndroidOngoingNotificationProgressPayload
95
+ | AndroidOngoingNotificationBigTextPayload
96
+
97
+ export type AndroidOngoingNotificationContent = ReactNode
98
+
99
+ export type AndroidOngoingNotificationInput =
100
+ | AndroidOngoingNotificationContent
101
+ | AndroidOngoingNotificationPayload
102
+ | string
103
+
104
+ export type StartAndroidOngoingNotificationOptions = {
105
+ notificationId?: string
106
+ channelId: string
107
+ smallIcon?: string
108
+ deepLinkUrl?: string
109
+ requestPromotedOngoing?: boolean
110
+ fallbackBehavior?: AndroidOngoingNotificationFallbackBehavior
111
+ }
112
+
113
+ export type UpdateAndroidOngoingNotificationOptions = Omit<
114
+ Partial<StartAndroidOngoingNotificationOptions>,
115
+ 'notificationId'
116
+ >
117
+
118
+ export type UseAndroidOngoingNotificationOptions = StartAndroidOngoingNotificationOptions & {
119
+ autoStart?: boolean
120
+ autoUpdate?: boolean
121
+ }
122
+
123
+ export type AndroidOngoingNotificationCapabilities = {
124
+ apiLevel: number
125
+ notificationsEnabled: boolean
126
+ supportsPromotedNotifications: boolean
127
+ canPostPromotedNotifications: boolean
128
+ canRequestPromotedOngoing: boolean
129
+ }
130
+
131
+ export type AndroidOngoingNotificationStatus = {
132
+ isActive: boolean
133
+ isDismissed: boolean
134
+ isPromoted?: boolean
135
+ hasPromotableCharacteristics?: boolean
136
+ }
137
+
138
+ export type AndroidOngoingNotificationStartResult =
139
+ | {
140
+ ok: true
141
+ notificationId: string
142
+ action: 'started'
143
+ reason?: undefined
144
+ }
145
+ | {
146
+ ok: false
147
+ notificationId: string
148
+ action?: undefined
149
+ reason: 'already_exists'
150
+ }
151
+
152
+ export type AndroidOngoingNotificationUpdateResult =
153
+ | {
154
+ ok: true
155
+ notificationId: string
156
+ action: 'updated'
157
+ reason?: undefined
158
+ }
159
+ | {
160
+ ok: false
161
+ notificationId: string
162
+ action?: undefined
163
+ reason: 'not_found' | 'dismissed'
164
+ }
165
+
166
+ export type AndroidOngoingNotificationUpsertResult =
167
+ | {
168
+ ok: true
169
+ notificationId: string
170
+ action: 'started' | 'updated'
171
+ reason?: undefined
172
+ }
173
+ | {
174
+ ok: false
175
+ notificationId: string
176
+ action?: undefined
177
+ reason: 'already_exists' | 'dismissed'
178
+ }
179
+
180
+ export type AndroidOngoingNotificationStopResult =
181
+ | {
182
+ ok: true
183
+ notificationId: string
184
+ action: 'stopped'
185
+ reason?: undefined
186
+ }
187
+ | {
188
+ ok: false
189
+ notificationId: string
190
+ action?: undefined
191
+ reason: 'not_found'
192
+ }
193
+
194
+ export type UseAndroidOngoingNotificationResult = {
195
+ start: (options?: Partial<StartAndroidOngoingNotificationOptions>) => Promise<AndroidOngoingNotificationStartResult>
196
+ update: (options?: UpdateAndroidOngoingNotificationOptions) => Promise<AndroidOngoingNotificationUpdateResult>
197
+ end: () => Promise<AndroidOngoingNotificationStopResult>
198
+ isActive: boolean
199
+ }
@@ -0,0 +1,89 @@
1
+ /* eslint-disable */
2
+ // 🤖 AUTO-GENERATED from data/components.json
3
+ // DO NOT EDIT MANUALLY - Changes will be overwritten
4
+ // Schema version: 1.0.0
5
+
6
+ /**
7
+ * Mapping from Android component name to numeric ID
8
+ * Component IDs are assigned sequentially based on order in components.json (0-indexed)
9
+ */
10
+ export const ANDROID_COMPONENT_NAME_TO_ID: Record<string, number> = {
11
+ AndroidFilledButton: 0,
12
+ AndroidImage: 1,
13
+ AndroidSwitch: 2,
14
+ AndroidCheckBox: 3,
15
+ AndroidRadioButton: 4,
16
+ AndroidBox: 5,
17
+ AndroidButton: 6,
18
+ AndroidCircleIconButton: 7,
19
+ AndroidCircularProgressIndicator: 8,
20
+ AndroidColumn: 9,
21
+ AndroidLazyColumn: 10,
22
+ AndroidLazyVerticalGrid: 11,
23
+ AndroidLinearProgressIndicator: 12,
24
+ AndroidOutlineButton: 13,
25
+ AndroidRow: 14,
26
+ AndroidScaffold: 15,
27
+ AndroidSpacer: 16,
28
+ AndroidSquareIconButton: 17,
29
+ AndroidText: 18,
30
+ AndroidTitleBar: 19,
31
+ AndroidChart: 20,
32
+ }
33
+
34
+ /**
35
+ * Mapping from numeric ID to Android component name
36
+ */
37
+ export const ANDROID_COMPONENT_ID_TO_NAME: Record<number, string> = {
38
+ 0: 'AndroidFilledButton',
39
+ 1: 'AndroidImage',
40
+ 2: 'AndroidSwitch',
41
+ 3: 'AndroidCheckBox',
42
+ 4: 'AndroidRadioButton',
43
+ 5: 'AndroidBox',
44
+ 6: 'AndroidButton',
45
+ 7: 'AndroidCircleIconButton',
46
+ 8: 'AndroidCircularProgressIndicator',
47
+ 9: 'AndroidColumn',
48
+ 10: 'AndroidLazyColumn',
49
+ 11: 'AndroidLazyVerticalGrid',
50
+ 12: 'AndroidLinearProgressIndicator',
51
+ 13: 'AndroidOutlineButton',
52
+ 14: 'AndroidRow',
53
+ 15: 'AndroidScaffold',
54
+ 16: 'AndroidSpacer',
55
+ 17: 'AndroidSquareIconButton',
56
+ 18: 'AndroidText',
57
+ 19: 'AndroidTitleBar',
58
+ 20: 'AndroidChart',
59
+ }
60
+
61
+ /**
62
+ * Get Android component ID from name
63
+ * @throws Error if component name is not found
64
+ */
65
+ export function getAndroidComponentId(name: string): number {
66
+ const id = ANDROID_COMPONENT_NAME_TO_ID[name]
67
+ if (id === undefined) {
68
+ throw new Error(
69
+ `Unknown Android component name: "${name}". Available components: ${Object.keys(
70
+ ANDROID_COMPONENT_NAME_TO_ID
71
+ ).join(', ')}`
72
+ )
73
+ }
74
+ return id
75
+ }
76
+
77
+ /**
78
+ * Get Android component name from ID
79
+ * @throws Error if component ID is not found
80
+ */
81
+ export function getAndroidComponentName(id: number): string {
82
+ const name = ANDROID_COMPONENT_ID_TO_NAME[id]
83
+ if (name === undefined) {
84
+ throw new Error(
85
+ `Unknown Android component ID: ${id}. Valid IDs: 0-${Object.keys(ANDROID_COMPONENT_ID_TO_NAME).length - 1}`
86
+ )
87
+ }
88
+ return name
89
+ }