@dxos/plugin-search 0.8.4-main.bc674ce → 0.8.4-main.bcb3aa67d6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +0 -1
  2. package/dist/lib/browser/index.mjs +306 -52
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/types/src/SearchPlugin.d.ts.map +1 -1
  6. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  7. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  8. package/dist/types/src/capabilities/index.d.ts +5 -3
  9. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  10. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  11. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  12. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  13. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  14. package/dist/types/src/components/SearchResultStack/SearchResultStack.d.ts +13 -0
  15. package/dist/types/src/components/SearchResultStack/SearchResultStack.d.ts.map +1 -0
  16. package/dist/types/src/components/SearchResultStack/index.d.ts +2 -0
  17. package/dist/types/src/components/SearchResultStack/index.d.ts.map +1 -0
  18. package/dist/types/src/components/index.d.ts +1 -3
  19. package/dist/types/src/components/index.d.ts.map +1 -1
  20. package/dist/types/src/constants.d.ts +2 -0
  21. package/dist/types/src/constants.d.ts.map +1 -0
  22. package/dist/types/src/containers/SearchArticle/SearchArticle.d.ts +7 -0
  23. package/dist/types/src/containers/SearchArticle/SearchArticle.d.ts.map +1 -0
  24. package/dist/types/src/containers/SearchArticle/SearchArticle.stories.d.ts +15 -0
  25. package/dist/types/src/containers/SearchArticle/SearchArticle.stories.d.ts.map +1 -0
  26. package/dist/types/src/containers/SearchArticle/index.d.ts +3 -0
  27. package/dist/types/src/containers/SearchArticle/index.d.ts.map +1 -0
  28. package/dist/types/src/containers/SearchDialog/SearchDialog.d.ts +8 -0
  29. package/dist/types/src/containers/SearchDialog/SearchDialog.d.ts.map +1 -0
  30. package/dist/types/src/containers/SearchDialog/SearchDialog.stories.d.ts +17 -0
  31. package/dist/types/src/containers/SearchDialog/SearchDialog.stories.d.ts.map +1 -0
  32. package/dist/types/src/containers/SearchDialog/index.d.ts +3 -0
  33. package/dist/types/src/containers/SearchDialog/index.d.ts.map +1 -0
  34. package/dist/types/src/containers/index.d.ts +5 -0
  35. package/dist/types/src/containers/index.d.ts.map +1 -0
  36. package/dist/types/src/hooks/sync.d.ts +1 -1
  37. package/dist/types/src/hooks/sync.d.ts.map +1 -1
  38. package/dist/types/src/hooks/useGlobalSearch.d.ts +2 -2
  39. package/dist/types/src/hooks/useGlobalSearch.d.ts.map +1 -1
  40. package/dist/types/src/hooks/useWebSearch.d.ts +1 -1
  41. package/dist/types/src/hooks/useWebSearch.d.ts.map +1 -1
  42. package/dist/types/src/operations/definitions.d.ts +3 -0
  43. package/dist/types/src/operations/definitions.d.ts.map +1 -0
  44. package/dist/types/src/operations/index.d.ts +4 -0
  45. package/dist/types/src/operations/index.d.ts.map +1 -0
  46. package/dist/types/src/operations/open-search.d.ts +5 -0
  47. package/dist/types/src/operations/open-search.d.ts.map +1 -0
  48. package/dist/types/src/translations.d.ts +15 -9
  49. package/dist/types/src/translations.d.ts.map +1 -1
  50. package/dist/types/src/types/index.d.ts +0 -1
  51. package/dist/types/src/types/index.d.ts.map +1 -1
  52. package/dist/types/src/types/search.d.ts +1 -16
  53. package/dist/types/src/types/search.d.ts.map +1 -1
  54. package/dist/types/tsconfig.tsbuildinfo +1 -1
  55. package/package.json +53 -41
  56. package/src/SearchPlugin.tsx +11 -9
  57. package/src/capabilities/{app-graph-builder/app-graph-builder.ts → app-graph-builder.ts} +16 -20
  58. package/src/capabilities/index.ts +9 -3
  59. package/src/capabilities/operation-handler.ts +16 -0
  60. package/src/capabilities/react-surface.tsx +62 -0
  61. package/src/components/SearchResultStack/SearchResultStack.tsx +118 -0
  62. package/src/components/SearchResultStack/index.ts +5 -0
  63. package/src/components/index.ts +1 -3
  64. package/src/constants.ts +7 -0
  65. package/src/containers/SearchArticle/SearchArticle.stories.tsx +80 -0
  66. package/src/containers/SearchArticle/SearchArticle.tsx +63 -0
  67. package/src/containers/SearchArticle/index.ts +7 -0
  68. package/src/containers/SearchDialog/SearchDialog.stories.tsx +109 -0
  69. package/src/containers/SearchDialog/SearchDialog.tsx +100 -0
  70. package/src/containers/SearchDialog/index.ts +6 -0
  71. package/src/containers/index.ts +10 -0
  72. package/src/hooks/sync.ts +1 -1
  73. package/src/hooks/useGlobalSearch.tsx +3 -3
  74. package/src/hooks/useWebSearch.ts +1 -1
  75. package/src/meta.ts +2 -2
  76. package/src/operations/definitions.ts +17 -0
  77. package/src/operations/index.ts +9 -0
  78. package/src/operations/open-search.ts +25 -0
  79. package/src/search/exa.ts +1 -1
  80. package/src/translations.ts +10 -9
  81. package/src/types/index.ts +0 -1
  82. package/src/types/search.ts +1 -19
  83. package/dist/lib/browser/app-graph-builder-KZ3V2E5U.mjs +0 -81
  84. package/dist/lib/browser/app-graph-builder-KZ3V2E5U.mjs.map +0 -7
  85. package/dist/lib/browser/chunk-HRIWTRJV.mjs +0 -22
  86. package/dist/lib/browser/chunk-HRIWTRJV.mjs.map +0 -7
  87. package/dist/lib/browser/chunk-I7YWQSUZ.mjs +0 -26
  88. package/dist/lib/browser/chunk-I7YWQSUZ.mjs.map +0 -7
  89. package/dist/lib/browser/chunk-ZRJJXRGF.mjs +0 -282
  90. package/dist/lib/browser/chunk-ZRJJXRGF.mjs.map +0 -7
  91. package/dist/lib/browser/operation-resolver-6MBOKZQH.mjs +0 -25
  92. package/dist/lib/browser/operation-resolver-6MBOKZQH.mjs.map +0 -7
  93. package/dist/lib/browser/react-surface-RVLK6KJ5.mjs +0 -368
  94. package/dist/lib/browser/react-surface-RVLK6KJ5.mjs.map +0 -7
  95. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +0 -6
  96. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
  97. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
  98. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
  99. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  100. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  101. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  102. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  103. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  104. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  105. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
  106. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  107. package/dist/types/src/components/SearchDialog.d.ts +0 -7
  108. package/dist/types/src/components/SearchDialog.d.ts.map +0 -1
  109. package/dist/types/src/components/SearchMain.d.ts +0 -6
  110. package/dist/types/src/components/SearchMain.d.ts.map +0 -1
  111. package/dist/types/src/components/SearchMain.stories.d.ts +0 -31
  112. package/dist/types/src/components/SearchMain.stories.d.ts.map +0 -1
  113. package/dist/types/src/components/SpaceMain.d.ts +0 -9
  114. package/dist/types/src/components/SpaceMain.d.ts.map +0 -1
  115. package/dist/types/src/types/action.d.ts +0 -16
  116. package/dist/types/src/types/action.d.ts.map +0 -1
  117. package/src/capabilities/app-graph-builder/index.ts +0 -7
  118. package/src/capabilities/operation-resolver/index.ts +0 -7
  119. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -23
  120. package/src/capabilities/react-surface/index.ts +0 -7
  121. package/src/capabilities/react-surface/react-surface.tsx +0 -70
  122. package/src/components/SearchDialog.tsx +0 -130
  123. package/src/components/SearchMain.stories.tsx +0 -90
  124. package/src/components/SearchMain.tsx +0 -83
  125. package/src/components/SpaceMain.tsx +0 -169
  126. package/src/types/action.tsx +0 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-search",
