@planningcenter/chat-react-native 3.15.0-rc.0 → 3.15.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/conversations/conversation_actions.js +1 -1
- package/build/components/conversations/conversation_actions.js.map +1 -1
- package/build/components/conversations/conversation_preview.d.ts.map +1 -1
- package/build/components/conversations/conversation_preview.js +9 -5
- package/build/components/conversations/conversation_preview.js.map +1 -1
- package/build/components/conversations/mute_indicator.d.ts.map +1 -1
- package/build/components/conversations/mute_indicator.js +3 -1
- package/build/components/conversations/mute_indicator.js.map +1 -1
- package/build/components/conversations/swipeable_toggle_button.d.ts.map +1 -1
- package/build/components/conversations/swipeable_toggle_button.js +6 -3
- package/build/components/conversations/swipeable_toggle_button.js.map +1 -1
- package/build/components/conversations/unread_count_badge.js +9 -6
- package/build/components/conversations/unread_count_badge.js.map +1 -1
- package/build/components/display/action_button.d.ts.map +1 -1
- package/build/components/display/action_button.js +2 -4
- package/build/components/display/action_button.js.map +1 -1
- package/build/components/display/avatar.d.ts +3 -1
- package/build/components/display/avatar.d.ts.map +1 -1
- package/build/components/display/avatar.js +2 -2
- package/build/components/display/avatar.js.map +1 -1
- package/build/components/display/avatar_group.d.ts +3 -1
- package/build/components/display/avatar_group.d.ts.map +1 -1
- package/build/components/display/avatar_group.js +2 -2
- package/build/components/display/avatar_group.js.map +1 -1
- package/build/components/display/badge.d.ts +5 -1
- package/build/components/display/badge.d.ts.map +1 -1
- package/build/components/display/badge.js +2 -2
- package/build/components/display/badge.js.map +1 -1
- package/build/components/display/icon.d.ts +26 -13
- package/build/components/display/icon.d.ts.map +1 -1
- package/build/components/display/icon.js +0 -12
- package/build/components/display/icon.js.map +1 -1
- package/build/components/display/index.d.ts +1 -0
- package/build/components/display/index.d.ts.map +1 -1
- package/build/components/display/index.js +1 -0
- package/build/components/display/index.js.map +1 -1
- package/build/components/display/pressable_row.d.ts +14 -0
- package/build/components/display/pressable_row.d.ts.map +1 -0
- package/build/components/display/pressable_row.js +65 -0
- package/build/components/display/pressable_row.js.map +1 -0
- package/build/components/display/toggle_button.d.ts +3 -1
- package/build/components/display/toggle_button.d.ts.map +1 -1
- package/build/components/display/toggle_button.js +1 -1
- package/build/components/display/toggle_button.js.map +1 -1
- package/build/components/primitive/avatar_primitive.d.ts +2 -0
- package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
- package/build/components/primitive/avatar_primitive.js +20 -19
- package/build/components/primitive/avatar_primitive.js.map +1 -1
- package/build/components/primitive/form_sheet.d.ts +3 -2
- package/build/components/primitive/form_sheet.d.ts.map +1 -1
- package/build/components/primitive/form_sheet.js +5 -3
- package/build/components/primitive/form_sheet.js.map +1 -1
- package/build/hooks/index.d.ts +1 -0
- package/build/hooks/index.d.ts.map +1 -1
- package/build/hooks/index.js +1 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/use_api.d.ts +1 -1
- package/build/hooks/use_api.d.ts.map +1 -1
- package/build/hooks/use_api.js.map +1 -1
- package/build/hooks/use_api_client.d.ts +1 -1
- package/build/hooks/use_api_client.d.ts.map +1 -1
- package/build/hooks/use_api_client.js +1 -1
- package/build/hooks/use_api_client.js.map +1 -1
- package/build/hooks/use_app_name.d.ts +3 -0
- package/build/hooks/use_app_name.d.ts.map +1 -0
- package/build/hooks/use_app_name.js +12 -0
- package/build/hooks/use_app_name.js.map +1 -0
- package/build/hooks/use_async_storage.d.ts +1 -1
- package/build/hooks/use_async_storage.d.ts.map +1 -1
- package/build/hooks/use_async_storage.js +6 -5
- package/build/hooks/use_async_storage.js.map +1 -1
- package/build/hooks/use_report_bug_action.d.ts +1 -1
- package/build/hooks/use_report_bug_action.d.ts.map +1 -1
- package/build/hooks/use_report_bug_action.js +1 -9
- package/build/hooks/use_report_bug_action.js.map +1 -1
- package/build/hooks/use_scalable_number_of_lines.d.ts +2 -0
- package/build/hooks/use_scalable_number_of_lines.d.ts.map +1 -0
- package/build/hooks/use_scalable_number_of_lines.js +9 -0
- package/build/hooks/use_scalable_number_of_lines.js.map +1 -0
- package/build/hooks/use_suspense_api.d.ts +1 -1
- package/build/hooks/use_suspense_api.d.ts.map +1 -1
- package/build/hooks/use_suspense_api.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/navigation/index.d.ts +20 -5
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +23 -15
- package/build/navigation/index.js.map +1 -1
- package/build/polyfills/events/CustomEvent.d.ts +21 -0
- package/build/polyfills/events/CustomEvent.d.ts.map +1 -0
- package/build/polyfills/events/CustomEvent.js +22 -0
- package/build/polyfills/events/CustomEvent.js.map +1 -0
- package/build/polyfills/events/Event.d.ts +49 -0
- package/build/polyfills/events/Event.d.ts.map +1 -0
- package/build/polyfills/events/Event.js +125 -0
- package/build/polyfills/events/Event.js.map +1 -0
- package/build/polyfills/events/EventHandlerAttributes.d.ts +8 -0
- package/build/polyfills/events/EventHandlerAttributes.d.ts.map +1 -0
- package/build/polyfills/events/EventHandlerAttributes.js +46 -0
- package/build/polyfills/events/EventHandlerAttributes.js.map +1 -0
- package/build/polyfills/events/EventTarget.d.ts +33 -0
- package/build/polyfills/events/EventTarget.d.ts.map +1 -0
- package/build/polyfills/events/EventTarget.js +238 -0
- package/build/polyfills/events/EventTarget.js.map +1 -0
- package/build/polyfills/events/internals/EventInternals.d.ts +30 -0
- package/build/polyfills/events/internals/EventInternals.d.ts.map +1 -0
- package/build/polyfills/events/internals/EventInternals.js +76 -0
- package/build/polyfills/events/internals/EventInternals.js.map +1 -0
- package/build/polyfills/events/internals/EventTargetInternals.d.ts +9 -0
- package/build/polyfills/events/internals/EventTargetInternals.d.ts.map +1 -0
- package/build/polyfills/events/internals/EventTargetInternals.js +11 -0
- package/build/polyfills/events/internals/EventTargetInternals.js.map +1 -0
- package/build/polyfills/webidl/PlatformObjects.d.ts +31 -0
- package/build/polyfills/webidl/PlatformObjects.d.ts.map +1 -0
- package/build/polyfills/webidl/PlatformObjects.js +39 -0
- package/build/polyfills/webidl/PlatformObjects.js.map +1 -0
- package/build/screens/bug_report_screen.d.ts.map +1 -1
- package/build/screens/bug_report_screen.js +62 -57
- package/build/screens/bug_report_screen.js.map +1 -1
- package/build/screens/conversation_filters/components/conversation_filters.js +9 -7
- package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
- package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
- package/build/screens/conversation_filters/components/rows.js +50 -31
- package/build/screens/conversation_filters/components/rows.js.map +1 -1
- package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
- package/build/screens/conversations/components/list_header_component.js +2 -2
- package/build/screens/conversations/components/list_header_component.js.map +1 -1
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js +6 -6
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/screens/design_system_screen.js +1 -1
- package/build/screens/design_system_screen.js.map +1 -1
- package/build/screens/get_help_screen.d.ts +5 -0
- package/build/screens/get_help_screen.d.ts.map +1 -0
- package/build/screens/get_help_screen.js +94 -0
- package/build/screens/get_help_screen.js.map +1 -0
- package/build/screens/message_actions_screen.d.ts +1 -1
- package/build/screens/message_actions_screen.d.ts.map +1 -1
- package/build/screens/message_actions_screen.js +14 -11
- package/build/screens/message_actions_screen.js.map +1 -1
- package/build/utils/client/index.d.ts +1 -0
- package/build/utils/client/index.d.ts.map +1 -1
- package/build/utils/client/index.js +1 -0
- package/build/utils/client/index.js.map +1 -1
- package/build/utils/client/types.d.ts +61 -0
- package/build/utils/client/types.d.ts.map +1 -0
- package/build/utils/client/types.js +2 -0
- package/build/utils/client/types.js.map +1 -0
- package/build/utils/styles.d.ts +1 -1
- package/build/utils/styles.js +1 -1
- package/build/utils/styles.js.map +1 -1
- package/build/utils/theme.d.ts +1 -0
- package/build/utils/theme.d.ts.map +1 -1
- package/build/utils/theme.js +2 -0
- package/build/utils/theme.js.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/event-polyfill.test.ts +314 -0
- package/src/components/conversations/conversation_actions.tsx +1 -1
- package/src/components/conversations/conversation_preview.tsx +15 -4
- package/src/components/conversations/mute_indicator.tsx +9 -1
- package/src/components/conversations/swipeable_toggle_button.tsx +18 -3
- package/src/components/conversations/unread_count_badge.tsx +9 -6
- package/src/components/display/action_button.tsx +3 -4
- package/src/components/display/avatar.tsx +5 -1
- package/src/components/display/avatar_group.tsx +5 -1
- package/src/components/display/badge.tsx +6 -1
- package/src/components/display/icon.tsx +17 -14
- package/src/components/display/index.ts +1 -0
- package/src/components/display/pressable_row.tsx +103 -0
- package/src/components/display/toggle_button.tsx +12 -1
- package/src/components/primitive/avatar_primitive.tsx +35 -19
- package/src/components/primitive/form_sheet.tsx +33 -5
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use_api.ts +1 -1
- package/src/hooks/use_api_client.ts +2 -2
- package/src/hooks/use_app_name.ts +17 -0
- package/src/hooks/use_async_storage.ts +8 -5
- package/src/hooks/use_report_bug_action.ts +2 -10
- package/src/hooks/use_scalable_number_of_lines.ts +10 -0
- package/src/hooks/use_suspense_api.ts +1 -1
- package/src/index.tsx +2 -0
- package/src/navigation/index.tsx +38 -25
- package/src/polyfills/events/CustomEvent.ts +32 -0
- package/src/polyfills/events/Event.ts +186 -0
- package/src/polyfills/events/EventHandlerAttributes.ts +67 -0
- package/src/polyfills/events/EventTarget.ts +360 -0
- package/src/polyfills/events/README.md +1 -0
- package/src/polyfills/events/internals/EventInternals.ts +95 -0
- package/src/polyfills/events/internals/EventTargetInternals.ts +16 -0
- package/src/polyfills/webidl/PlatformObjects.ts +50 -0
- package/src/screens/bug_report_screen.tsx +79 -67
- package/src/screens/conversation_filters/components/conversation_filters.tsx +10 -7
- package/src/screens/conversation_filters/components/rows.tsx +63 -50
- package/src/screens/conversations/components/list_header_component.tsx +3 -1
- package/src/screens/conversations/conversations_screen.tsx +8 -6
- package/src/screens/design_system_screen.tsx +1 -1
- package/src/screens/get_help_screen.tsx +131 -0
- package/src/screens/message_actions_screen.tsx +34 -12
- package/src/utils/client/index.ts +1 -0
- package/src/utils/styles.ts +1 -1
- package/src/utils/theme.ts +3 -0
- /package/src/utils/client/{types.d.ts → types.ts} +0 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Event/CustomEvent/EventTarget polyfills
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import Event from '../polyfills/events/Event'
|
|
6
|
+
import EventTarget from '../polyfills/events/EventTarget'
|
|
7
|
+
import { CustomEvent } from '../polyfills/events/CustomEvent'
|
|
8
|
+
|
|
9
|
+
// Set up global polyfill for tests
|
|
10
|
+
;(global as any).Event = Event
|
|
11
|
+
;(global as any).CustomEvent = CustomEvent
|
|
12
|
+
|
|
13
|
+
describe('Event Polyfill', () => {
|
|
14
|
+
describe('Event', () => {
|
|
15
|
+
it('should create a basic event', () => {
|
|
16
|
+
const event = new Event('test')
|
|
17
|
+
expect(event.type).toBe('test')
|
|
18
|
+
expect(event.bubbles).toBe(false)
|
|
19
|
+
expect(event.cancelable).toBe(false)
|
|
20
|
+
expect(event.composed).toBe(false)
|
|
21
|
+
expect(event.defaultPrevented).toBe(false)
|
|
22
|
+
expect(event.isTrusted).toBe(false)
|
|
23
|
+
expect(event.eventPhase).toBe(Event.NONE)
|
|
24
|
+
expect(typeof event.timeStamp).toBe('number')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('should create an event with options', () => {
|
|
28
|
+
const event = new Event('test', {
|
|
29
|
+
bubbles: true,
|
|
30
|
+
cancelable: true,
|
|
31
|
+
composed: true,
|
|
32
|
+
})
|
|
33
|
+
expect(event.bubbles).toBe(true)
|
|
34
|
+
expect(event.cancelable).toBe(true)
|
|
35
|
+
expect(event.composed).toBe(true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should have correct phase constants', () => {
|
|
39
|
+
expect(Event.NONE).toBe(0)
|
|
40
|
+
expect(Event.CAPTURING_PHASE).toBe(1)
|
|
41
|
+
expect(Event.AT_TARGET).toBe(2)
|
|
42
|
+
expect(Event.BUBBLING_PHASE).toBe(3)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should prevent default when cancelable', () => {
|
|
46
|
+
const event = new Event('test', { cancelable: true })
|
|
47
|
+
expect(event.defaultPrevented).toBe(false)
|
|
48
|
+
event.preventDefault()
|
|
49
|
+
expect(event.defaultPrevented).toBe(true)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should not prevent default when not cancelable', () => {
|
|
53
|
+
const event = new Event('test', { cancelable: false })
|
|
54
|
+
event.preventDefault()
|
|
55
|
+
expect(event.defaultPrevented).toBe(false)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should support stopPropagation', () => {
|
|
59
|
+
const event = new Event('test')
|
|
60
|
+
// No error thrown - internal flags are set
|
|
61
|
+
event.stopPropagation()
|
|
62
|
+
event.stopImmediatePropagation()
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
describe('CustomEvent', () => {
|
|
67
|
+
it('should create a custom event with detail', () => {
|
|
68
|
+
const detail = { foo: 'bar', count: 42 }
|
|
69
|
+
const event = new CustomEvent('custom', { detail })
|
|
70
|
+
expect(event.type).toBe('custom')
|
|
71
|
+
expect(event.detail).toEqual(detail)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('should inherit from Event', () => {
|
|
75
|
+
const event = new CustomEvent('custom', {
|
|
76
|
+
bubbles: true,
|
|
77
|
+
cancelable: true,
|
|
78
|
+
detail: 'test',
|
|
79
|
+
})
|
|
80
|
+
expect(event instanceof Event).toBe(true)
|
|
81
|
+
expect(event.bubbles).toBe(true)
|
|
82
|
+
expect(event.cancelable).toBe(true)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('should handle undefined detail', () => {
|
|
86
|
+
const event = new CustomEvent('custom')
|
|
87
|
+
expect(event.detail).toBeUndefined()
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('EventTarget', () => {
|
|
92
|
+
let target: EventTarget
|
|
93
|
+
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
target = new EventTarget()
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('should add and remove event listeners', () => {
|
|
99
|
+
const listener = jest.fn()
|
|
100
|
+
target.addEventListener('test', listener)
|
|
101
|
+
|
|
102
|
+
const event = new Event('test')
|
|
103
|
+
const result = target.dispatchEvent(event)
|
|
104
|
+
|
|
105
|
+
expect(listener).toHaveBeenCalledWith(event)
|
|
106
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
107
|
+
expect(result).toBe(true) // not prevented
|
|
108
|
+
|
|
109
|
+
target.removeEventListener('test', listener)
|
|
110
|
+
target.dispatchEvent(new Event('test'))
|
|
111
|
+
expect(listener).toHaveBeenCalledTimes(1) // not called again
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('should handle multiple listeners for the same event', () => {
|
|
115
|
+
const listener1 = jest.fn()
|
|
116
|
+
const listener2 = jest.fn()
|
|
117
|
+
|
|
118
|
+
target.addEventListener('test', listener1)
|
|
119
|
+
target.addEventListener('test', listener2)
|
|
120
|
+
|
|
121
|
+
target.dispatchEvent(new Event('test'))
|
|
122
|
+
|
|
123
|
+
expect(listener1).toHaveBeenCalledTimes(1)
|
|
124
|
+
expect(listener2).toHaveBeenCalledTimes(1)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('should handle once option', () => {
|
|
128
|
+
const listener = jest.fn()
|
|
129
|
+
target.addEventListener('test', listener, { once: true })
|
|
130
|
+
|
|
131
|
+
target.dispatchEvent(new Event('test'))
|
|
132
|
+
target.dispatchEvent(new Event('test'))
|
|
133
|
+
|
|
134
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('should handle capture option', () => {
|
|
138
|
+
const listener = jest.fn()
|
|
139
|
+
target.addEventListener('test', listener, { capture: true })
|
|
140
|
+
|
|
141
|
+
target.dispatchEvent(new Event('test'))
|
|
142
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
143
|
+
|
|
144
|
+
target.removeEventListener('test', listener, { capture: true })
|
|
145
|
+
target.dispatchEvent(new Event('test'))
|
|
146
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('should handle passive option', () => {
|
|
150
|
+
const listener = jest.fn()
|
|
151
|
+
target.addEventListener('test', listener, { passive: true })
|
|
152
|
+
|
|
153
|
+
target.dispatchEvent(new Event('test'))
|
|
154
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('should handle object listeners with handleEvent', () => {
|
|
158
|
+
const listener = {
|
|
159
|
+
handleEvent: jest.fn(),
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
target.addEventListener('test', listener)
|
|
163
|
+
target.dispatchEvent(new Event('test'))
|
|
164
|
+
|
|
165
|
+
expect(listener.handleEvent).toHaveBeenCalledTimes(1)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('should return false when event is prevented', () => {
|
|
169
|
+
const listener = (event: Event) => {
|
|
170
|
+
event.preventDefault()
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
target.addEventListener('test', listener)
|
|
174
|
+
const event = new Event('test', { cancelable: true })
|
|
175
|
+
const result = target.dispatchEvent(event)
|
|
176
|
+
|
|
177
|
+
expect(result).toBe(false)
|
|
178
|
+
expect(event.defaultPrevented).toBe(true)
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('should set event properties during dispatch', () => {
|
|
182
|
+
let capturedEvent: Event | null = null
|
|
183
|
+
|
|
184
|
+
const listener = (event: Event) => {
|
|
185
|
+
capturedEvent = event
|
|
186
|
+
expect(event.target).toBe(target)
|
|
187
|
+
expect(event.currentTarget).toBe(target)
|
|
188
|
+
expect(event.eventPhase).toBe(Event.AT_TARGET)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
target.addEventListener('test', listener)
|
|
192
|
+
target.dispatchEvent(new Event('test'))
|
|
193
|
+
|
|
194
|
+
expect(capturedEvent).not.toBeNull()
|
|
195
|
+
// After dispatch, these should be reset
|
|
196
|
+
expect(capturedEvent!.currentTarget).toBeNull()
|
|
197
|
+
expect(capturedEvent!.eventPhase).toBe(Event.NONE)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('should handle bubbling events', () => {
|
|
201
|
+
const listener = jest.fn()
|
|
202
|
+
target.addEventListener('test', listener)
|
|
203
|
+
|
|
204
|
+
const bubblingEvent = new Event('test', { bubbles: true })
|
|
205
|
+
target.dispatchEvent(bubblingEvent)
|
|
206
|
+
|
|
207
|
+
expect(listener).toHaveBeenCalledWith(bubblingEvent)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('should handle error in listener gracefully', () => {
|
|
211
|
+
const errorListener = () => {
|
|
212
|
+
throw new Error('Test error')
|
|
213
|
+
}
|
|
214
|
+
const normalListener = jest.fn()
|
|
215
|
+
|
|
216
|
+
// Mock console.error to avoid test output noise
|
|
217
|
+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation()
|
|
218
|
+
|
|
219
|
+
target.addEventListener('test', errorListener)
|
|
220
|
+
target.addEventListener('test', normalListener)
|
|
221
|
+
|
|
222
|
+
target.dispatchEvent(new Event('test'))
|
|
223
|
+
|
|
224
|
+
expect(normalListener).toHaveBeenCalledTimes(1)
|
|
225
|
+
expect(consoleErrorSpy).toHaveBeenCalled()
|
|
226
|
+
|
|
227
|
+
consoleErrorSpy.mockRestore()
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('should ignore null listeners', () => {
|
|
231
|
+
// Should not throw
|
|
232
|
+
target.addEventListener('test', null)
|
|
233
|
+
target.removeEventListener('test', null)
|
|
234
|
+
target.dispatchEvent(new Event('test'))
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('should handle composed path', () => {
|
|
238
|
+
let composedPath: readonly EventTarget[] | null = null
|
|
239
|
+
|
|
240
|
+
const listener = (event: Event) => {
|
|
241
|
+
composedPath = event.composedPath()
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
target.addEventListener('test', listener)
|
|
245
|
+
target.dispatchEvent(new Event('test'))
|
|
246
|
+
|
|
247
|
+
expect(composedPath).toEqual([target])
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
it('should prevent duplicate listeners', () => {
|
|
251
|
+
const listener = jest.fn()
|
|
252
|
+
|
|
253
|
+
target.addEventListener('test', listener)
|
|
254
|
+
target.addEventListener('test', listener) // Same listener
|
|
255
|
+
|
|
256
|
+
target.dispatchEvent(new Event('test'))
|
|
257
|
+
expect(listener).toHaveBeenCalledTimes(1) // Only called once
|
|
258
|
+
})
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
describe('Event flow integration', () => {
|
|
262
|
+
it('should work with CustomEvent dispatch', () => {
|
|
263
|
+
const target = new EventTarget()
|
|
264
|
+
const listener = jest.fn()
|
|
265
|
+
const detail = { message: 'hello' }
|
|
266
|
+
|
|
267
|
+
target.addEventListener('custom', listener)
|
|
268
|
+
|
|
269
|
+
const event = new CustomEvent('custom', {
|
|
270
|
+
detail,
|
|
271
|
+
bubbles: true,
|
|
272
|
+
cancelable: true,
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
const result = target.dispatchEvent(event)
|
|
276
|
+
|
|
277
|
+
expect(listener).toHaveBeenCalledWith(event)
|
|
278
|
+
expect(listener.mock.calls[0][0].detail).toEqual(detail)
|
|
279
|
+
expect(result).toBe(true)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it('should handle stopImmediatePropagation', () => {
|
|
283
|
+
const target = new EventTarget()
|
|
284
|
+
const listener1 = jest.fn((event: Event) => {
|
|
285
|
+
event.stopImmediatePropagation()
|
|
286
|
+
})
|
|
287
|
+
const listener2 = jest.fn()
|
|
288
|
+
|
|
289
|
+
target.addEventListener('test', listener1)
|
|
290
|
+
target.addEventListener('test', listener2)
|
|
291
|
+
|
|
292
|
+
target.dispatchEvent(new Event('test'))
|
|
293
|
+
|
|
294
|
+
expect(listener1).toHaveBeenCalledTimes(1)
|
|
295
|
+
expect(listener2).toHaveBeenCalledTimes(0) // Stopped
|
|
296
|
+
})
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
describe('Global polyfill installation', () => {
|
|
300
|
+
it('should make Event available globally', () => {
|
|
301
|
+
// This tests that our polyfill setup works
|
|
302
|
+
expect(typeof (global as any).Event).toBe('function')
|
|
303
|
+
expect(typeof (global as any).CustomEvent).toBe('function')
|
|
304
|
+
|
|
305
|
+
const globalEvent = new (global as any).Event('test')
|
|
306
|
+
expect(globalEvent.type).toBe('test')
|
|
307
|
+
|
|
308
|
+
const globalCustomEvent = new (global as any).CustomEvent('custom', {
|
|
309
|
+
detail: 'test',
|
|
310
|
+
})
|
|
311
|
+
expect(globalCustomEvent.detail).toBe('test')
|
|
312
|
+
})
|
|
313
|
+
})
|
|
314
|
+
})
|
|
@@ -219,7 +219,7 @@ const useStyles = () => {
|
|
|
219
219
|
const { colors } = useTheme()
|
|
220
220
|
return StyleSheet.create({
|
|
221
221
|
swipeableChildContainer: {
|
|
222
|
-
backgroundColor: colors.
|
|
222
|
+
backgroundColor: colors.conversationActionsBackground,
|
|
223
223
|
},
|
|
224
224
|
actionButtonContainer: {
|
|
225
225
|
flexDirection: 'row',
|
|
@@ -3,7 +3,12 @@ import { StyleSheet, View, ViewStyle } from 'react-native'
|
|
|
3
3
|
import { ConversationResource } from '../../types'
|
|
4
4
|
import { AvatarGroup, Heading, Text, Badge, type BadgeProps } from '../display'
|
|
5
5
|
import { formatDatePreview } from '../../utils/date'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
useTheme,
|
|
8
|
+
useAtFontScaleBreakpoint,
|
|
9
|
+
useFontScale,
|
|
10
|
+
useScalableNumberOfLines,
|
|
11
|
+
} from '../../hooks'
|
|
7
12
|
import { UnreadCountBadge } from './unread_count_badge'
|
|
8
13
|
import { ConversationActions } from './conversation_actions'
|
|
9
14
|
import { MuteIndicator } from './mute_indicator'
|
|
@@ -41,6 +46,9 @@ export const ConversationPreview = ({
|
|
|
41
46
|
const fallbackIconName = emptyConversation ? 'people.noTextMessage' : 'general.person'
|
|
42
47
|
const hasMetaContent = lastMessageCreatedAt || unreadCount > 0 || muted
|
|
43
48
|
|
|
49
|
+
const numberOfLinesScaledTitle = useScalableNumberOfLines(1)
|
|
50
|
+
const numberOfLinesScaledPreviewText = useScalableNumberOfLines(2)
|
|
51
|
+
|
|
44
52
|
const conversationPreviewText = lastMessageTextPreview
|
|
45
53
|
? `${lastMessageAuthorName}: ${lastMessageTextPreview}`
|
|
46
54
|
: EMPTY_CONVERSATION_PREVIEW_TEXT
|
|
@@ -64,12 +72,12 @@ export const ConversationPreview = ({
|
|
|
64
72
|
fallbackIconName={fallbackIconName}
|
|
65
73
|
/>
|
|
66
74
|
<View style={styles.conversationBody}>
|
|
67
|
-
<Heading numberOfLines={
|
|
75
|
+
<Heading numberOfLines={numberOfLinesScaledTitle} variant="h3" style={styles.title}>
|
|
68
76
|
{title}
|
|
69
77
|
</Heading>
|
|
70
78
|
<Text
|
|
71
79
|
variant="tertiary"
|
|
72
|
-
numberOfLines={
|
|
80
|
+
numberOfLines={numberOfLinesScaledPreviewText}
|
|
73
81
|
style={emptyConversation && styles.emptyConversationPreviewText}
|
|
74
82
|
>
|
|
75
83
|
{conversationPreviewText}
|
|
@@ -96,6 +104,7 @@ interface BadgeShape {
|
|
|
96
104
|
}
|
|
97
105
|
const ConversationBadges = ({ visible, badges }: { visible: boolean; badges?: BadgeShape[] }) => {
|
|
98
106
|
const styles = useStyles()
|
|
107
|
+
const numberOfLinesScaled = useScalableNumberOfLines(1)
|
|
99
108
|
|
|
100
109
|
if (!visible || !badges || badges.length === 0) {
|
|
101
110
|
return null
|
|
@@ -110,6 +119,7 @@ const ConversationBadges = ({ visible, badges }: { visible: boolean; badges?: Ba
|
|
|
110
119
|
productLogoName={badge.appName}
|
|
111
120
|
label={badge.pcoResourceType}
|
|
112
121
|
metaLabel={badge.text || ''}
|
|
122
|
+
numberOfLinesMetaLabel={numberOfLinesScaled}
|
|
113
123
|
/>
|
|
114
124
|
))}
|
|
115
125
|
</View>
|
|
@@ -183,6 +193,7 @@ const getConversationAccessibilityLabel = ({
|
|
|
183
193
|
const useStyles = () => {
|
|
184
194
|
const { colors } = useTheme()
|
|
185
195
|
const atFontScaleBreakpoint = useAtFontScaleBreakpoint()
|
|
196
|
+
const fontScale = useFontScale()
|
|
186
197
|
|
|
187
198
|
return StyleSheet.create({
|
|
188
199
|
previewRow: {
|
|
@@ -238,7 +249,7 @@ const useStyles = () => {
|
|
|
238
249
|
statusContainer: {
|
|
239
250
|
flexDirection: 'row',
|
|
240
251
|
alignItems: 'center',
|
|
241
|
-
gap: 4,
|
|
252
|
+
gap: 4 * fontScale,
|
|
242
253
|
},
|
|
243
254
|
})
|
|
244
255
|
}
|
|
@@ -2,13 +2,20 @@ import React from 'react'
|
|
|
2
2
|
import { StyleSheet } from 'react-native'
|
|
3
3
|
import { Icon } from '../display'
|
|
4
4
|
import { useTheme } from '../../hooks'
|
|
5
|
+
import { MAX_FONT_SIZE_MULTIPLIER } from '../../utils'
|
|
5
6
|
|
|
6
7
|
export const MuteIndicator = ({ muted }: { muted: boolean }) => {
|
|
7
8
|
const styles = useStyles()
|
|
8
9
|
|
|
9
10
|
if (!muted) return null
|
|
10
11
|
|
|
11
|
-
return
|
|
12
|
+
return (
|
|
13
|
+
<Icon
|
|
14
|
+
name="general.bellMuted"
|
|
15
|
+
style={styles.mutedIcon}
|
|
16
|
+
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
const useStyles = () => {
|
|
@@ -16,6 +23,7 @@ const useStyles = () => {
|
|
|
16
23
|
return StyleSheet.create({
|
|
17
24
|
mutedIcon: {
|
|
18
25
|
color: colors.iconColorDefaultDim,
|
|
26
|
+
fontSize: 16,
|
|
19
27
|
},
|
|
20
28
|
})
|
|
21
29
|
}
|
|
@@ -3,7 +3,11 @@ import { StyleSheet } from 'react-native'
|
|
|
3
3
|
import { Pressable, type PressableProps } from 'react-native-gesture-handler'
|
|
4
4
|
import { Icon, IconString, Spinner, Text } from '../display'
|
|
5
5
|
import { useCreateAndroidRippleColor, useTheme } from '../../hooks'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
MAX_FONT_SIZE_MULTIPLIER,
|
|
8
|
+
platformFontWeightMedium,
|
|
9
|
+
platformPressedOpacityStyle,
|
|
10
|
+
} from '../../utils/styles'
|
|
7
11
|
import { tokens } from '../../vendor/tapestry/tokens'
|
|
8
12
|
import { Haptic } from '../../utils/native_adapters/configuration'
|
|
9
13
|
|
|
@@ -50,8 +54,16 @@ export function SwipeableToggleButton({
|
|
|
50
54
|
<Spinner size={20} />
|
|
51
55
|
) : (
|
|
52
56
|
<>
|
|
53
|
-
<Icon
|
|
54
|
-
|
|
57
|
+
<Icon
|
|
58
|
+
name={iconName}
|
|
59
|
+
style={styles.icon}
|
|
60
|
+
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
|
|
61
|
+
/>
|
|
62
|
+
<Text
|
|
63
|
+
variant="footnote"
|
|
64
|
+
style={styles.text}
|
|
65
|
+
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
|
|
66
|
+
>
|
|
55
67
|
{label}
|
|
56
68
|
</Text>
|
|
57
69
|
</>
|
|
@@ -78,12 +90,15 @@ const useStyles = ({ backgroundColor, disabled }: Partial<SwipeableToggleButtonP
|
|
|
78
90
|
backgroundColor: buttonBackgroundColor,
|
|
79
91
|
},
|
|
80
92
|
icon: {
|
|
93
|
+
fontSize: 20,
|
|
81
94
|
color: fillColor,
|
|
82
95
|
marginTop: 4,
|
|
83
96
|
},
|
|
84
97
|
text: {
|
|
85
98
|
color: fillColor,
|
|
86
99
|
fontWeight: platformFontWeightMedium,
|
|
100
|
+
textAlign: 'center',
|
|
101
|
+
paddingHorizontal: 8,
|
|
87
102
|
},
|
|
88
103
|
})
|
|
89
104
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { StyleSheet, View } from 'react-native'
|
|
3
3
|
import { Text } from '../display'
|
|
4
|
-
import { useTheme } from '../../hooks'
|
|
5
|
-
import { platformFontWeightBold } from '../../utils'
|
|
4
|
+
import { useFontScale, useTheme } from '../../hooks'
|
|
5
|
+
import { MAX_FONT_SIZE_MULTIPLIER, platformFontWeightBold } from '../../utils'
|
|
6
6
|
|
|
7
7
|
export const UnreadCountBadge = ({ count, showDot }: { count: number; showDot: boolean }) => {
|
|
8
8
|
const styles = useStyles()
|
|
@@ -22,6 +22,9 @@ export const UnreadCountBadge = ({ count, showDot }: { count: number; showDot: b
|
|
|
22
22
|
|
|
23
23
|
const useStyles = () => {
|
|
24
24
|
const { colors } = useTheme()
|
|
25
|
+
const dotScaleLimit = MAX_FONT_SIZE_MULTIPLIER * 1.5
|
|
26
|
+
const fontScale = useFontScale({ maxFontSizeMultiplier: dotScaleLimit })
|
|
27
|
+
const size = 8 * fontScale
|
|
25
28
|
|
|
26
29
|
return StyleSheet.create({
|
|
27
30
|
badge: {
|
|
@@ -29,16 +32,16 @@ const useStyles = () => {
|
|
|
29
32
|
backgroundColor: colors.fillColorInteractionDefault,
|
|
30
33
|
paddingVertical: 2,
|
|
31
34
|
paddingHorizontal: 8,
|
|
32
|
-
borderRadius: 24,
|
|
35
|
+
borderRadius: 24 * fontScale,
|
|
33
36
|
},
|
|
34
37
|
count: {
|
|
35
38
|
fontWeight: platformFontWeightBold,
|
|
36
39
|
color: 'white',
|
|
37
40
|
},
|
|
38
41
|
dot: {
|
|
39
|
-
width:
|
|
40
|
-
height:
|
|
41
|
-
borderRadius:
|
|
42
|
+
width: size,
|
|
43
|
+
height: size,
|
|
44
|
+
borderRadius: size,
|
|
42
45
|
backgroundColor: colors.fillColorInteractionDefault,
|
|
43
46
|
},
|
|
44
47
|
})
|
|
@@ -58,20 +58,19 @@ export const ActionButton = ({
|
|
|
58
58
|
iconNameLeft={buttonIconNameLeft}
|
|
59
59
|
loading={loading}
|
|
60
60
|
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
|
|
61
|
+
accessibilityShowsLargeContentViewer
|
|
62
|
+
accessibilityLargeContentTitle={title}
|
|
61
63
|
/>
|
|
62
64
|
</View>
|
|
63
65
|
</Animated.View>
|
|
64
66
|
)
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
const SCALE_THAT_BUTTONS_WRAP = 1.15
|
|
68
|
-
|
|
69
69
|
const useStyles = () => {
|
|
70
70
|
const { fontScale } = useWindowDimensions()
|
|
71
71
|
const { bottom } = useSafeAreaInsets()
|
|
72
72
|
const { colors } = useTheme()
|
|
73
73
|
const containerVerticalPadding = 16
|
|
74
|
-
const isButtonsWrapping = fontScale >= SCALE_THAT_BUTTONS_WRAP
|
|
75
74
|
|
|
76
75
|
return StyleSheet.create({
|
|
77
76
|
container: {
|
|
@@ -85,7 +84,7 @@ const useStyles = () => {
|
|
|
85
84
|
},
|
|
86
85
|
buttonRow: {
|
|
87
86
|
flexDirection: 'row',
|
|
88
|
-
justifyContent:
|
|
87
|
+
justifyContent: fontScale > 1 ? 'center' : 'space-between',
|
|
89
88
|
alignItems: 'center',
|
|
90
89
|
gap: 16,
|
|
91
90
|
flexWrap: 'wrap-reverse',
|
|
@@ -12,6 +12,8 @@ interface AvatarProps {
|
|
|
12
12
|
presence?: AvatarPresenceProps['presence']
|
|
13
13
|
showFallback?: boolean
|
|
14
14
|
fallbackIconName?: IconString
|
|
15
|
+
style?: AvatarRootProps['style']
|
|
16
|
+
maxFontSizeMultiplier?: AvatarRootProps['maxFontSizeMultiplier']
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export function Avatar({
|
|
@@ -20,11 +22,13 @@ export function Avatar({
|
|
|
20
22
|
sourceUri,
|
|
21
23
|
showFallback = false,
|
|
22
24
|
fallbackIconName = 'general.person',
|
|
25
|
+
style,
|
|
26
|
+
maxFontSizeMultiplier,
|
|
23
27
|
}: AvatarProps) {
|
|
24
28
|
const shouldShowFallback = showFallback || !sourceUri
|
|
25
29
|
|
|
26
30
|
return (
|
|
27
|
-
<AvatarPrimitive.Root size={size}>
|
|
31
|
+
<AvatarPrimitive.Root size={size} style={style} maxFontSizeMultiplier={maxFontSizeMultiplier}>
|
|
28
32
|
<AvatarPrimitive.Mask>
|
|
29
33
|
{shouldShowFallback ? (
|
|
30
34
|
<AvatarPrimitive.ImageFallback name={fallbackIconName} />
|
|
@@ -10,6 +10,8 @@ interface AvatarGroupDisplayProps {
|
|
|
10
10
|
showFallback?: boolean
|
|
11
11
|
fallbackIconName?: IconString
|
|
12
12
|
size?: AvatarRootProps['size']
|
|
13
|
+
style?: AvatarRootProps['style']
|
|
14
|
+
maxFontSizeMultiplier?: AvatarRootProps['maxFontSizeMultiplier']
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export function AvatarGroup({
|
|
@@ -17,11 +19,13 @@ export function AvatarGroup({
|
|
|
17
19
|
showFallback = false,
|
|
18
20
|
fallbackIconName = 'general.person',
|
|
19
21
|
size = 'lg',
|
|
22
|
+
style,
|
|
23
|
+
maxFontSizeMultiplier,
|
|
20
24
|
}: AvatarGroupDisplayProps) {
|
|
21
25
|
const shouldShowFallback = showFallback || !sourceUris || sourceUris.length === 0
|
|
22
26
|
|
|
23
27
|
return (
|
|
24
|
-
<AvatarPrimitive.Root size={size}>
|
|
28
|
+
<AvatarPrimitive.Root size={size} style={style} maxFontSizeMultiplier={maxFontSizeMultiplier}>
|
|
25
29
|
<AvatarPrimitive.Mask>
|
|
26
30
|
{shouldShowFallback ? (
|
|
27
31
|
<AvatarPrimitive.ImageFallback name={fallbackIconName} />
|
|
@@ -91,6 +91,10 @@ export interface BadgeProps {
|
|
|
91
91
|
* Callback function when the badge is pressed.
|
|
92
92
|
*/
|
|
93
93
|
onPress?: () => void
|
|
94
|
+
/**
|
|
95
|
+
* Specifies the number of lines for the meta label before truncating.
|
|
96
|
+
*/
|
|
97
|
+
numberOfLinesMetaLabel?: number
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
export function Badge({
|
|
@@ -103,6 +107,7 @@ export function Badge({
|
|
|
103
107
|
productLogoName,
|
|
104
108
|
variant = 'default',
|
|
105
109
|
maxFontSizeMultiplier,
|
|
110
|
+
numberOfLinesMetaLabel = 1,
|
|
106
111
|
onPress,
|
|
107
112
|
}: BadgeProps) {
|
|
108
113
|
const styles = useStyles({ appearance, maxFontSizeMultiplier, variant })
|
|
@@ -134,7 +139,7 @@ export function Badge({
|
|
|
134
139
|
<Text
|
|
135
140
|
variant="footnote"
|
|
136
141
|
style={styles.metaLabel}
|
|
137
|
-
numberOfLines={
|
|
142
|
+
numberOfLines={numberOfLinesMetaLabel}
|
|
138
143
|
maxFontSizeMultiplier={maxFontSizeMultiplier}
|
|
139
144
|
>
|
|
140
145
|
{metaLabel}
|
|
@@ -5,29 +5,17 @@ import { SvgXml } from 'react-native-svg'
|
|
|
5
5
|
import type { XmlProps } from 'react-native-svg'
|
|
6
6
|
import { useFontScale, useTheme } from '../../hooks'
|
|
7
7
|
|
|
8
|
-
// @ts-ignore
|
|
9
8
|
import * as accounts from '@planningcenter/icons/paths/accounts'
|
|
10
|
-
// @ts-ignore
|
|
11
9
|
import * as api from '@planningcenter/icons/paths/api'
|
|
12
|
-
// @ts-ignore
|
|
13
10
|
import * as brand from '@planningcenter/icons/paths/brand'
|
|
14
|
-
// @ts-ignore
|
|
15
11
|
import * as calendar from '@planningcenter/icons/paths/calendar'
|
|
16
|
-
// @ts-ignore
|
|
17
12
|
import * as chat from '@planningcenter/icons/paths/chat'
|
|
18
|
-
// @ts-ignore
|
|
19
13
|
import * as churchCenter from '@planningcenter/icons/paths/church-center'
|
|
20
|
-
// @ts-ignore
|
|
21
14
|
import * as general from '@planningcenter/icons/paths/general'
|
|
22
|
-
// @ts-ignore
|
|
23
15
|
import * as groups from '@planningcenter/icons/paths/groups'
|
|
24
|
-
// @ts-ignore
|
|
25
16
|
import * as logomark from '@planningcenter/icons/paths/logomark'
|
|
26
|
-
// @ts-ignore
|
|
27
17
|
import * as people from '@planningcenter/icons/paths/people'
|
|
28
|
-
// @ts-ignore
|
|
29
18
|
import * as services from '@planningcenter/icons/paths/services'
|
|
30
|
-
// @ts-ignore
|
|
31
19
|
import * as publishing from '@planningcenter/icons/paths/publishing'
|
|
32
20
|
|
|
33
21
|
// =================================
|
|
@@ -57,7 +45,22 @@ export type IconStyle = ViewStyle & {
|
|
|
57
45
|
}
|
|
58
46
|
|
|
59
47
|
export type IconSetName = keyof typeof ICONS
|
|
60
|
-
|
|
48
|
+
|
|
49
|
+
type IconName<T extends IconSetName> = keyof (typeof ICONS)[T] & string
|
|
50
|
+
|
|
51
|
+
export type IconString =
|
|
52
|
+
| `accounts.${IconName<'accounts'>}`
|
|
53
|
+
| `api.${IconName<'api'>}`
|
|
54
|
+
| `brand.${IconName<'brand'>}`
|
|
55
|
+
| `calendar.${IconName<'calendar'>}`
|
|
56
|
+
| `chat.${IconName<'chat'>}`
|
|
57
|
+
| `churchCenter.${IconName<'churchCenter'>}`
|
|
58
|
+
| `general.${IconName<'general'>}`
|
|
59
|
+
| `groups.${IconName<'groups'>}`
|
|
60
|
+
| `logomark.${IconName<'logomark'>}`
|
|
61
|
+
| `people.${IconName<'people'>}`
|
|
62
|
+
| `services.${IconName<'services'>}`
|
|
63
|
+
| `publishing.${IconName<'publishing'>}`
|
|
61
64
|
|
|
62
65
|
// =================================
|
|
63
66
|
// ====== Component ================
|
|
@@ -137,7 +140,7 @@ const useGetIconSize = (size?: number, style?: IconStyle, maxFontSizeMultiplier?
|
|
|
137
140
|
const getIconPath = (name: IconString): string => {
|
|
138
141
|
const [setName, iconName] = name.split('.')
|
|
139
142
|
|
|
140
|
-
return ICONS[setName as IconSetName]?.[iconName]
|
|
143
|
+
return (ICONS[setName as IconSetName] as Record<string, string>)?.[iconName]
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
// =================================
|