@peers-app/peers-ui 0.14.0 → 0.15.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.
- package/.github/workflows/publish.yml +8 -5
- package/babel.config.js +4 -4
- package/biome.json +191 -0
- package/dist/command-palette/command-palette-ui.d.ts +1 -2
- package/dist/command-palette/command-palette-ui.js +175 -244
- package/dist/command-palette/command-palette.js +65 -64
- package/dist/components/chat-overlay.d.ts +2 -2
- package/dist/components/chat-overlay.js +160 -217
- package/dist/components/checkbox.d.ts +5 -4
- package/dist/components/checkbox.js +4 -7
- package/dist/components/group-switcher.d.ts +1 -2
- package/dist/components/group-switcher.js +119 -159
- package/dist/components/input-date.d.ts +3 -3
- package/dist/components/input-date.js +6 -6
- package/dist/components/input-number.d.ts +7 -6
- package/dist/components/input-number.js +25 -20
- package/dist/components/input.d.ts +5 -4
- package/dist/components/input.js +4 -7
- package/dist/components/inverse-lazy-list.d.ts +3 -3
- package/dist/components/inverse-lazy-list.js +13 -47
- package/dist/components/io-schema-values.d.ts +5 -6
- package/dist/components/io-schema-values.js +28 -65
- package/dist/components/io-schema.d.ts +4 -5
- package/dist/components/io-schema.js +42 -79
- package/dist/components/lazy-list.d.ts +3 -3
- package/dist/components/lazy-list.js +38 -58
- package/dist/components/list-screen.d.ts +3 -8
- package/dist/components/list-screen.js +28 -23
- package/dist/components/loading-indicator.d.ts +1 -2
- package/dist/components/loading-indicator.js +2 -6
- package/dist/components/markdown-editor/autolink-plugin.js +5 -8
- package/dist/components/markdown-editor/editor-inline.d.ts +2 -3
- package/dist/components/markdown-editor/editor-inline.js +2 -6
- package/dist/components/markdown-editor/editor.d.ts +6 -6
- package/dist/components/markdown-editor/editor.js +9 -19
- package/dist/components/markdown-editor/markdown-plugin.d.ts +1 -1
- package/dist/components/markdown-editor/markdown-plugin.js +20 -21
- package/dist/components/markdown-editor/mention-node.d.ts +2 -2
- package/dist/components/markdown-editor/mention-node.js +24 -24
- package/dist/components/markdown-editor/mentions-plugin.d.ts +2 -2
- package/dist/components/markdown-editor/mentions-plugin.js +61 -62
- package/dist/components/markdown-editor/theme.js +28 -28
- package/dist/components/markdown-editor/toolbar.d.ts +2 -3
- package/dist/components/markdown-editor/toolbar.js +32 -49
- package/dist/components/markdown-with-mentions.d.ts +1 -1
- package/dist/components/markdown-with-mentions.js +43 -43
- package/dist/components/message-logs/message-logs.d.ts +1 -2
- package/dist/components/message-logs/message-logs.js +91 -116
- package/dist/components/messages/avatar.d.ts +3 -4
- package/dist/components/messages/avatar.js +37 -46
- package/dist/components/messages/channel-message-list.d.ts +5 -6
- package/dist/components/messages/channel-message-list.js +34 -34
- package/dist/components/messages/channel-view.d.ts +1 -2
- package/dist/components/messages/channel-view.js +23 -57
- package/dist/components/messages/message-compose.d.ts +3 -4
- package/dist/components/messages/message-compose.js +27 -38
- package/dist/components/messages/message-display.d.ts +2 -3
- package/dist/components/messages/message-display.js +42 -95
- package/dist/components/messages/thread-message-list.d.ts +4 -5
- package/dist/components/messages/thread-message-list.js +29 -29
- package/dist/components/router.d.ts +1 -2
- package/dist/components/router.js +58 -66
- package/dist/components/save-button.d.ts +3 -3
- package/dist/components/save-button.js +23 -33
- package/dist/components/sortable-list.d.ts +11 -12
- package/dist/components/sortable-list.js +42 -22
- package/dist/components/tabs.d.ts +3 -3
- package/dist/components/tabs.js +16 -47
- package/dist/components/tooltip.d.ts +4 -4
- package/dist/components/tooltip.js +4 -9
- package/dist/components/trust-level-badge.d.ts +2 -3
- package/dist/components/trust-level-badge.js +16 -16
- package/dist/components/trust-level-dropdown.d.ts +3 -4
- package/dist/components/trust-level-dropdown.js +32 -55
- package/dist/components/typeahead.d.ts +3 -3
- package/dist/components/typeahead.js +48 -89
- package/dist/components/voice-indicator.d.ts +2 -2
- package/dist/components/voice-indicator.js +93 -106
- package/dist/components/voice-subscribe-events.d.ts +32 -0
- package/dist/components/voice-subscribe-events.js +2 -0
- package/dist/globals.d.ts +3 -5
- package/dist/globals.js +22 -33
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +22 -12
- package/dist/hooks.test.js +129 -145
- package/dist/index.d.ts +9 -8
- package/dist/index.js +13 -12
- package/dist/mention-configs.d.ts +2 -2
- package/dist/mention-configs.js +55 -42
- package/dist/screens/assistants/assistant-config.d.ts +2 -3
- package/dist/screens/assistants/assistant-config.js +9 -22
- package/dist/screens/assistants/assistant-details.d.ts +1 -2
- package/dist/screens/assistants/assistant-details.js +13 -28
- package/dist/screens/assistants/assistant-info.d.ts +2 -3
- package/dist/screens/assistants/assistant-info.js +3 -17
- package/dist/screens/assistants/assistant-list.d.ts +1 -2
- package/dist/screens/assistants/assistant-list.js +15 -56
- package/dist/screens/assistants/assistant-tools.d.ts +2 -3
- package/dist/screens/assistants/assistant-tools.js +10 -24
- package/dist/screens/console-logs/console-logs-list.d.ts +1 -2
- package/dist/screens/console-logs/console-logs-list.js +130 -134
- package/dist/screens/console-logs/log-display.d.ts +2 -3
- package/dist/screens/console-logs/log-display.js +40 -42
- package/dist/screens/console-logs/log-filters.d.ts +1 -2
- package/dist/screens/console-logs/log-filters.js +2 -24
- package/dist/screens/console-logs/mobile-log-card.d.ts +2 -3
- package/dist/screens/console-logs/mobile-log-card.js +64 -67
- package/dist/screens/console-logs/resizable-table-header.d.ts +1 -2
- package/dist/screens/console-logs/resizable-table-header.js +31 -67
- package/dist/screens/contacts/contact-details.d.ts +1 -2
- package/dist/screens/contacts/contact-details.js +16 -46
- package/dist/screens/contacts/contact-list.d.ts +1 -2
- package/dist/screens/contacts/contact-list.js +44 -103
- package/dist/screens/contacts/index.d.ts +4 -4
- package/dist/screens/contacts/index.js +1 -1
- package/dist/screens/contacts/user-connect.d.ts +1 -2
- package/dist/screens/contacts/user-connect.js +85 -186
- package/dist/screens/data-explorer/data-explorer.d.ts +1 -2
- package/dist/screens/data-explorer/data-explorer.js +61 -181
- package/dist/screens/data-explorer/index.d.ts +2 -2
- package/dist/screens/data-explorer/query-executor.d.ts +1 -2
- package/dist/screens/data-explorer/query-executor.js +56 -166
- package/dist/screens/groups/group-details.d.ts +1 -2
- package/dist/screens/groups/group-details.js +27 -122
- package/dist/screens/groups/group-invite-listener.d.ts +2 -3
- package/dist/screens/groups/group-invite-listener.js +8 -104
- package/dist/screens/groups/group-list.d.ts +1 -2
- package/dist/screens/groups/group-list.js +56 -133
- package/dist/screens/groups/group-members.d.ts +2 -3
- package/dist/screens/groups/group-members.js +62 -132
- package/dist/screens/groups/index.d.ts +4 -4
- package/dist/screens/groups/index.js +1 -1
- package/dist/screens/join-group/index.d.ts +2 -2
- package/dist/screens/join-group/join-group.d.ts +1 -2
- package/dist/screens/join-group/join-group.js +9 -109
- package/dist/screens/network-viewer/connection-troubleshooter.d.ts +2 -3
- package/dist/screens/network-viewer/connection-troubleshooter.js +89 -193
- package/dist/screens/network-viewer/cpu-usage-graph.d.ts +1 -2
- package/dist/screens/network-viewer/cpu-usage-graph.js +60 -99
- package/dist/screens/network-viewer/device-details-modal.d.ts +1 -2
- package/dist/screens/network-viewer/device-details-modal.js +25 -177
- package/dist/screens/network-viewer/group-details-modal.d.ts +1 -2
- package/dist/screens/network-viewer/group-details-modal.js +31 -142
- package/dist/screens/network-viewer/index.d.ts +4 -4
- package/dist/screens/network-viewer/index.js +3 -3
- package/dist/screens/network-viewer/network-viewer-ipc.d.ts +22 -0
- package/dist/screens/network-viewer/network-viewer-ipc.js +6 -0
- package/dist/screens/network-viewer/network-viewer.d.ts +1 -2
- package/dist/screens/network-viewer/network-viewer.js +91 -296
- package/dist/screens/network-viewer/usage-graph.d.ts +1 -2
- package/dist/screens/network-viewer/usage-graph.js +78 -110
- package/dist/screens/packages/package-details.d.ts +1 -2
- package/dist/screens/packages/package-details.js +35 -41
- package/dist/screens/packages/package-info.d.ts +2 -2
- package/dist/screens/packages/package-info.js +33 -86
- package/dist/screens/packages/package-list.d.ts +1 -2
- package/dist/screens/packages/package-list.js +42 -106
- package/dist/screens/packages/package-new-local.d.ts +1 -2
- package/dist/screens/packages/package-new-local.js +13 -19
- package/dist/screens/packages/package-versions.d.ts +2 -3
- package/dist/screens/packages/package-versions.js +29 -96
- package/dist/screens/peer-types/peer-type-details.d.ts +3 -4
- package/dist/screens/peer-types/peer-type-details.js +26 -78
- package/dist/screens/peer-types/peer-type-list.d.ts +1 -2
- package/dist/screens/peer-types/peer-type-list.js +13 -24
- package/dist/screens/search/global-search.d.ts +1 -2
- package/dist/screens/search/global-search.js +104 -182
- package/dist/screens/settings/color-mode-dropdown.d.ts +3 -4
- package/dist/screens/settings/color-mode-dropdown.js +18 -37
- package/dist/screens/settings/settings-page.d.ts +1 -1
- package/dist/screens/settings/settings-page.js +86 -213
- package/dist/screens/settings/voice-settings-agent.d.ts +1 -1
- package/dist/screens/settings/voice-settings-agent.js +7 -44
- package/dist/screens/settings/voice-settings-api-keys.d.ts +2 -2
- package/dist/screens/settings/voice-settings-api-keys.js +2 -29
- package/dist/screens/settings/voice-settings-output.d.ts +2 -2
- package/dist/screens/settings/voice-settings-output.js +2 -40
- package/dist/screens/settings/voice-settings-providers.d.ts +2 -2
- package/dist/screens/settings/voice-settings-providers.js +2 -19
- package/dist/screens/settings/voice-settings-types.d.ts +4 -4
- package/dist/screens/settings/voice-settings-types.js +31 -31
- package/dist/screens/settings/voice-settings-wake-word.d.ts +2 -2
- package/dist/screens/settings/voice-settings-wake-word.js +2 -33
- package/dist/screens/settings/voice-settings.d.ts +1 -1
- package/dist/screens/settings/voice-settings.js +35 -112
- package/dist/screens/setup-user.d.ts +1 -2
- package/dist/screens/setup-user.js +38 -116
- package/dist/screens/tools/tool-code.d.ts +2 -3
- package/dist/screens/tools/tool-code.js +9 -13
- package/dist/screens/tools/tool-details.d.ts +1 -2
- package/dist/screens/tools/tool-details.js +26 -39
- package/dist/screens/tools/tool-info.d.ts +2 -3
- package/dist/screens/tools/tool-info.js +9 -48
- package/dist/screens/tools/tool-list.d.ts +1 -2
- package/dist/screens/tools/tool-list.js +33 -65
- package/dist/screens/tools/tool-schema.d.ts +2 -3
- package/dist/screens/tools/tool-schema.js +2 -13
- package/dist/screens/tools/tool-test-details.d.ts +1 -2
- package/dist/screens/tools/tool-test-details.js +12 -28
- package/dist/screens/tools/tool-test-list.d.ts +1 -2
- package/dist/screens/tools/tool-test-list.js +17 -56
- package/dist/screens/variables/variable-details.d.ts +1 -2
- package/dist/screens/variables/variable-details.js +19 -86
- package/dist/screens/variables/variable-list.d.ts +1 -2
- package/dist/screens/variables/variable-list.js +16 -27
- package/dist/screens/welcome-modal.d.ts +1 -2
- package/dist/screens/welcome-modal.js +44 -111
- package/dist/screens/workflows/workflow-details.d.ts +1 -2
- package/dist/screens/workflows/workflow-details.js +17 -31
- package/dist/screens/workflows/workflow-info.d.ts +2 -3
- package/dist/screens/workflows/workflow-info.js +2 -9
- package/dist/screens/workflows/workflow-instructions.d.ts +2 -3
- package/dist/screens/workflows/workflow-instructions.js +23 -55
- package/dist/screens/workflows/workflow-list.d.ts +1 -2
- package/dist/screens/workflows/workflow-list.js +23 -62
- package/dist/setupTests.d.ts +1 -1
- package/dist/setupTests.js +10 -11
- package/dist/system-apps/assistants.app.d.ts +1 -1
- package/dist/system-apps/assistants.app.js +3 -3
- package/dist/system-apps/console-logs.app.d.ts +1 -1
- package/dist/system-apps/console-logs.app.js +3 -3
- package/dist/system-apps/contacts.app.d.ts +1 -1
- package/dist/system-apps/contacts.app.js +4 -4
- package/dist/system-apps/data-explorer.app.d.ts +1 -1
- package/dist/system-apps/data-explorer.app.js +4 -4
- package/dist/system-apps/groups.app.d.ts +1 -1
- package/dist/system-apps/groups.app.js +4 -4
- package/dist/system-apps/index.d.ts +17 -17
- package/dist/system-apps/index.js +52 -52
- package/dist/system-apps/join-group.app.d.ts +1 -1
- package/dist/system-apps/join-group.app.js +4 -4
- package/dist/system-apps/mobile-settings.app.d.ts +1 -1
- package/dist/system-apps/mobile-settings.app.js +3 -3
- package/dist/system-apps/network-viewer.app.d.ts +1 -1
- package/dist/system-apps/network-viewer.app.js +4 -4
- package/dist/system-apps/packages.app.d.ts +1 -1
- package/dist/system-apps/packages.app.js +3 -3
- package/dist/system-apps/search.app.d.ts +1 -1
- package/dist/system-apps/search.app.js +4 -4
- package/dist/system-apps/settings.app.d.ts +1 -1
- package/dist/system-apps/settings.app.js +3 -3
- package/dist/system-apps/threads.app.d.ts +1 -1
- package/dist/system-apps/threads.app.js +3 -3
- package/dist/system-apps/tools.app.d.ts +1 -1
- package/dist/system-apps/tools.app.js +3 -3
- package/dist/system-apps/types.app.d.ts +1 -1
- package/dist/system-apps/types.app.js +3 -3
- package/dist/system-apps/variables.app.d.ts +1 -1
- package/dist/system-apps/variables.app.js +3 -3
- package/dist/system-apps/workflows.app.d.ts +1 -1
- package/dist/system-apps/workflows.app.js +3 -3
- package/dist/tabs-layout/tabs-layout.d.ts +2 -3
- package/dist/tabs-layout/tabs-layout.js +215 -246
- package/dist/tabs-layout/tabs-state.d.ts +2 -2
- package/dist/tabs-layout/tabs-state.js +73 -61
- package/dist/ui-defaults/index.d.ts +2 -2
- package/dist/ui-defaults/list-screen.d.ts +2 -3
- package/dist/ui-defaults/list-screen.js +33 -37
- package/dist/ui-defaults/markdown-field.js +24 -56
- package/dist/ui-router/routes-loader.d.ts +1 -1
- package/dist/ui-router/routes-loader.js +17 -13
- package/dist/ui-router/ui-loader.d.ts +6 -6
- package/dist/ui-router/ui-loader.js +172 -268
- package/dist/utils.js +49 -39
- package/jest.config.js +16 -16
- package/package.json +16 -14
- package/src/command-palette/command-palette-ui.tsx +261 -237
- package/src/command-palette/command-palette.ts +81 -78
- package/src/components/chat-overlay.tsx +366 -261
- package/src/components/checkbox.tsx +15 -12
- package/src/components/group-switcher.tsx +150 -105
- package/src/components/input-date.tsx +17 -16
- package/src/components/input-number.tsx +47 -31
- package/src/components/input.tsx +15 -12
- package/src/components/inverse-lazy-list.tsx +14 -13
- package/src/components/io-schema-values.tsx +51 -69
- package/src/components/io-schema.tsx +94 -69
- package/src/components/lazy-list.tsx +51 -34
- package/src/components/list-screen.tsx +51 -35
- package/src/components/loading-indicator.tsx +2 -4
- package/src/components/markdown-editor/autolink-plugin.tsx +4 -11
- package/src/components/markdown-editor/editor-inline.tsx +3 -4
- package/src/components/markdown-editor/editor.tsx +53 -51
- package/src/components/markdown-editor/markdown-plugin.tsx +48 -40
- package/src/components/markdown-editor/mention-node.ts +39 -38
- package/src/components/markdown-editor/mentions-plugin.tsx +99 -101
- package/src/components/markdown-editor/theme.ts +28 -29
- package/src/components/markdown-editor/toolbar.tsx +53 -47
- package/src/components/markdown-with-mentions.tsx +56 -46
- package/src/components/message-logs/message-logs.tsx +225 -165
- package/src/components/messages/avatar.tsx +70 -52
- package/src/components/messages/channel-message-list.tsx +80 -68
- package/src/components/messages/channel-view.tsx +34 -33
- package/src/components/messages/message-compose.tsx +84 -67
- package/src/components/messages/message-display.tsx +103 -89
- package/src/components/messages/thread-message-list.tsx +53 -44
- package/src/components/router.tsx +42 -43
- package/src/components/save-button.tsx +43 -39
- package/src/components/sortable-list.tsx +77 -49
- package/src/components/tabs.tsx +31 -31
- package/src/components/tooltip.tsx +21 -28
- package/src/components/trust-level-badge.tsx +15 -11
- package/src/components/trust-level-dropdown.tsx +49 -19
- package/src/components/typeahead.tsx +57 -59
- package/src/components/voice-indicator.tsx +158 -141
- package/src/components/voice-subscribe-events.ts +20 -0
- package/src/globals.tsx +42 -40
- package/src/hooks.test.tsx +141 -134
- package/src/hooks.ts +80 -48
- package/src/index.tsx +17 -10
- package/src/mention-configs.ts +122 -68
- package/src/screens/assistants/assistant-config.tsx +28 -18
- package/src/screens/assistants/assistant-details.tsx +35 -36
- package/src/screens/assistants/assistant-info.tsx +16 -11
- package/src/screens/assistants/assistant-list.tsx +37 -34
- package/src/screens/assistants/assistant-tools.tsx +41 -20
- package/src/screens/console-logs/console-logs-list.tsx +173 -140
- package/src/screens/console-logs/log-display.tsx +65 -38
- package/src/screens/console-logs/log-filters.tsx +4 -3
- package/src/screens/console-logs/mobile-log-card.tsx +78 -71
- package/src/screens/console-logs/resizable-table-header.tsx +29 -21
- package/src/screens/contacts/contact-details.tsx +29 -30
- package/src/screens/contacts/contact-list.tsx +71 -60
- package/src/screens/contacts/index.ts +5 -5
- package/src/screens/contacts/user-connect.tsx +177 -171
- package/src/screens/data-explorer/data-explorer.tsx +134 -98
- package/src/screens/data-explorer/index.ts +2 -3
- package/src/screens/data-explorer/query-executor.tsx +90 -80
- package/src/screens/groups/group-details.tsx +120 -101
- package/src/screens/groups/group-invite-listener.tsx +34 -37
- package/src/screens/groups/group-list.tsx +119 -103
- package/src/screens/groups/group-members.tsx +225 -164
- package/src/screens/groups/index.ts +5 -6
- package/src/screens/join-group/index.ts +2 -2
- package/src/screens/join-group/join-group.tsx +41 -39
- package/src/screens/network-viewer/connection-troubleshooter.tsx +145 -104
- package/src/screens/network-viewer/cpu-usage-graph.tsx +39 -43
- package/src/screens/network-viewer/device-details-modal.tsx +46 -59
- package/src/screens/network-viewer/group-details-modal.tsx +68 -49
- package/src/screens/network-viewer/index.ts +4 -5
- package/src/screens/network-viewer/network-viewer-ipc.ts +23 -0
- package/src/screens/network-viewer/network-viewer.tsx +261 -236
- package/src/screens/network-viewer/usage-graph.tsx +57 -49
- package/src/screens/packages/package-details.tsx +43 -35
- package/src/screens/packages/package-info.tsx +107 -66
- package/src/screens/packages/package-list.tsx +175 -98
- package/src/screens/packages/package-new-local.tsx +28 -26
- package/src/screens/packages/package-versions.tsx +102 -77
- package/src/screens/peer-types/peer-type-details.tsx +60 -50
- package/src/screens/peer-types/peer-type-list.tsx +20 -30
- package/src/screens/search/global-search.tsx +153 -137
- package/src/screens/settings/color-mode-dropdown.tsx +52 -35
- package/src/screens/settings/settings-page.tsx +215 -141
- package/src/screens/settings/voice-settings-agent.tsx +13 -12
- package/src/screens/settings/voice-settings-api-keys.tsx +14 -12
- package/src/screens/settings/voice-settings-output.tsx +12 -11
- package/src/screens/settings/voice-settings-providers.tsx +7 -3
- package/src/screens/settings/voice-settings-types.ts +52 -49
- package/src/screens/settings/voice-settings-wake-word.tsx +25 -9
- package/src/screens/settings/voice-settings.tsx +66 -43
- package/src/screens/setup-user.tsx +88 -41
- package/src/screens/tools/tool-code.tsx +12 -17
- package/src/screens/tools/tool-details.tsx +28 -28
- package/src/screens/tools/tool-info.tsx +14 -19
- package/src/screens/tools/tool-list.tsx +58 -40
- package/src/screens/tools/tool-schema.tsx +16 -9
- package/src/screens/tools/tool-test-details.tsx +11 -22
- package/src/screens/tools/tool-test-list.tsx +29 -30
- package/src/screens/variables/variable-details.tsx +63 -51
- package/src/screens/variables/variable-list.tsx +29 -30
- package/src/screens/welcome-modal.tsx +68 -48
- package/src/screens/workflows/workflow-details.tsx +40 -30
- package/src/screens/workflows/workflow-info.tsx +4 -11
- package/src/screens/workflows/workflow-instructions.tsx +35 -28
- package/src/screens/workflows/workflow-list.tsx +50 -40
- package/src/setupTests.ts +14 -13
- package/src/system-apps/assistants.app.ts +5 -5
- package/src/system-apps/console-logs.app.ts +4 -4
- package/src/system-apps/contacts.app.ts +6 -6
- package/src/system-apps/data-explorer.app.ts +5 -5
- package/src/system-apps/groups.app.ts +6 -6
- package/src/system-apps/index.ts +49 -49
- package/src/system-apps/join-group.app.ts +5 -5
- package/src/system-apps/mobile-settings.app.ts +4 -5
- package/src/system-apps/network-viewer.app.ts +5 -5
- package/src/system-apps/packages.app.ts +5 -5
- package/src/system-apps/search.app.ts +6 -6
- package/src/system-apps/settings.app.ts +5 -5
- package/src/system-apps/threads.app.ts +5 -5
- package/src/system-apps/tools.app.ts +5 -5
- package/src/system-apps/types.app.ts +5 -5
- package/src/system-apps/variables.app.ts +5 -5
- package/src/system-apps/workflows.app.ts +5 -5
- package/src/tabs-layout/tabs-layout.tsx +345 -254
- package/src/tabs-layout/tabs-state.ts +100 -81
- package/src/ui-defaults/index.ts +2 -3
- package/src/ui-defaults/list-screen.tsx +45 -40
- package/src/ui-defaults/markdown-field.tsx +22 -26
- package/src/ui-router/routes-loader.ts +40 -24
- package/src/ui-router/ui-loader.tsx +312 -214
- package/src/utils.ts +68 -81
- package/tsconfig.json +5 -10
- package/dist/components/input-datetime.d.ts +0 -7
- package/dist/components/input-datetime.js +0 -35
- package/dist/components/lazy-sortable-list.d.ts +0 -29
- package/dist/components/lazy-sortable-list.js +0 -12
- package/dist/components/left-bar.d.ts +0 -5
- package/dist/components/left-bar.js +0 -207
- package/dist/components/main-content-container.d.ts +0 -2
- package/dist/components/main-content-container.js +0 -92
- package/dist/components/messages/thread-view.d.ts +0 -6
- package/dist/components/messages/thread-view.js +0 -174
- package/dist/components/off-canvas.d.ts +0 -13
- package/dist/components/off-canvas.js +0 -89
- package/dist/components/text-list-editor.tsx/text-list-editor.d.ts +0 -6
- package/dist/components/text-list-editor.tsx/text-list-editor.js +0 -13
- package/dist/components/top-bar.d.ts +0 -2
- package/dist/components/top-bar.js +0 -51
- package/dist/components/typeahead/mentions-plugin.d.ts +0 -7
- package/dist/components/typeahead/mentions-plugin.js +0 -203
- package/dist/components/typeahead/typeahead-editor.d.ts +0 -15
- package/dist/components/typeahead/typeahead-editor.js +0 -134
- package/dist/components/typeahead/typeahead.d.ts +0 -12
- package/dist/components/typeahead/typeahead.js +0 -94
- package/dist/screens/profile.d.ts +0 -2
- package/dist/screens/profile.js +0 -76
- package/src/components/input-datetime.tsx +0 -41
- package/src/components/lazy-sortable-list.tsx +0 -51
- package/src/components/left-bar.tsx +0 -322
- package/src/components/main-content-container.tsx +0 -79
- package/src/components/messages/thread-view.tsx +0 -214
- package/src/components/off-canvas.tsx +0 -83
- package/src/components/text-list-editor.tsx/text-list-editor.tsx +0 -13
- package/src/components/top-bar.tsx +0 -119
- package/src/components/typeahead/mentions-plugin.tsx +0 -265
- package/src/components/typeahead/typeahead-editor.tsx +0 -140
- package/src/components/typeahead/typeahead.tsx +0 -77
- package/src/screens/profile.tsx +0 -75
package/dist/globals.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.groups = exports.isDesktop = exports.windowHeight = exports.windowWidth = exports.me = exports.
|
|
3
|
+
exports.groups = exports.isDesktop = exports.windowHeight = exports.windowWidth = exports.me = exports.mainContentPath = exports._mainContentPath = exports.packageReloaded = void 0;
|
|
4
4
|
exports.queryParam = queryParam;
|
|
5
5
|
exports.openThread = openThread;
|
|
6
6
|
exports.openThreadInTab = openThreadInTab;
|
|
@@ -9,7 +9,7 @@ const peers_sdk_1 = require("@peers-app/peers-sdk");
|
|
|
9
9
|
const tabs_state_1 = require("./tabs-layout/tabs-state");
|
|
10
10
|
const utils_1 = require("./utils");
|
|
11
11
|
exports.packageReloaded = (0, peers_sdk_1.observable)(0);
|
|
12
|
-
exports._mainContentPath = (0, peers_sdk_1.groupUserVar)(
|
|
12
|
+
exports._mainContentPath = (0, peers_sdk_1.groupUserVar)("mainContentPath", { defaultValue: "" });
|
|
13
13
|
exports.mainContentPath = (0, peers_sdk_1.computed)({
|
|
14
14
|
read: () => {
|
|
15
15
|
return (0, exports._mainContentPath)();
|
|
@@ -24,7 +24,7 @@ exports.mainContentPath = (0, peers_sdk_1.computed)({
|
|
|
24
24
|
});
|
|
25
25
|
const queryParams = (0, peers_sdk_1.computed)({
|
|
26
26
|
read: () => {
|
|
27
|
-
const queryStr = (0, exports.mainContentPath)()?.split(
|
|
27
|
+
const queryStr = (0, exports.mainContentPath)()?.split("?")[1] || "";
|
|
28
28
|
const params = new URLSearchParams(queryStr);
|
|
29
29
|
const obj = {};
|
|
30
30
|
for (const [key, value] of params.entries()) {
|
|
@@ -33,12 +33,12 @@ const queryParams = (0, peers_sdk_1.computed)({
|
|
|
33
33
|
return obj;
|
|
34
34
|
},
|
|
35
35
|
write: (value) => {
|
|
36
|
-
const queryStr = (0, exports.mainContentPath)().split(
|
|
36
|
+
const queryStr = (0, exports.mainContentPath)().split("?")[1] || "";
|
|
37
37
|
const params = new URLSearchParams(queryStr);
|
|
38
38
|
for (const key in value) {
|
|
39
39
|
params.set(key, value[key]);
|
|
40
40
|
}
|
|
41
|
-
(0, exports.mainContentPath)((0, exports.mainContentPath)().split(
|
|
41
|
+
(0, exports.mainContentPath)(`${(0, exports.mainContentPath)().split("?")[0]}?${params.toString()}`);
|
|
42
42
|
},
|
|
43
43
|
});
|
|
44
44
|
function queryParam(name, value) {
|
|
@@ -47,7 +47,7 @@ function queryParam(name, value) {
|
|
|
47
47
|
if (params[name] === value) {
|
|
48
48
|
return value;
|
|
49
49
|
}
|
|
50
|
-
if (value === null || value ===
|
|
50
|
+
if (value === null || value === "") {
|
|
51
51
|
delete params[name];
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
@@ -57,25 +57,14 @@ function queryParam(name, value) {
|
|
|
57
57
|
}
|
|
58
58
|
return params[name];
|
|
59
59
|
}
|
|
60
|
-
exports.openThreads = (0, peers_sdk_1.groupUserVar)('openThreads', { defaultValue: [] });
|
|
61
|
-
exports.threadViewOpen = (0, peers_sdk_1.groupUserVar)('threadViewOpen', { defaultValue: false });
|
|
62
60
|
async function openThread(thread) {
|
|
63
61
|
openThreadInTab(thread);
|
|
64
|
-
// let threadId = typeof thread === 'string' ? thread : thread.messageId;
|
|
65
|
-
// const message = await Messages().get(threadId);
|
|
66
|
-
// if (message) {
|
|
67
|
-
// thread = message.messageParentId || message.messageId;
|
|
68
|
-
// }
|
|
69
|
-
// const threadsWithout = openThreads().filter(t => (typeof t === 'string' && t !== threadId) || (typeof t === 'object' && t.messageId !== threadId));
|
|
70
|
-
// openThreads([thread, ...threadsWithout]);
|
|
71
|
-
// threadViewOpen(true);
|
|
72
62
|
}
|
|
73
|
-
// Thread opening function for tabs system
|
|
74
63
|
async function openThreadInTab(thread) {
|
|
75
|
-
|
|
64
|
+
const threadId = typeof thread === "string" ? thread : thread.messageId;
|
|
76
65
|
const message = await (0, peers_sdk_1.Messages)().get(threadId);
|
|
77
66
|
if (!message) {
|
|
78
|
-
console.warn(
|
|
67
|
+
console.warn("Thread message not found:", threadId);
|
|
79
68
|
return;
|
|
80
69
|
}
|
|
81
70
|
// Use parent message ID if this is a reply, otherwise use the message itself
|
|
@@ -83,27 +72,27 @@ async function openThreadInTab(thread) {
|
|
|
83
72
|
// Generate thread title from message content (strip mentions and clean formatting)
|
|
84
73
|
const cleanMessage = (0, utils_1.stripMentions)(message.message);
|
|
85
74
|
const messagePreview = cleanMessage.slice(0, 30);
|
|
86
|
-
const threadTitle = `${messagePreview}${cleanMessage.length > 30 ?
|
|
75
|
+
const threadTitle = `${messagePreview}${cleanMessage.length > 30 ? "..." : ""}` || `Thread`;
|
|
87
76
|
// // Import openNewTab dynamically to avoid circular dependency
|
|
88
77
|
// const { openNewTab } = await import('./tabs-layout/tabs-layout');
|
|
89
78
|
(0, tabs_state_1.openNewTab)({
|
|
90
|
-
packageId:
|
|
79
|
+
packageId: "system-apps",
|
|
91
80
|
path: `threads/${actualThreadId}`,
|
|
92
81
|
title: threadTitle,
|
|
93
|
-
iconClassName:
|
|
82
|
+
iconClassName: "bi-chat-dots",
|
|
94
83
|
});
|
|
95
84
|
}
|
|
96
85
|
peers_sdk_1.rpcClientCalls.setClientPath = async (url) => {
|
|
97
|
-
(0, exports.mainContentPath)(url && String(url).trim() ||
|
|
86
|
+
(0, exports.mainContentPath)((url && String(url).trim()) || "");
|
|
98
87
|
};
|
|
99
88
|
peers_sdk_1.rpcClientCalls.openThread = async (threadId) => {
|
|
100
|
-
console.warn(
|
|
89
|
+
console.warn("Opening thread:", threadId);
|
|
101
90
|
openThread(threadId);
|
|
102
91
|
};
|
|
103
92
|
exports.me = null;
|
|
104
93
|
exports.windowWidth = (0, peers_sdk_1.observable)(window.innerWidth); //.extend({ rateLimit: 500 });
|
|
105
94
|
exports.windowHeight = (0, peers_sdk_1.observable)(window.innerHeight); //.extend({ rateLimit: 500 });
|
|
106
|
-
window.addEventListener("resize", (
|
|
95
|
+
window.addEventListener("resize", (_ev) => {
|
|
107
96
|
(0, exports.windowWidth)(window.innerWidth);
|
|
108
97
|
(0, exports.windowHeight)(window.innerHeight);
|
|
109
98
|
});
|
|
@@ -121,18 +110,18 @@ async function loadGlobals() {
|
|
|
121
110
|
exports.me = await (0, peers_sdk_1.getMe)();
|
|
122
111
|
await peers_sdk_1.reloadPackagesOnPageRefresh.loadingPromise;
|
|
123
112
|
if ((0, peers_sdk_1.reloadPackagesOnPageRefresh)()) {
|
|
124
|
-
await peers_sdk_1.rpcServerCalls.addOrUpdatePackage(
|
|
113
|
+
await peers_sdk_1.rpcServerCalls.addOrUpdatePackage("updateAll");
|
|
125
114
|
}
|
|
126
115
|
await Promise.all([
|
|
127
|
-
(0, peers_sdk_1.Groups)()
|
|
116
|
+
(0, peers_sdk_1.Groups)()
|
|
117
|
+
.list()
|
|
118
|
+
.then((r) => (0, exports.groups)(r)),
|
|
128
119
|
exports._mainContentPath.loadingPromise,
|
|
129
|
-
exports.openThreads.loadingPromise,
|
|
130
|
-
exports.threadViewOpen.loadingPromise,
|
|
131
120
|
(0, peers_sdk_1.sleep)(100),
|
|
132
121
|
]);
|
|
133
122
|
function updateWindowHash() {
|
|
134
123
|
const currentPath = window.location.hash.substring(1);
|
|
135
|
-
const expectedPath = (0, exports.mainContentPath)() ||
|
|
124
|
+
const expectedPath = (0, exports.mainContentPath)() || "";
|
|
136
125
|
// console.log({ expectedPath, currentPath });
|
|
137
126
|
if (currentPath !== expectedPath) {
|
|
138
127
|
window.location.hash = expectedPath;
|
|
@@ -141,10 +130,10 @@ async function loadGlobals() {
|
|
|
141
130
|
}
|
|
142
131
|
exports.mainContentPath.subscribe(updateWindowHash);
|
|
143
132
|
updateWindowHash();
|
|
144
|
-
window.addEventListener(
|
|
133
|
+
window.addEventListener("hashchange", () => (0, exports.mainContentPath)(window.location.hash.substring(1)));
|
|
145
134
|
return true;
|
|
146
135
|
}
|
|
147
|
-
if (typeof window !==
|
|
148
|
-
// @ts-
|
|
136
|
+
if (typeof window !== "undefined") {
|
|
137
|
+
// @ts-expect-error
|
|
149
138
|
window.globals = module.exports;
|
|
150
139
|
}
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Observable } from "@peers-app/peers-sdk";
|
|
2
|
-
import React from
|
|
1
|
+
import { type Observable } from "@peers-app/peers-sdk";
|
|
2
|
+
import type React from "react";
|
|
3
3
|
/**
|
|
4
4
|
* Use this to subscribe to an observable or computed in a functional component.
|
|
5
5
|
* Uses useSyncExternalStore for proper React 18 concurrent rendering support.
|
|
@@ -31,6 +31,6 @@ export declare function useObservableState<T = undefined>(initialValue?: T, doNo
|
|
|
31
31
|
* The handler will be called immediately and whenever the subscribable changes.
|
|
32
32
|
* @param subscribable The observable to subscribe to
|
|
33
33
|
* @param onChange The function to call with the new value when the observable changes
|
|
34
|
-
|
|
35
|
-
export declare function useSubscription<T>(subscribable: Observable<T>, onChange: (value: T) =>
|
|
36
|
-
export declare function useOnScreen(ref: React.RefObject<
|
|
34
|
+
*/
|
|
35
|
+
export declare function useSubscription<T>(subscribable: Observable<T>, onChange: (value: T) => void, doNotCallOnChangeDuringSetup?: boolean): void;
|
|
36
|
+
export declare function useOnScreen(ref: React.RefObject<Element | null>): boolean;
|
package/dist/hooks.js
CHANGED
|
@@ -47,12 +47,13 @@ function useObservable(sub, deps = []) {
|
|
|
47
47
|
*/
|
|
48
48
|
function usePromise(p, initialValue, deps = []) {
|
|
49
49
|
const [data, setData] = (0, react_1.useState)(initialValue);
|
|
50
|
+
// `deps` drives when the effect re-runs; callers include `p` when it changes. Omitting `p` avoids duplicate tracking with `[...deps]`.
|
|
50
51
|
(0, react_1.useEffect)(() => {
|
|
51
52
|
let disposed = false;
|
|
52
|
-
if (typeof p ===
|
|
53
|
+
if (typeof p === "function") {
|
|
53
54
|
p = p();
|
|
54
55
|
}
|
|
55
|
-
p.then(newData => {
|
|
56
|
+
p.then((newData) => {
|
|
56
57
|
// if (!_.isEqual(newData, data) && !disposed) {
|
|
57
58
|
if (!disposed) {
|
|
58
59
|
setData(newData);
|
|
@@ -61,12 +62,13 @@ function usePromise(p, initialValue, deps = []) {
|
|
|
61
62
|
return () => {
|
|
62
63
|
disposed = true;
|
|
63
64
|
};
|
|
64
|
-
}, deps);
|
|
65
|
+
}, [...deps]);
|
|
65
66
|
return data;
|
|
66
67
|
}
|
|
67
68
|
function useObservableState(initialValue, doNotSubscribe) {
|
|
68
69
|
const [obs] = (0, react_1.useState)(() => initialValue !== undefined ? (0, peers_sdk_1.observable)(initialValue) : (0, peers_sdk_1.observable)());
|
|
69
70
|
if (!doNotSubscribe) {
|
|
71
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: when doNotSubscribe, caller keeps a stable observable without React-driven subscription (see docstring).
|
|
70
72
|
useObservable(obs);
|
|
71
73
|
}
|
|
72
74
|
return obs;
|
|
@@ -76,23 +78,31 @@ function useObservableState(initialValue, doNotSubscribe) {
|
|
|
76
78
|
* The handler will be called immediately and whenever the subscribable changes.
|
|
77
79
|
* @param subscribable The observable to subscribe to
|
|
78
80
|
* @param onChange The function to call with the new value when the observable changes
|
|
79
|
-
|
|
81
|
+
*/
|
|
80
82
|
function useSubscription(subscribable, onChange, doNotCallOnChangeDuringSetup) {
|
|
81
|
-
if (!doNotCallOnChangeDuringSetup) {
|
|
82
|
-
(0, react_1.useEffect)(() => onChange(subscribable()), []);
|
|
83
|
-
}
|
|
84
83
|
(0, react_1.useEffect)(() => {
|
|
84
|
+
if (!doNotCallOnChangeDuringSetup) {
|
|
85
|
+
onChange(subscribable());
|
|
86
|
+
}
|
|
85
87
|
const subscription = subscribable.subscribe(() => onChange(subscribable()));
|
|
86
88
|
return () => subscription.dispose();
|
|
87
|
-
}, [subscribable, onChange]);
|
|
89
|
+
}, [subscribable, onChange, doNotCallOnChangeDuringSetup]);
|
|
88
90
|
}
|
|
89
91
|
function useOnScreen(ref) {
|
|
90
92
|
const [isIntersecting, setIntersecting] = (0, react_1.useState)(false);
|
|
91
|
-
|
|
93
|
+
// Read ref.current once on mount (ref object identity is stable).
|
|
92
94
|
(0, react_1.useEffect)(() => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
const element = ref.current;
|
|
96
|
+
if (!element) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
100
|
+
setIntersecting(entry.isIntersecting);
|
|
101
|
+
});
|
|
102
|
+
observer.observe(element);
|
|
103
|
+
return () => {
|
|
104
|
+
observer.disconnect();
|
|
105
|
+
};
|
|
96
106
|
}, []);
|
|
97
107
|
return isIntersecting;
|
|
98
108
|
}
|
package/dist/hooks.test.js
CHANGED
|
@@ -1,111 +1,102 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const
|
|
7
|
-
const react_2 = require("@testing-library/react");
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
4
|
const peers_sdk_1 = require("@peers-app/peers-sdk");
|
|
5
|
+
const react_1 = require("@testing-library/react");
|
|
9
6
|
const hooks_1 = require("./hooks");
|
|
10
7
|
// Helper component to test useObservable
|
|
11
|
-
function TestComponent({ obs, testId =
|
|
8
|
+
function TestComponent({ obs, testId = "value" }) {
|
|
12
9
|
const [value, setValue] = (0, hooks_1.useObservable)(obs);
|
|
13
|
-
return (
|
|
14
|
-
react_1.default.createElement("span", { "data-testid": testId }, JSON.stringify(value)),
|
|
15
|
-
react_1.default.createElement("button", { "data-testid": "setter", onClick: () => setValue('new-value') }, "Set")));
|
|
10
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { "data-testid": testId, children: JSON.stringify(value) }), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-testid": "setter", onClick: () => setValue("new-value"), children: "Set" })] }));
|
|
16
11
|
}
|
|
17
12
|
// Helper component to test array behavior
|
|
18
13
|
function ArrayTestComponent({ obs }) {
|
|
19
14
|
const [value] = (0, hooks_1.useObservable)(obs);
|
|
20
|
-
return (
|
|
21
|
-
react_1.default.createElement("span", { "data-testid": "array-value" }, JSON.stringify(value)),
|
|
22
|
-
react_1.default.createElement("span", { "data-testid": "array-length" }, value.length)));
|
|
15
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { "data-testid": "array-value", children: JSON.stringify(value) }), (0, jsx_runtime_1.jsx)("span", { "data-testid": "array-length", children: value.length })] }));
|
|
23
16
|
}
|
|
24
17
|
// Helper component to test useObservableState
|
|
25
18
|
function ObservableStateTestComponent({ initialValue }) {
|
|
26
19
|
const obs = (0, hooks_1.useObservableState)(initialValue);
|
|
27
20
|
const [value] = (0, hooks_1.useObservable)(obs);
|
|
28
|
-
return (
|
|
29
|
-
react_1.default.createElement("span", { "data-testid": "state-value" }, value),
|
|
30
|
-
react_1.default.createElement("button", { "data-testid": "increment", onClick: () => obs(obs() + 1) }, "Increment")));
|
|
21
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { "data-testid": "state-value", children: value }), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-testid": "increment", onClick: () => obs(obs() + 1), children: "Increment" })] }));
|
|
31
22
|
}
|
|
32
|
-
describe(
|
|
33
|
-
describe(
|
|
34
|
-
it(
|
|
35
|
-
const obs = (0, peers_sdk_1.observable)(
|
|
36
|
-
(0,
|
|
37
|
-
expect(
|
|
38
|
-
});
|
|
39
|
-
it(
|
|
40
|
-
(0,
|
|
41
|
-
expect(
|
|
42
|
-
});
|
|
43
|
-
it(
|
|
44
|
-
const obs = (0, peers_sdk_1.observable)(
|
|
45
|
-
(0,
|
|
46
|
-
expect(
|
|
47
|
-
(0,
|
|
48
|
-
obs(
|
|
23
|
+
describe("useObservable", () => {
|
|
24
|
+
describe("basic functionality", () => {
|
|
25
|
+
it("should return the current value of an observable", () => {
|
|
26
|
+
const obs = (0, peers_sdk_1.observable)("hello");
|
|
27
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { obs: obs }));
|
|
28
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent('"hello"');
|
|
29
|
+
});
|
|
30
|
+
it("should return the value when passed a plain value (non-observable)", () => {
|
|
31
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { obs: "plain-value" }));
|
|
32
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent('"plain-value"');
|
|
33
|
+
});
|
|
34
|
+
it("should re-render when observable value changes", async () => {
|
|
35
|
+
const obs = (0, peers_sdk_1.observable)("initial");
|
|
36
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { obs: obs }));
|
|
37
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent('"initial"');
|
|
38
|
+
(0, react_1.act)(() => {
|
|
39
|
+
obs("updated");
|
|
49
40
|
});
|
|
50
|
-
await (0,
|
|
51
|
-
expect(
|
|
41
|
+
await (0, react_1.waitFor)(() => {
|
|
42
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent('"updated"');
|
|
52
43
|
});
|
|
53
44
|
});
|
|
54
|
-
it(
|
|
55
|
-
const obs = (0, peers_sdk_1.observable)(
|
|
56
|
-
(0,
|
|
57
|
-
(0,
|
|
58
|
-
|
|
45
|
+
it("should update the observable when setter is called", async () => {
|
|
46
|
+
const obs = (0, peers_sdk_1.observable)("initial");
|
|
47
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { obs: obs }));
|
|
48
|
+
(0, react_1.act)(() => {
|
|
49
|
+
react_1.screen.getByTestId("setter").click();
|
|
59
50
|
});
|
|
60
|
-
await (0,
|
|
61
|
-
expect(obs()).toBe(
|
|
62
|
-
expect(
|
|
51
|
+
await (0, react_1.waitFor)(() => {
|
|
52
|
+
expect(obs()).toBe("new-value");
|
|
53
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent('"new-value"');
|
|
63
54
|
});
|
|
64
55
|
});
|
|
65
|
-
it(
|
|
56
|
+
it("should handle undefined values", () => {
|
|
66
57
|
const obs = (0, peers_sdk_1.observable)(undefined);
|
|
67
|
-
(0,
|
|
58
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { obs: obs }));
|
|
68
59
|
// undefined serializes to empty string in JSON.stringify, but actually shows as nothing
|
|
69
|
-
expect(
|
|
70
|
-
});
|
|
71
|
-
it(
|
|
72
|
-
const obs = (0, peers_sdk_1.observable)({ name:
|
|
73
|
-
(0,
|
|
74
|
-
expect(
|
|
75
|
-
(0,
|
|
76
|
-
obs({ name:
|
|
60
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent("");
|
|
61
|
+
});
|
|
62
|
+
it("should handle object values", async () => {
|
|
63
|
+
const obs = (0, peers_sdk_1.observable)({ name: "test", count: 5 });
|
|
64
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { obs: obs }));
|
|
65
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent('{"name":"test","count":5}');
|
|
66
|
+
(0, react_1.act)(() => {
|
|
67
|
+
obs({ name: "updated", count: 10 });
|
|
77
68
|
});
|
|
78
|
-
await (0,
|
|
79
|
-
expect(
|
|
69
|
+
await (0, react_1.waitFor)(() => {
|
|
70
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent('{"name":"updated","count":10}');
|
|
80
71
|
});
|
|
81
72
|
});
|
|
82
73
|
});
|
|
83
|
-
describe(
|
|
84
|
-
it(
|
|
85
|
-
const obs = (0, peers_sdk_1.observable)([
|
|
86
|
-
(0,
|
|
87
|
-
expect(
|
|
88
|
-
expect(
|
|
89
|
-
});
|
|
90
|
-
it(
|
|
91
|
-
const obs = (0, peers_sdk_1.observable)([
|
|
92
|
-
(0,
|
|
93
|
-
expect(
|
|
94
|
-
(0,
|
|
95
|
-
obs([
|
|
74
|
+
describe("array handling", () => {
|
|
75
|
+
it("should handle array values", () => {
|
|
76
|
+
const obs = (0, peers_sdk_1.observable)(["a", "b", "c"]);
|
|
77
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ArrayTestComponent, { obs: obs }));
|
|
78
|
+
expect(react_1.screen.getByTestId("array-value")).toHaveTextContent('["a","b","c"]');
|
|
79
|
+
expect(react_1.screen.getByTestId("array-length")).toHaveTextContent("3");
|
|
80
|
+
});
|
|
81
|
+
it("should re-render when array is replaced with new reference", async () => {
|
|
82
|
+
const obs = (0, peers_sdk_1.observable)(["a", "b"]);
|
|
83
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ArrayTestComponent, { obs: obs }));
|
|
84
|
+
expect(react_1.screen.getByTestId("array-length")).toHaveTextContent("2");
|
|
85
|
+
(0, react_1.act)(() => {
|
|
86
|
+
obs(["a", "b", "c"]); // New array reference
|
|
96
87
|
});
|
|
97
|
-
await (0,
|
|
98
|
-
expect(
|
|
88
|
+
await (0, react_1.waitFor)(() => {
|
|
89
|
+
expect(react_1.screen.getByTestId("array-length")).toHaveTextContent("3");
|
|
99
90
|
});
|
|
100
91
|
});
|
|
101
|
-
it(
|
|
92
|
+
it("should NOT re-render when array is mutated in place (requires immutable updates)", async () => {
|
|
102
93
|
// This tests the case where an array is mutated in place and notifySubscribers is called.
|
|
103
|
-
//
|
|
94
|
+
//
|
|
104
95
|
// IMPORTANT BEHAVIORAL NOTE:
|
|
105
|
-
// The OLD implementation (useState + useEffect) had special handling that would
|
|
106
|
-
// spread the array when it detected same-reference mutation:
|
|
96
|
+
// The OLD implementation (useState + useEffect) had special handling that would
|
|
97
|
+
// spread the array when it detected same-reference mutation:
|
|
107
98
|
// if (isArray(newData) && newData === data) setData([...newData])
|
|
108
|
-
//
|
|
99
|
+
//
|
|
109
100
|
// The NEW implementation (useSyncExternalStore) does NOT do this.
|
|
110
101
|
// useSyncExternalStore uses Object.is() comparison on getSnapshot results.
|
|
111
102
|
// If the reference is the same, React won't re-render.
|
|
@@ -113,97 +104,95 @@ describe('useObservable', () => {
|
|
|
113
104
|
// This is actually the CORRECT behavior - it encourages immutable data patterns
|
|
114
105
|
// which are required for React 18 concurrent rendering to work correctly.
|
|
115
106
|
// Mutating data in place can cause tearing in concurrent mode.
|
|
116
|
-
const obs = (0, peers_sdk_1.observable)([
|
|
117
|
-
(0,
|
|
118
|
-
expect(
|
|
119
|
-
(0,
|
|
107
|
+
const obs = (0, peers_sdk_1.observable)(["a", "b"]);
|
|
108
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ArrayTestComponent, { obs: obs }));
|
|
109
|
+
expect(react_1.screen.getByTestId("array-length")).toHaveTextContent("2");
|
|
110
|
+
(0, react_1.act)(() => {
|
|
120
111
|
// Mutate the array in place (BAD PRACTICE - don't do this!)
|
|
121
112
|
const arr = obs();
|
|
122
|
-
arr.push(
|
|
113
|
+
arr.push("c");
|
|
123
114
|
obs.notifySubscribers();
|
|
124
115
|
});
|
|
125
116
|
// The observable itself has the mutated value
|
|
126
|
-
expect(obs()).toEqual([
|
|
117
|
+
expect(obs()).toEqual(["a", "b", "c"]);
|
|
127
118
|
// But the component did NOT re-render because the reference didn't change
|
|
128
119
|
// This is expected with useSyncExternalStore - it requires immutable updates
|
|
129
|
-
expect(
|
|
120
|
+
expect(react_1.screen.getByTestId("array-length")).toHaveTextContent("2");
|
|
130
121
|
});
|
|
131
|
-
it(
|
|
122
|
+
it("should re-render when array is properly updated with spread", async () => {
|
|
132
123
|
// This is the recommended pattern for updating arrays
|
|
133
|
-
const obs = (0, peers_sdk_1.observable)([
|
|
134
|
-
(0,
|
|
135
|
-
expect(
|
|
136
|
-
(0,
|
|
137
|
-
obs([...obs(),
|
|
124
|
+
const obs = (0, peers_sdk_1.observable)(["a", "b"]);
|
|
125
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ArrayTestComponent, { obs: obs }));
|
|
126
|
+
expect(react_1.screen.getByTestId("array-length")).toHaveTextContent("2");
|
|
127
|
+
(0, react_1.act)(() => {
|
|
128
|
+
obs([...obs(), "c"]); // Proper immutable update
|
|
138
129
|
});
|
|
139
|
-
await (0,
|
|
140
|
-
expect(
|
|
141
|
-
expect(
|
|
130
|
+
await (0, react_1.waitFor)(() => {
|
|
131
|
+
expect(react_1.screen.getByTestId("array-length")).toHaveTextContent("3");
|
|
132
|
+
expect(react_1.screen.getByTestId("array-value")).toHaveTextContent('["a","b","c"]');
|
|
142
133
|
});
|
|
143
134
|
});
|
|
144
135
|
});
|
|
145
|
-
describe(
|
|
146
|
-
it(
|
|
147
|
-
const obs = (0, peers_sdk_1.observable)(
|
|
136
|
+
describe("subscription management", () => {
|
|
137
|
+
it("should unsubscribe when component unmounts", () => {
|
|
138
|
+
const obs = (0, peers_sdk_1.observable)("test");
|
|
148
139
|
const initialSubscriberCount = obs.subscriberCount();
|
|
149
|
-
const { unmount } = (0,
|
|
140
|
+
const { unmount } = (0, react_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { obs: obs }));
|
|
150
141
|
// Should have subscribed
|
|
151
142
|
expect(obs.subscriberCount()).toBeGreaterThan(initialSubscriberCount);
|
|
152
143
|
unmount();
|
|
153
144
|
// Should have unsubscribed
|
|
154
145
|
expect(obs.subscriberCount()).toBe(initialSubscriberCount);
|
|
155
146
|
});
|
|
156
|
-
it(
|
|
157
|
-
const obs = (0, peers_sdk_1.observable)(
|
|
158
|
-
(0,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
(0, react_2.act)(() => {
|
|
164
|
-
obs('updated');
|
|
147
|
+
it("should handle multiple components subscribing to same observable", async () => {
|
|
148
|
+
const obs = (0, peers_sdk_1.observable)("shared");
|
|
149
|
+
(0, react_1.render)((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(TestComponent, { obs: obs, testId: "value1" }), (0, jsx_runtime_1.jsx)(TestComponent, { obs: obs, testId: "value2" })] }));
|
|
150
|
+
expect(react_1.screen.getByTestId("value1")).toHaveTextContent('"shared"');
|
|
151
|
+
expect(react_1.screen.getByTestId("value2")).toHaveTextContent('"shared"');
|
|
152
|
+
(0, react_1.act)(() => {
|
|
153
|
+
obs("updated");
|
|
165
154
|
});
|
|
166
|
-
await (0,
|
|
167
|
-
expect(
|
|
168
|
-
expect(
|
|
155
|
+
await (0, react_1.waitFor)(() => {
|
|
156
|
+
expect(react_1.screen.getByTestId("value1")).toHaveTextContent('"updated"');
|
|
157
|
+
expect(react_1.screen.getByTestId("value2")).toHaveTextContent('"updated"');
|
|
169
158
|
});
|
|
170
159
|
});
|
|
171
160
|
});
|
|
172
|
-
describe(
|
|
173
|
-
it(
|
|
161
|
+
describe("rapid updates", () => {
|
|
162
|
+
it("should handle rapid sequential updates correctly", async () => {
|
|
174
163
|
const obs = (0, peers_sdk_1.observable)(0);
|
|
175
164
|
function CounterComponent() {
|
|
176
165
|
const [value] = (0, hooks_1.useObservable)(obs);
|
|
177
|
-
return
|
|
166
|
+
return (0, jsx_runtime_1.jsx)("span", { "data-testid": "counter", children: value });
|
|
178
167
|
}
|
|
179
|
-
(0,
|
|
180
|
-
(0,
|
|
168
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(CounterComponent, {}));
|
|
169
|
+
(0, react_1.act)(() => {
|
|
181
170
|
for (let i = 1; i <= 10; i++) {
|
|
182
171
|
obs(i);
|
|
183
172
|
}
|
|
184
173
|
});
|
|
185
|
-
await (0,
|
|
186
|
-
expect(
|
|
174
|
+
await (0, react_1.waitFor)(() => {
|
|
175
|
+
expect(react_1.screen.getByTestId("counter")).toHaveTextContent("10");
|
|
187
176
|
});
|
|
188
177
|
});
|
|
189
178
|
});
|
|
190
179
|
});
|
|
191
|
-
describe(
|
|
192
|
-
it(
|
|
193
|
-
(0,
|
|
194
|
-
expect(
|
|
180
|
+
describe("useObservableState", () => {
|
|
181
|
+
it("should create an observable with the initial value", () => {
|
|
182
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ObservableStateTestComponent, { initialValue: 42 }));
|
|
183
|
+
expect(react_1.screen.getByTestId("state-value")).toHaveTextContent("42");
|
|
195
184
|
});
|
|
196
|
-
it(
|
|
197
|
-
(0,
|
|
198
|
-
expect(
|
|
199
|
-
(0,
|
|
200
|
-
|
|
185
|
+
it("should re-render when the observable is updated", async () => {
|
|
186
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ObservableStateTestComponent, { initialValue: 0 }));
|
|
187
|
+
expect(react_1.screen.getByTestId("state-value")).toHaveTextContent("0");
|
|
188
|
+
(0, react_1.act)(() => {
|
|
189
|
+
react_1.screen.getByTestId("increment").click();
|
|
201
190
|
});
|
|
202
|
-
await (0,
|
|
203
|
-
expect(
|
|
191
|
+
await (0, react_1.waitFor)(() => {
|
|
192
|
+
expect(react_1.screen.getByTestId("state-value")).toHaveTextContent("1");
|
|
204
193
|
});
|
|
205
194
|
});
|
|
206
|
-
it(
|
|
195
|
+
it("should maintain the same observable instance across re-renders", async () => {
|
|
207
196
|
let capturedObs = null;
|
|
208
197
|
function CaptureObsComponent() {
|
|
209
198
|
const obs = (0, hooks_1.useObservableState)(0);
|
|
@@ -211,37 +200,32 @@ describe('useObservableState', () => {
|
|
|
211
200
|
capturedObs = obs;
|
|
212
201
|
}
|
|
213
202
|
const [value] = (0, hooks_1.useObservable)(obs);
|
|
214
|
-
return (
|
|
215
|
-
react_1.default.createElement("span", { "data-testid": "value" }, value),
|
|
216
|
-
react_1.default.createElement("span", { "data-testid": "same-obs" }, obs === capturedObs ? 'same' : 'different'),
|
|
217
|
-
react_1.default.createElement("button", { "data-testid": "update", onClick: () => obs(obs() + 1) }, "Update")));
|
|
203
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { "data-testid": "value", children: value }), (0, jsx_runtime_1.jsx)("span", { "data-testid": "same-obs", children: obs === capturedObs ? "same" : "different" }), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-testid": "update", onClick: () => obs(obs() + 1), children: "Update" })] }));
|
|
218
204
|
}
|
|
219
|
-
(0,
|
|
220
|
-
expect(
|
|
205
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(CaptureObsComponent, {}));
|
|
206
|
+
expect(react_1.screen.getByTestId("same-obs")).toHaveTextContent("same");
|
|
221
207
|
// Trigger a re-render by updating the observable
|
|
222
|
-
(0,
|
|
223
|
-
|
|
208
|
+
(0, react_1.act)(() => {
|
|
209
|
+
react_1.screen.getByTestId("update").click();
|
|
224
210
|
});
|
|
225
|
-
await (0,
|
|
226
|
-
expect(
|
|
227
|
-
expect(
|
|
211
|
+
await (0, react_1.waitFor)(() => {
|
|
212
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent("1");
|
|
213
|
+
expect(react_1.screen.getByTestId("same-obs")).toHaveTextContent("same");
|
|
228
214
|
});
|
|
229
215
|
});
|
|
230
|
-
it(
|
|
216
|
+
it("should not subscribe when doNotSubscribe is true", () => {
|
|
231
217
|
function NoSubscribeComponent() {
|
|
232
218
|
const obs = (0, hooks_1.useObservableState)(0, true); // doNotSubscribe = true
|
|
233
|
-
return (
|
|
234
|
-
react_1.default.createElement("span", { "data-testid": "value" }, obs()),
|
|
235
|
-
react_1.default.createElement("button", { "data-testid": "update", onClick: () => obs(obs() + 1) }, "Update")));
|
|
219
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { "data-testid": "value", children: obs() }), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-testid": "update", onClick: () => obs(obs() + 1), children: "Update" })] }));
|
|
236
220
|
}
|
|
237
|
-
(0,
|
|
238
|
-
expect(
|
|
221
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(NoSubscribeComponent, {}));
|
|
222
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent("0");
|
|
239
223
|
// Update won't cause re-render since we're not subscribed
|
|
240
|
-
(0,
|
|
241
|
-
|
|
224
|
+
(0, react_1.act)(() => {
|
|
225
|
+
react_1.screen.getByTestId("update").click();
|
|
242
226
|
});
|
|
243
227
|
// Value in DOM should still show 0 since component didn't re-render
|
|
244
228
|
// But the observable itself has been updated
|
|
245
|
-
expect(
|
|
229
|
+
expect(react_1.screen.getByTestId("value")).toHaveTextContent("0");
|
|
246
230
|
});
|
|
247
231
|
});
|