3
- "version": "0.8.4-main.bc674ce",
3
+ "version": "0.8.4-main.bcb3aa67d6",
4
4
  "description": "Search plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -12,6 +12,15 @@
12
12
  "author": "DXOS.org",
13
13
  "sideEffects": true,
14
14
  "type": "module",
15
+ "imports": {
16
+ "#capabilities": "./src/capabilities/index.ts",
17
+ "#components": "./src/components/index.ts",
18
+ "#containers": "./src/containers/index.ts",
19
+ "#hooks": "./src/hooks/index.ts",
20
+ "#meta": "./src/meta.ts",
21
+ "#operations": "./src/operations/index.ts",
22
+ "#types": "./src/types/index.ts"
23
+ },
15
24
  "exports": {
16
25
  ".": {
17
26
  "source": "./src/index.ts",
@@ -28,56 +37,59 @@
28
37
  "dependencies": {
29
38
  "exa-js": "^1.5.12",
30
39
  "main-thread-scheduling": "^14.1.1",
31
- "@dxos/assistant": "0.8.4-main.bc674ce",
32
- "@dxos/ai": "0.8.4-main.bc674ce",
33
- "@dxos/app-framework": "0.8.4-main.bc674ce",
34
- "@dxos/async": "0.8.4-main.bc674ce",
35
- "@dxos/debug": "0.8.4-main.bc674ce",
36
- "@dxos/echo": "0.8.4-main.bc674ce",
37
- "@dxos/echo-protocol": "0.8.4-main.bc674ce",
38
- "@dxos/echo-query": "0.8.4-main.bc674ce",
39
- "@dxos/blueprints": "0.8.4-main.bc674ce",
40
- "@dxos/effect": "0.8.4-main.bc674ce",
41
- "@dxos/invariant": "0.8.4-main.bc674ce",
42
- "@dxos/operation": "0.8.4-main.bc674ce",
43
- "@dxos/plugin-deck": "0.8.4-main.bc674ce",
44
- "@dxos/plugin-graph": "0.8.4-main.bc674ce",
45
- "@dxos/log": "0.8.4-main.bc674ce",
46
- "@dxos/plugin-space": "0.8.4-main.bc674ce",
47
- "@dxos/react-client": "0.8.4-main.bc674ce",
48
- "@dxos/react-ui-mosaic": "0.8.4-main.bc674ce",
49
- "@dxos/react-ui-components": "0.8.4-main.bc674ce",
50
- "@dxos/react-ui-searchlist": "0.8.4-main.bc674ce",
51
- "@dxos/schema": "0.8.4-main.bc674ce",
52
- "@dxos/react-ui-stack": "0.8.4-main.bc674ce",
53
- "@dxos/types": "0.8.4-main.bc674ce",
54
- "@dxos/util": "0.8.4-main.bc674ce",
55
- "@dxos/plugin-client": "0.8.4-main.bc674ce"
40
+ "@dxos/ai": "0.8.4-main.bcb3aa67d6",
41
+ "@dxos/app-toolkit": "0.8.4-main.bcb3aa67d6",
42
+ "@dxos/app-framework": "0.8.4-main.bcb3aa67d6",
43
+ "@dxos/assistant": "0.8.4-main.bcb3aa67d6",
44
+ "@dxos/async": "0.8.4-main.bcb3aa67d6",
45
+ "@dxos/blueprints": "0.8.4-main.bcb3aa67d6",
46
+ "@dxos/debug": "0.8.4-main.bcb3aa67d6",
47
+ "@dxos/echo": "0.8.4-main.bcb3aa67d6",
48
+ "@dxos/echo-protocol": "0.8.4-main.bcb3aa67d6",
49
+ "@dxos/effect": "0.8.4-main.bcb3aa67d6",
50
+ "@dxos/invariant": "0.8.4-main.bcb3aa67d6",
51
+ "@dxos/operation": "0.8.4-main.bcb3aa67d6",
52
+ "@dxos/log": "0.8.4-main.bcb3aa67d6",
53
+ "@dxos/plugin-client": "0.8.4-main.bcb3aa67d6",
54
+ "@dxos/plugin-space": "0.8.4-main.bcb3aa67d6",
55
+ "@dxos/plugin-graph": "0.8.4-main.bcb3aa67d6",
56
+ "@dxos/plugin-deck": "0.8.4-main.bcb3aa67d6",
57
+ "@dxos/react-client": "0.8.4-main.bcb3aa67d6",
58
+ "@dxos/echo-query": "0.8.4-main.bcb3aa67d6",
59
+ "@dxos/react-ui-attention": "0.8.4-main.bcb3aa67d6",
60
+ "@dxos/react-ui-components": "0.8.4-main.bcb3aa67d6",
61
+ "@dxos/react-ui-menu": "0.8.4-main.bcb3aa67d6",
62
+ "@dxos/react-ui-search": "0.8.4-main.bcb3aa67d6",
63
+ "@dxos/react-ui-mosaic": "0.8.4-main.bcb3aa67d6",
64
+ "@dxos/react-ui-stack": "0.8.4-main.bcb3aa67d6",
65
+ "@dxos/util": "0.8.4-main.bcb3aa67d6",
66
+ "@dxos/schema": "0.8.4-main.bcb3aa67d6",
67
+ "@dxos/types": "0.8.4-main.bcb3aa67d6"
56
68
  },
57
69
  "devDependencies": {
58
- "@effect-atom/atom-react": "^0.4.6",
59
- "@effect/platform": "0.93.6",
70
+ "@effect-atom/atom-react": "^0.5.0",
71
+ "@effect/platform": "0.94.4",
60
72
  "@types/react": "~19.2.7",
61
73
  "@types/react-dom": "~19.2.3",
62
- "effect": "3.19.11",
74
+ "effect": "3.20.0",
63
75
  "react": "~19.2.3",
64
76
  "react-dom": "~19.2.3",
65
- "vite": "7.1.9",
66
- "@dxos/plugin-preview": "0.8.4-main.bc674ce",
67
- "@dxos/plugin-testing": "0.8.4-main.bc674ce",
68
- "@dxos/random": "0.8.4-main.bc674ce",
69
- "@dxos/react-ui": "0.8.4-main.bc674ce",
70
- "@dxos/storybook-utils": "0.8.4-main.bc674ce",
71
- "@dxos/ui-theme": "0.8.4-main.bc674ce"
77
+ "vite": "^7.1.11",
78
+ "@dxos/plugin-testing": "0.8.4-main.bcb3aa67d6",
79
+ "@dxos/plugin-preview": "0.8.4-main.bcb3aa67d6",
80
+ "@dxos/random": "0.8.4-main.bcb3aa67d6",
81
+ "@dxos/react-ui": "0.8.4-main.bcb3aa67d6",
82
+ "@dxos/ui-theme": "0.8.4-main.bcb3aa67d6",
83
+ "@dxos/storybook-utils": "0.8.4-main.bcb3aa67d6"
72
84
  },
73
85
  "peerDependencies": {
74
- "@effect-atom/atom-react": "^0.4.6",
75
- "@effect/platform": "0.93.6",
76
- "effect": "3.19.11",
86
+ "@effect-atom/atom-react": "^0.5.0",
87
+ "@effect/platform": "0.94.4",
88
+ "effect": "3.20.0",
77
89
  "react": "~19.2.3",
78
90
  "react-dom": "~19.2.3",
79
- "@dxos/ui-theme": "0.8.4-main.bc674ce",
80
- "@dxos/react-ui": "0.8.4-main.bc674ce"
91
+ "@dxos/react-ui": "0.8.4-main.bcb3aa67d6",
92
+ "@dxos/ui-theme": "0.8.4-main.bcb3aa67d6"
81
93
  },
82
94
  "publishConfig": {
83
95
  "access": "public"
@@ -2,16 +2,18 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Common, Plugin } from '@dxos/app-framework';
5
+ import { Plugin } from '@dxos/app-framework';
6
+ import { AppPlugin } from '@dxos/app-toolkit';
6
7
 
7
- import { AppGraphBuilder, OperationResolver, ReactSurface } from './capabilities';
8
- import { SEARCH_RESULT, meta } from './meta';
8
+ import { SEARCH_RESULT, meta } from '#meta';
9
9
  import { translations } from './translations';
10
- import { type SearchResult } from './types';
10
+ import { type SearchResult } from '#types';
11
+
12
+ import { AppGraphBuilder, OperationHandler, ReactSurface } from '#capabilities';
11
13
 
12
14
  export const SearchPlugin = Plugin.define(meta).pipe(
13
- Common.Plugin.addTranslationsModule({ translations }),
14
- Common.Plugin.addMetadataModule({
15
+ AppPlugin.addAppGraphModule({ activate: AppGraphBuilder }),
16
+ AppPlugin.addMetadataModule({
15
17
  metadata: {
16
18
  id: SEARCH_RESULT,
17
19
  metadata: {
@@ -28,8 +30,8 @@ export const SearchPlugin = Plugin.define(meta).pipe(
28
30
  },
29
31
  },
30
32
  }),
31
- Common.Plugin.addAppGraphModule({ activate: AppGraphBuilder }),
32
- Common.Plugin.addOperationResolverModule({ activate: OperationResolver }),
33
- Common.Plugin.addSurfaceModule({ activate: ReactSurface }),
33
+ AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),
34
+ AppPlugin.addSurfaceModule({ activate: ReactSurface }),
35
+ AppPlugin.addTranslationsModule({ translations }),
34
36
  Plugin.make,
35
37
  );
@@ -4,40 +4,36 @@
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
- import { Capability, Common } from '@dxos/app-framework';
7
+ import { Capability } from '@dxos/app-framework';
8
+ import { AppCapabilities, AppNode, getSpaceIdFromPath } from '@dxos/app-toolkit';
9
+ import { linkedSegment } from '@dxos/react-ui-attention';
8
10
  import { Operation } from '@dxos/operation';
9
- import { ClientCapabilities } from '@dxos/plugin-client';
10
- import { ATTENDABLE_PATH_SEPARATOR, DECK_COMPANION_TYPE } from '@dxos/plugin-deck/types';
11
+ import { ClientCapabilities } from '@dxos/plugin-client/types';
11
12
  import { GraphBuilder, NodeMatcher } from '@dxos/plugin-graph';
12
- import { parseId } from '@dxos/react-client/echo';
13
13
 
14
- import { meta } from '../../meta';
15
- import { SearchOperation } from '../../types';
14
+ import { meta } from '#meta';
15
+ import { SearchOperation } from '#operations';
16
16
 
17
17
  export default Capability.makeModule(
18
18
  Effect.fnUntraced(function* () {
19
19
  const extensions = yield* Effect.all([
20
20
  GraphBuilder.createExtension({
21
- id: `${meta.id}/space-search`,
21
+ id: `${meta.id}.space-search`,
22
22
  match: NodeMatcher.whenRoot,
23
23
  connector: Effect.fnUntraced(function* (node, get) {
24
24
  const client = yield* Capability.get(ClientCapabilities.Client);
25
- const layoutAtom = get(yield* Capability.atom(Common.Capability.Layout))[0];
25
+ const layoutAtom = get(yield* Capability.atom(AppCapabilities.Layout))[0];
26
26
  const layout = layoutAtom ? get(layoutAtom) : undefined;
27
- const { spaceId } = parseId(layout?.workspace);
27
+ const spaceId = layout?.workspace ? getSpaceIdFromPath(layout.workspace) : undefined;
28
28
  const space = spaceId ? client.spaces.get(spaceId) : null;
29
29
 
30
30
  return [
31
- {
32
- id: [node.id, 'search'].join(ATTENDABLE_PATH_SEPARATOR),
33
- type: DECK_COMPANION_TYPE,
31
+ AppNode.makeDeckCompanion({
32
+ id: linkedSegment('search'),
33
+ label: ['search.label', { ns: meta.id }],
34
+ icon: 'ph--magnifying-glass--regular',
34
35
  data: space,
35
- properties: {
36
- label: ['search label', { ns: meta.id }],
37
- icon: 'ph--magnifying-glass--regular',
38
- disposition: 'hidden',
39
- },
40
- },
36
+ }),
41
37
  ];
42
38
  }),
43
39
  }),
@@ -53,7 +49,7 @@ export default Capability.makeModule(
53
49
  return false;
54
50
  }),
55
51
  properties: {
56
- label: ['search action label', { ns: meta.id }],
52
+ label: ['search-action.label', { ns: meta.id }],
57
53
  icon: 'ph--magnifying-glass--regular',
58
54
  keyBinding: {
59
55
  macos: 'shift+meta+f',
@@ -65,6 +61,6 @@ export default Capability.makeModule(
65
61
  }),
66
62
  ]);
67
63
 
68
- return Capability.contributes(Common.Capability.AppGraphBuilder, extensions);
64
+ return Capability.contributes(AppCapabilities.AppGraphBuilder, extensions);
69
65
  }),
70
66
  );
@@ -2,6 +2,12 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './app-graph-builder';
6
- export * from './operation-resolver';
7
- export * from './react-surface';
5
+ import { Capability } from '@dxos/app-framework';
6
+ import { OperationHandlerSet } from '@dxos/operation';
7
+
8
+ export const AppGraphBuilder = Capability.lazy('AppGraphBuilder', () => import('./app-graph-builder'));
9
+ export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
10
+ 'OperationHandler',
11
+ () => import('./operation-handler'),
12
+ );
13
+ export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import type { OperationHandlerSet } from '@dxos/operation';
9
+
10
+ import { SearchOperationHandlerSet } from '#operations';
11
+
12
+ export default Capability.makeModule<OperationHandlerSet.OperationHandlerSet>(
13
+ Effect.fnUntraced(function* () {
14
+ return Capability.contributes(Capabilities.OperationHandler, SearchOperationHandlerSet);
15
+ }),
16
+ );
@@ -0,0 +1,62 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import React from 'react';
7
+
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { Surface } from '@dxos/app-framework/ui';
10
+ import { useActiveSpace } from '@dxos/app-toolkit/ui';
11
+ import { type Space, isSpace } from '@dxos/react-client/echo';
12
+
13
+ import { SEARCH_DIALOG } from '../constants';
14
+ import { SearchArticle, SearchDialog, type SearchDialogProps } from '#containers';
15
+ import { SearchContextProvider } from '#hooks';
16
+
17
+ export default Capability.makeModule(() =>
18
+ Effect.succeed(
19
+ Capability.contributes(Capabilities.ReactSurface, [
20
+ Surface.create({
21
+ id: SEARCH_DIALOG,
22
+ role: 'dialog',
23
+ filter: (data): data is { props: SearchDialogProps } => data.component === SEARCH_DIALOG,
24
+ component: ({ data }) => (
25
+ <SearchContextProvider>
26
+ <SearchDialog {...data.props} />
27
+ </SearchContextProvider>
28
+ ),
29
+ }),
30
+ Surface.create({
31
+ id: `${SEARCH_DIALOG}.search-input`,
32
+ role: 'search-input',
33
+ component: () => {
34
+ const space = useActiveSpace();
35
+
36
+ return (
37
+ <SearchContextProvider>
38
+ <SearchArticle space={space} />
39
+ </SearchContextProvider>
40
+ );
41
+ },
42
+ }),
43
+ Surface.create({
44
+ id: `${SEARCH_DIALOG}.search`,
45
+ role: 'deck-companion--search',
46
+ filter: (data): data is { subject: Space } => isSpace(data.subject),
47
+ component: ({ data }) => {
48
+ const space = data.subject;
49
+ if (!space) {
50
+ return null;
51
+ }
52
+
53
+ return (
54
+ <SearchContextProvider>
55
+ <SearchArticle space={space} />
56
+ </SearchContextProvider>
57
+ );
58
+ },
59
+ }),
60
+ ]),
61
+ ),
62
+ );
@@ -0,0 +1,118 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React, { type KeyboardEvent, forwardRef, useCallback, useMemo, useState } from 'react';
6
+
7
+ import { Surface } from '@dxos/app-framework/ui';
8
+ import { useObjectMenuItems } from '@dxos/app-toolkit/ui';
9
+ import { Entity } from '@dxos/echo';
10
+ import { Card, Toolbar } from '@dxos/react-ui';
11
+ import { Menu } from '@dxos/react-ui-menu';
12
+ import { type MosaicTileProps, Mosaic, useMosaicContainer, Focus } from '@dxos/react-ui-mosaic';
13
+ import { ScrollArea } from '@dxos/react-ui';
14
+ import { type SearchResult } from '@dxos/react-ui-search';
15
+ import { composable, composableProps } from '@dxos/ui-theme';
16
+
17
+ //
18
+ // SearchResultStack
19
+ //
20
+
21
+ export type SearchResultStackProps = {
22
+ results: SearchResult[];
23
+ };
24
+
25
+ export const SearchResultStack = composable<HTMLDivElement, SearchResultStackProps>(
26
+ ({ results, ...props }, forwardedRef) => {
27
+ const [viewport, setViewport] = useState<HTMLElement | null>(null);
28
+ const items = useMemo(() => results.map((result) => ({ result })), [results]);
29
+
30
+ const handleKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {
31
+ if (event.key === 'Enter') {
32
+ event.preventDefault();
33
+ (document.activeElement as HTMLElement | null)?.click();
34
+ }
35
+ }, []);
36
+
37
+ return (
38
+ <Focus.Group asChild {...composableProps(props)} onKeyDown={handleKeyDown} ref={forwardedRef}>
39
+ <Mosaic.Container asChild>
40
+ <ScrollArea.Root orientation='vertical' padding centered>
41
+ <ScrollArea.Viewport ref={setViewport}>
42
+ <Mosaic.VirtualStack
43
+ Tile={SearchResultTile}
44
+ classNames='my-2'
45
+ gap={8}
46
+ items={items}
47
+ draggable={false}
48
+ getId={(item) => item.result.id}
49
+ getScrollElement={() => viewport}
50
+ estimateSize={() => 150}
51
+ />
52
+ </ScrollArea.Viewport>
53
+ </ScrollArea.Root>
54
+ </Mosaic.Container>
55
+ </Focus.Group>
56
+ );
57
+ },
58
+ );
59
+
60
+ SearchResultStack.displayName = 'SearchResultStack';
61
+
62
+ //
63
+ // SearchResultTile
64
+ //
65
+
66
+ type SearchResultTileData = {
67
+ result: SearchResult;
68
+ };
69
+
70
+ type SearchResultTileProps = Pick<MosaicTileProps<SearchResultTileData>, 'location' | 'data' | 'current'>;
71
+
72
+ /**
73
+ * Search result tile that uses Surface to render object content.
74
+ */
75
+ const SearchResultTile = forwardRef<HTMLDivElement, SearchResultTileProps>(
76
+ ({ data, location, current }, forwardedRef) => {
77
+ const { result } = data;
78
+ const menuItems = useObjectMenuItems(result.object);
79
+ const { setCurrentId } = useMosaicContainer('SearchResultTile');
80
+
81
+ const handleCurrentChange = useCallback(() => {
82
+ setCurrentId(result.id);
83
+ }, [result.id, setCurrentId]);
84
+
85
+ return (
86
+ <Menu.Root>
87
+ <Mosaic.Tile
88
+ asChild
89
+ classNames='dx-hover dx-current dx-selected'
90
+ id={result.id}
91
+ data={data}
92
+ location={location}
93
+ >
94
+ <Focus.Item asChild current={current} onCurrentChange={handleCurrentChange}>
95
+ <Card.Root ref={forwardedRef} role='button' classNames='cursor-pointer'>
96
+ <Card.Toolbar>
97
+ <Card.IconBlock />
98
+ <Card.Title>{result.label ?? (result.object && Entity.getLabel(result.object))}</Card.Title>
99
+ <Menu.Trigger asChild disabled={!menuItems?.length}>
100
+ <Toolbar.IconButton
101
+ iconOnly
102
+ variant='ghost'
103
+ icon='ph--dots-three-vertical--regular'
104
+ label='Actions'
105
+ />
106
+ </Menu.Trigger>
107
+ <Menu.Content items={menuItems} />
108
+ </Card.Toolbar>
109
+ <Surface.Surface role='card--content' data={{ subject: result.object }} limit={1} />
110
+ </Card.Root>
111
+ </Focus.Item>
112
+ </Mosaic.Tile>
113
+ </Menu.Root>
114
+ );
115
+ },
116
+ );
117
+
118
+ SearchResultTile.displayName = 'SearchResultTile';
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './SearchResultStack';
@@ -2,6 +2,4 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export * from './SearchMain';
6
- export * from './SearchDialog';
7
- export * from './SpaceMain';
5
+ export * from './SearchResultStack';
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { meta } from '#meta';
6
+
7
+ export const SEARCH_DIALOG = `${meta.id}.SearchDialog`;
@@ -0,0 +1,80 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Effect from 'effect/Effect';
7
+ import React from 'react';
8
+
9
+ import { Capability } from '@dxos/app-framework';
10
+ import { withPluginManager } from '@dxos/app-framework/testing';
11
+ import { AppCapabilities } from '@dxos/app-toolkit';
12
+ import { ClientPlugin } from '@dxos/plugin-client';
13
+ import { initializeIdentity } from '@dxos/plugin-client/testing';
14
+ import { corePlugins, StorybookPlugin } from '@dxos/plugin-testing';
15
+ import { faker } from '@dxos/random';
16
+ import { useSpaces } from '@dxos/react-client/echo';
17
+ import { Loading, withLayout } from '@dxos/react-ui/testing';
18
+ import { createObjectFactory } from '@dxos/schema/testing';
19
+ import { Organization, Person } from '@dxos/types';
20
+
21
+ import { SearchContextProvider } from '#hooks';
22
+ import { translations } from '../../translations';
23
+
24
+ import { SearchArticle } from './SearchArticle';
25
+
26
+ faker.seed(0);
27
+
28
+ const DefaultStory = () => {
29
+ const spaces = useSpaces();
30
+ const space = spaces[spaces.length - 1];
31
+ if (!space) {
32
+ return <Loading />;
33
+ }
34
+
35
+ return (
36
+ <SearchContextProvider>
37
+ <SearchArticle space={space} />
38
+ </SearchContextProvider>
39
+ );
40
+ };
41
+
42
+ const meta = {
43
+ title: 'plugins/plugin-search/containers/SearchArticle',
44
+ component: SearchArticle,
45
+ render: DefaultStory,
46
+ decorators: [
47
+ withLayout({ layout: 'column' }),
48
+ withPluginManager({
49
+ capabilities: [Capability.contributes(AppCapabilities.Translations, translations)],
50
+ plugins: [
51
+ ...corePlugins(),
52
+ StorybookPlugin({}),
53
+ ClientPlugin({
54
+ types: [Organization.Organization, Person.Person],
55
+ onClientInitialized: ({ client }) =>
56
+ Effect.gen(function* () {
57
+ const { personalSpace } = yield* initializeIdentity(client);
58
+
59
+ const factory = createObjectFactory(personalSpace.db, faker as any);
60
+ yield* Effect.promise(() =>
61
+ factory([
62
+ { type: Organization.Organization, count: 10 },
63
+ { type: Person.Person, count: 50 },
64
+ ]),
65
+ );
66
+ }),
67
+ }),
68
+ ],
69
+ }),
70
+ ],
71
+ parameters: {
72
+ layout: 'fullscreen',
73
+ },
74
+ } satisfies Meta<typeof SearchArticle>;
75
+
76
+ export default meta;
77
+
78
+ type Story = StoryObj<typeof meta>;
79
+
80
+ export const Default: Story = {};
@@ -0,0 +1,63 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo, useState } from 'react';
6
+
7
+ import { Entity, Query } from '@dxos/echo';
8
+ import { Filter, type Space, useQuery } from '@dxos/react-client/echo';
9
+ import { Panel, Toolbar } from '@dxos/react-ui';
10
+ import { SearchList } from '@dxos/react-ui-search';
11
+ import { Text } from '@dxos/schema';
12
+ import { isTauri, getHostPlatform } from '@dxos/util';
13
+
14
+ import { SearchResultStack } from '#components';
15
+ import { useGlobalSearch, useGlobalSearchResults, useWebSearch } from '#hooks';
16
+
17
+ export type SearchArticleProps = {
18
+ space?: Space;
19
+ };
20
+
21
+ export const SearchArticle = ({ space }: SearchArticleProps) => {
22
+ // TODO(burdon): Option to query across spaces.
23
+ const [query, setQuery] = useState<string>();
24
+ // TODO(burdon): Re-enable full-text search when indexer is available in all environments.
25
+ const objects = useQuery(
26
+ space?.db,
27
+ query === undefined ? Query.select(Filter.nothing()) : Query.select(Filter.not(Filter.type(Text.Text))),
28
+ );
29
+
30
+ const { setMatch } = useGlobalSearch();
31
+ const results = useGlobalSearchResults(objects);
32
+ const { results: webResults } = useWebSearch({ query });
33
+ const allResults = useMemo(
34
+ () => [...results, ...webResults].filter(({ object }) => object && Entity.getLabel(object)),
35
+ [results, webResults],
36
+ );
37
+
38
+ const handleSearch = useCallback(
39
+ (text: string) => {
40
+ setQuery(text);
41
+ setMatch?.(text);
42
+ },
43
+ [setMatch],
44
+ );
45
+
46
+ const autoFocus = !isTauri() || getHostPlatform() !== 'ios';
47
+
48
+ // TODO(burdon): Move current up/down without losing focus.
49
+ return (
50
+ <SearchList.Root onSearch={handleSearch}>
51
+ <Panel.Root>
52
+ <Panel.Content asChild>
53
+ <SearchResultStack results={allResults} />
54
+ </Panel.Content>
55
+ <Panel.Statusbar asChild>
56
+ <Toolbar.Root>
57
+ <SearchList.Input placeholder='Search...' autoFocus={autoFocus} />
58
+ </Toolbar.Root>
59
+ </Panel.Statusbar>
60
+ </Panel.Root>
61
+ </SearchList.Root>
62
+ );
63
+ };
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { SearchArticle } from './SearchArticle';
6
+
7
+ export default SearchArticle;