@dxos/plugin-search 0.8.4-main.f5c0578 → 0.8.4-main.fcfe5033a5

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 (141) hide show
  1. package/README.md +0 -1
  2. package/dist/lib/browser/index.mjs +328 -82
  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 +2 -1
  6. package/dist/types/src/SearchPlugin.d.ts.map +1 -1
  7. package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
  8. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  9. package/dist/types/src/capabilities/index.d.ts +5 -3
  10. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  11. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  12. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  13. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  14. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  15. package/dist/types/src/components/SearchResultStack/SearchResultStack.d.ts +9 -0
  16. package/dist/types/src/components/SearchResultStack/SearchResultStack.d.ts.map +1 -0
  17. package/dist/types/src/components/SearchResultStack/index.d.ts +2 -0
  18. package/dist/types/src/components/SearchResultStack/index.d.ts.map +1 -0
  19. package/dist/types/src/components/index.d.ts +1 -3
  20. package/dist/types/src/components/index.d.ts.map +1 -1
  21. package/dist/types/src/constants.d.ts +2 -0
  22. package/dist/types/src/constants.d.ts.map +1 -0
  23. package/dist/types/src/containers/SearchArticle/SearchArticle.d.ts +7 -0
  24. package/dist/types/src/containers/SearchArticle/SearchArticle.d.ts.map +1 -0
  25. package/dist/types/src/containers/SearchArticle/SearchArticle.stories.d.ts +15 -0
  26. package/dist/types/src/containers/SearchArticle/SearchArticle.stories.d.ts.map +1 -0
  27. package/dist/types/src/containers/SearchArticle/index.d.ts +2 -0
  28. package/dist/types/src/containers/SearchArticle/index.d.ts.map +1 -0
  29. package/dist/types/src/containers/SearchDialog/SearchDialog.d.ts +8 -0
  30. package/dist/types/src/containers/SearchDialog/SearchDialog.d.ts.map +1 -0
  31. package/dist/types/src/containers/SearchDialog/SearchDialog.stories.d.ts +17 -0
  32. package/dist/types/src/containers/SearchDialog/SearchDialog.stories.d.ts.map +1 -0
  33. package/dist/types/src/containers/SearchDialog/index.d.ts +3 -0
  34. package/dist/types/src/containers/SearchDialog/index.d.ts.map +1 -0
  35. package/dist/types/src/containers/index.d.ts +5 -0
  36. package/dist/types/src/containers/index.d.ts.map +1 -0
  37. package/dist/types/src/hooks/index.d.ts +1 -0
  38. package/dist/types/src/hooks/index.d.ts.map +1 -1
  39. package/dist/types/src/hooks/sync.d.ts +4 -3
  40. package/dist/types/src/hooks/sync.d.ts.map +1 -1
  41. package/dist/types/src/hooks/useGlobalSearch.d.ts +8 -4
  42. package/dist/types/src/hooks/useGlobalSearch.d.ts.map +1 -1
  43. package/dist/types/src/hooks/useSearchResults.d.ts +3 -2
  44. package/dist/types/src/hooks/useSearchResults.d.ts.map +1 -1
  45. package/dist/types/src/hooks/useWebSearch.d.ts +7 -4
  46. package/dist/types/src/hooks/useWebSearch.d.ts.map +1 -1
  47. package/dist/types/src/meta.d.ts +3 -4
  48. package/dist/types/src/meta.d.ts.map +1 -1
  49. package/dist/types/src/operations/definitions.d.ts +3 -0
  50. package/dist/types/src/operations/definitions.d.ts.map +1 -0
  51. package/dist/types/src/operations/index.d.ts +4 -0
  52. package/dist/types/src/operations/index.d.ts.map +1 -0
  53. package/dist/types/src/operations/open-search.d.ts +5 -0
  54. package/dist/types/src/operations/open-search.d.ts.map +1 -0
  55. package/dist/types/src/search/exa.d.ts +4 -2
  56. package/dist/types/src/search/exa.d.ts.map +1 -1
  57. package/dist/types/src/translations.d.ts +15 -9
  58. package/dist/types/src/translations.d.ts.map +1 -1
  59. package/dist/types/src/types/index.d.ts +0 -1
  60. package/dist/types/src/types/index.d.ts.map +1 -1
  61. package/dist/types/src/types/search.d.ts +1 -20
  62. package/dist/types/src/types/search.d.ts.map +1 -1
  63. package/dist/types/tsconfig.tsbuildinfo +1 -1
  64. package/package.json +66 -47
  65. package/src/SearchPlugin.tsx +30 -47
  66. package/src/capabilities/app-graph-builder.ts +56 -69
  67. package/src/capabilities/index.ts +8 -4
  68. package/src/capabilities/operation-handler.ts +16 -0
  69. package/src/capabilities/react-surface.tsx +50 -47
  70. package/src/components/SearchResultStack/SearchResultStack.tsx +118 -0
  71. package/src/components/SearchResultStack/index.ts +5 -0
  72. package/src/components/index.ts +1 -3
  73. package/src/constants.ts +7 -0
  74. package/src/containers/SearchArticle/SearchArticle.stories.tsx +80 -0
  75. package/src/containers/SearchArticle/SearchArticle.tsx +63 -0
  76. package/src/containers/SearchArticle/index.ts +5 -0
  77. package/src/containers/SearchDialog/SearchDialog.stories.tsx +109 -0
  78. package/src/containers/SearchDialog/SearchDialog.tsx +96 -0
  79. package/src/containers/SearchDialog/index.ts +6 -0
  80. package/src/containers/index.ts +10 -0
  81. package/src/hooks/index.ts +2 -0
  82. package/src/hooks/sync.test.ts +9 -7
  83. package/src/hooks/sync.ts +28 -32
  84. package/src/hooks/useGlobalSearch.tsx +32 -13
  85. package/src/hooks/useSearchResults.ts +9 -6
  86. package/src/hooks/useWebSearch.ts +22 -11
  87. package/src/meta.ts +10 -7
  88. package/src/operations/definitions.ts +17 -0
  89. package/src/operations/index.ts +9 -0
  90. package/src/operations/open-search.ts +24 -0
  91. package/src/search/exa.test.ts +9 -11
  92. package/src/search/exa.ts +11 -8
  93. package/src/translations.ts +10 -9
  94. package/src/types/command-score.d.ts +16 -0
  95. package/src/types/index.ts +0 -1
  96. package/src/types/search.ts +1 -25
  97. package/dist/lib/browser/app-graph-builder-D2QQTIIR.mjs +0 -77
  98. package/dist/lib/browser/app-graph-builder-D2QQTIIR.mjs.map +0 -7
  99. package/dist/lib/browser/chunk-JVMYGOKS.mjs +0 -21
  100. package/dist/lib/browser/chunk-JVMYGOKS.mjs.map +0 -7
  101. package/dist/lib/browser/chunk-KNS62YL2.mjs +0 -20
  102. package/dist/lib/browser/chunk-KNS62YL2.mjs.map +0 -7
  103. package/dist/lib/browser/chunk-VKV5ZDB4.mjs +0 -190
  104. package/dist/lib/browser/chunk-VKV5ZDB4.mjs.map +0 -7
  105. package/dist/lib/browser/intent-resolver-NXFDPFHC.mjs +0 -22
  106. package/dist/lib/browser/intent-resolver-NXFDPFHC.mjs.map +0 -7
  107. package/dist/lib/browser/react-surface-B2XYD6JN.mjs +0 -468
  108. package/dist/lib/browser/react-surface-B2XYD6JN.mjs.map +0 -7
  109. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  110. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  111. package/dist/types/src/components/Search.stories.d.ts +0 -15
  112. package/dist/types/src/components/Search.stories.d.ts.map +0 -1
  113. package/dist/types/src/components/SearchDialog.d.ts +0 -7
  114. package/dist/types/src/components/SearchDialog.d.ts.map +0 -1
  115. package/dist/types/src/components/SearchMain.d.ts +0 -7
  116. package/dist/types/src/components/SearchMain.d.ts.map +0 -1
  117. package/dist/types/src/components/SearchResults/SearchResults.d.ts +0 -20
  118. package/dist/types/src/components/SearchResults/SearchResults.d.ts.map +0 -1
  119. package/dist/types/src/components/SearchResults/SearchResults.stories.d.ts +0 -12
  120. package/dist/types/src/components/SearchResults/SearchResults.stories.d.ts.map +0 -1
  121. package/dist/types/src/components/SearchResults/index.d.ts +0 -2
  122. package/dist/types/src/components/SearchResults/index.d.ts.map +0 -1
  123. package/dist/types/src/components/Searchbar/Searchbar.d.ts +0 -14
  124. package/dist/types/src/components/Searchbar/Searchbar.d.ts.map +0 -1
  125. package/dist/types/src/components/Searchbar/Searchbar.stories.d.ts +0 -11
  126. package/dist/types/src/components/Searchbar/Searchbar.stories.d.ts.map +0 -1
  127. package/dist/types/src/components/Searchbar/index.d.ts +0 -2
  128. package/dist/types/src/components/Searchbar/index.d.ts.map +0 -1
  129. package/dist/types/src/types/action.d.ts +0 -13
  130. package/dist/types/src/types/action.d.ts.map +0 -1
  131. package/src/capabilities/intent-resolver.ts +0 -18
  132. package/src/components/Search.stories.tsx +0 -67
  133. package/src/components/SearchDialog.tsx +0 -124
  134. package/src/components/SearchMain.tsx +0 -68
  135. package/src/components/SearchResults/SearchResults.stories.tsx +0 -58
  136. package/src/components/SearchResults/SearchResults.tsx +0 -86
  137. package/src/components/SearchResults/index.ts +0 -5
  138. package/src/components/Searchbar/Searchbar.stories.tsx +0 -28
  139. package/src/components/Searchbar/Searchbar.tsx +0 -67
  140. package/src/components/Searchbar/index.ts +0 -5
  141. package/src/types/action.tsx +0 -16
@@ -1 +0,0 @@
1
- {"version":3,"file":"SearchResults.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/SearchResults/SearchResults.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAQlD,OAAO,EAAE,aAAa,EAA2B,MAAM,iBAAiB,CAAC;AA0BzE,eAAO,MAAM,OAAO;;;;;CAKnB,CAAC;AAEF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,aAAa,CAQpC,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './SearchResults';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/SearchResults/index.ts"],"names":[],"mappings":"AAIA,cAAc,iBAAiB,CAAC"}
@@ -1,14 +0,0 @@
1
- import React from 'react';
2
- import { type TextInputProps } from '@dxos/react-ui';
3
- export type SearchbarProps = Pick<TextInputProps, 'variant' | 'placeholder'> & {
4
- classes?: {
5
- root?: string;
6
- input?: string;
7
- };
8
- value?: string;
9
- onChange?: (text?: string) => void;
10
- onSubmit?: (text?: string) => void;
11
- delay?: number;
12
- };
13
- export declare const Searchbar: ({ classes, variant, placeholder, value, onChange, onSubmit }: SearchbarProps) => React.JSX.Element;
14
- //# sourceMappingURL=Searchbar.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Searchbar.d.ts","sourceRoot":"","sources":["../../../../../src/components/Searchbar/Searchbar.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAE/E,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,aAAa,CAAC,GAAG;IAC7E,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,8DAA8D,cAAc,sBA+CrG,CAAC"}
@@ -1,11 +0,0 @@
1
- import '@dxos-theme';
2
- import { type Meta } from '@storybook/react-vite';
3
- import { type SearchbarProps } from './Searchbar';
4
- declare const meta: Meta<SearchbarProps>;
5
- export default meta;
6
- export declare const Default: {
7
- args: {
8
- placeholder: string;
9
- };
10
- };
11
- //# sourceMappingURL=Searchbar.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Searchbar.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Searchbar/Searchbar.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAIlD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,cAAc,CAO9B,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,eAAO,MAAM,OAAO;;;;CAInB,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './Searchbar';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Searchbar/index.ts"],"names":[],"mappings":"AAIA,cAAc,aAAa,CAAC"}
@@ -1,13 +0,0 @@
1
- import { Schema } from 'effect';
2
- export declare namespace SearchAction {
3
- const OpenSearch_base: Schema.TaggedClass<OpenSearch, "dxos.org/plugin/search/action/open-search", {
4
- readonly _tag: Schema.tag<"dxos.org/plugin/search/action/open-search">;
5
- } & {
6
- input: typeof Schema.Void;
7
- output: typeof Schema.Void;
8
- }>;
9
- export class OpenSearch extends OpenSearch_base {
10
- }
11
- export {};
12
- }
13
- //# sourceMappingURL=action.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../../../src/types/action.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhC,yBAAiB,YAAY,CAAC;;;;;;;IAG5B,MAAM,OAAO,UAAW,SAAQ,eAG9B;KAAG;;CACN"}
@@ -1,18 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Capabilities, LayoutAction, contributes, createIntent, createResolver } from '@dxos/app-framework';
6
-
7
- import { SearchAction } from '../types';
8
-
9
- export default () =>
10
- contributes(
11
- Capabilities.IntentResolver,
12
- createResolver({
13
- intent: SearchAction.OpenSearch,
14
- resolve: () => ({
15
- intents: [createIntent(LayoutAction.UpdateComplementary, { part: 'complementary', subject: 'search' })],
16
- }),
17
- }),
18
- );
@@ -1,67 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import '@dxos-theme';
6
-
7
- import { type Decorator, type Meta, type StoryFn } from '@storybook/react-vite';
8
- import React, { useState } from 'react';
9
-
10
- import { faker } from '@dxos/random';
11
- import { withLayout, withTheme } from '@dxos/storybook-utils';
12
-
13
- import { SearchContextProvider, useGlobalSearch, useGlobalSearchResults } from '../hooks';
14
-
15
- import { Searchbar, type SearchbarProps } from './Searchbar';
16
- import { SearchResults } from './SearchResults';
17
-
18
- faker.seed(1);
19
-
20
- type StoryProps = SearchbarProps & {
21
- objects?: any[];
22
- };
23
-
24
- const DefaultStory = ({ objects, ...props }: StoryProps) => {
25
- const [selected, setSelected] = useState<string>();
26
- const { setMatch } = useGlobalSearch();
27
- const filteredItems = useGlobalSearchResults(objects);
28
-
29
- return (
30
- <div className='flex grow justify-center overflow-hidden'>
31
- <div className='flex flex-col w-[300px] m-4 overflow-hidden'>
32
- <Searchbar variant='subdued' placeholder='Enter regular expression...' onChange={setMatch} {...props} />
33
- <SearchResults items={filteredItems} selected={selected} onSelect={setSelected} />
34
- </div>
35
- </div>
36
- );
37
- };
38
-
39
- const SearchContextDecorator = (): Decorator => {
40
- return (Story: StoryFn) => (
41
- <SearchContextProvider>
42
- <Story />
43
- </SearchContextProvider>
44
- );
45
- };
46
-
47
- export const Default = {
48
- args: {
49
- objects: Array.from({ length: 8 }).map(() => ({
50
- id: faker.string.uuid(),
51
- label: faker.lorem.sentence(4).replace(/\./g, ''),
52
- content: faker.lorem.sentences(3),
53
- })),
54
- },
55
- };
56
-
57
- const meta: Meta<typeof Searchbar> = {
58
- title: 'plugins/plugin-search/Search',
59
- component: Searchbar,
60
- render: DefaultStory,
61
- decorators: [withTheme, withLayout({ fullscreen: true }), SearchContextDecorator()],
62
- parameters: {
63
- layout: 'fullscreen',
64
- },
65
- };
66
-
67
- export default meta;
@@ -1,124 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { Option } from 'effect';
6
- import React, { forwardRef, useCallback, useState } from 'react';
7
-
8
- import { LayoutAction, createIntent, useAppGraph, useIntentDispatcher, useLayout } from '@dxos/app-framework';
9
- import { type Node } from '@dxos/plugin-graph';
10
- import { useClient } from '@dxos/react-client';
11
- import { Filter, fullyQualifiedId, useQuery } from '@dxos/react-client/echo';
12
- import { Button, Dialog, Icon, toLocalizedString, useTranslation } from '@dxos/react-ui';
13
- import { SearchList, type SearchListItemProps } from '@dxos/react-ui-searchlist';
14
- import { descriptionText, mx } from '@dxos/react-ui-theme';
15
-
16
- import { useSearchResults } from '../hooks';
17
- import { SEARCH_PLUGIN } from '../meta';
18
-
19
- export const SEARCH_DIALOG = `${SEARCH_PLUGIN}/SearchDialog`;
20
-
21
- type SearchListResultProps = {
22
- node: Node;
23
- } & Pick<SearchListItemProps, 'onSelect'>;
24
-
25
- const SearchListResult = forwardRef<HTMLDivElement, SearchListResultProps>(({ node, onSelect }, forwardedRef) => {
26
- const { t } = useTranslation(SEARCH_PLUGIN);
27
- const label = toLocalizedString(node?.properties.label ?? 'never', t);
28
- return (
29
- <SearchList.Item
30
- value={label}
31
- key={node!.id}
32
- classNames='flex gap-2 items-center pli-2'
33
- onSelect={() => onSelect?.(node!.id)}
34
- ref={forwardedRef}
35
- >
36
- <Icon size={5} icon={node?.properties.icon} />
37
- <span className='is-0 grow truncate'>{label}</span>
38
- </SearchList.Item>
39
- );
40
- });
41
-
42
- export type SearchDialogProps = {
43
- pivotId: string;
44
- };
45
-
46
- export const SearchDialog = ({ pivotId }: SearchDialogProps) => {
47
- const { t } = useTranslation(SEARCH_PLUGIN);
48
- const { graph } = useAppGraph();
49
- const layout = useLayout();
50
- const closed = (Array.isArray(layout.inactive) ? layout.inactive : [layout.inactive])
51
- .map((id) => graph?.getNode(id))
52
- .filter(Boolean);
53
- const [queryString, setQueryString] = useState('');
54
- const client = useClient();
55
- const dangerouslyLoadAllObjects = useQuery(client.spaces, Filter.everything());
56
- const [pending, results] = useSearchResults(queryString, dangerouslyLoadAllObjects);
57
- const resultObjects = Array.from(results.keys());
58
- const { dispatchPromise: dispatch } = useIntentDispatcher();
59
-
60
- const handleSelect = useCallback(
61
- async (nodeId: string) => {
62
- await dispatch(createIntent(LayoutAction.UpdateDialog, { part: 'dialog', options: { state: false } }));
63
-
64
- // If node is already present in the active parts, scroll to it and close the dialog.
65
- const index = layout.active.findIndex((id) => id === nodeId);
66
- if (index !== -1) {
67
- await dispatch(createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: nodeId }));
68
- } else {
69
- await dispatch(
70
- createIntent(LayoutAction.Open, {
71
- part: 'main',
72
- subject: [nodeId],
73
- options: {
74
- pivotId,
75
- positioning: 'end',
76
- },
77
- }),
78
- );
79
- }
80
- },
81
- [pivotId, dispatch, layout],
82
- );
83
-
84
- return (
85
- <Dialog.Content classNames={['md:max-is-[24rem] overflow-hidden mbs-12']}>
86
- <Dialog.Title>{t('search dialog title')}</Dialog.Title>
87
- <SearchList.Root label={t('search placeholder')} classNames='flex flex-col grow overflow-hidden my-2'>
88
- <SearchList.Input
89
- value={queryString}
90
- onValueChange={(nextValue) => {
91
- setQueryString(nextValue);
92
- }}
93
- placeholder={t('search placeholder')}
94
- classNames='px-1 my-2'
95
- />
96
- <SearchList.Content classNames='max-bs-[24rem] overflow-auto'>
97
- {queryString.length > 0 ? (
98
- resultObjects.length > 0 ? (
99
- resultObjects
100
- .map((object) => graph.getNode(fullyQualifiedId(object)))
101
- .filter(Option.isSome)
102
- .map((node) => <SearchListResult key={node.value.id} node={node.value} onSelect={handleSelect} />)
103
- ) : (
104
- <p className='pli-1'>{t(pending ? 'pending results message' : 'empty results message')}</p>
105
- )
106
- ) : (
107
- <>
108
- {closed.length > 0 && <h2 className={mx('mlb-1', descriptionText)}>{t('recently closed heading')}</h2>}
109
- {closed.filter(Option.isSome).map((node) => (
110
- <SearchListResult key={node.value.id} node={node.value} onSelect={handleSelect} />
111
- ))}
112
- </>
113
- )}
114
- </SearchList.Content>
115
- </SearchList.Root>
116
-
117
- <Dialog.Close asChild>
118
- <Button variant='primary' classNames='mbs-2'>
119
- {t('close label', { ns: 'os' })}
120
- </Button>
121
- </Dialog.Close>
122
- </Dialog.Content>
123
- );
124
- };
@@ -1,68 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import React, { type FC, useState } from 'react';
6
-
7
- import { log } from '@dxos/log';
8
- import { useClient } from '@dxos/react-client';
9
- import { Filter, type Space, useQuery } from '@dxos/react-client/echo';
10
- import { type ThemedClassName, useTranslation } from '@dxos/react-ui';
11
- import { activeSurface, mx } from '@dxos/react-ui-theme';
12
-
13
- import { useGlobalSearch, useGlobalSearchResults } from '../hooks';
14
- import { useWebSearch } from '../hooks/useWebSearch';
15
- import { SEARCH_PLUGIN } from '../meta';
16
-
17
- import { Searchbar } from './Searchbar';
18
- import { SearchResults } from './SearchResults';
19
-
20
- export const SearchMain: FC<ThemedClassName<{ space: Space }>> = ({ classNames, space }) => {
21
- const { t } = useTranslation(SEARCH_PLUGIN);
22
- const client = useClient();
23
- const { setMatch } = useGlobalSearch();
24
- const [query, setQuery] = useState<string>();
25
- // TODO(burdon): UX to select all spaces.
26
- const allSpaces = false;
27
-
28
- // TODO(burdon): Returns ALL objects (e.g., incl. Text objects that are fields of parent objects).
29
- const objects = useQuery(allSpaces ? client.spaces : space, Filter.everything());
30
- const results = useGlobalSearchResults(objects);
31
-
32
- const {
33
- runSearch,
34
- results: webResults,
35
- isLoading,
36
- } = useWebSearch({
37
- query,
38
- });
39
-
40
- const [selected, setSelected] = useState<string>();
41
-
42
- // TODO(burdon): Activate and/or filter current main (set context).
43
- const handleSelect = (id: string) => {
44
- setSelected((selected) => (selected === id ? undefined : id));
45
- };
46
-
47
- const allResults = [...results, ...webResults];
48
- log.info('results', { results, webResults });
49
-
50
- return (
51
- <div className={mx('flex flex-col grow h-full overflow-hidden', classNames)}>
52
- <Searchbar
53
- placeholder={t('search placeholder')}
54
- onChange={(text) => {
55
- setQuery(text);
56
- setMatch?.(text);
57
- }}
58
- onSubmit={runSearch}
59
- />
60
- {isLoading && <div className={mx('flex flex-col grow overflow-hidden', activeSurface)}>Loading...</div>}
61
- {allResults.length > 0 && (
62
- <div className={mx('flex flex-col grow overflow-hidden', activeSurface)}>
63
- <SearchResults items={allResults} selected={selected} onSelect={handleSelect} />
64
- </div>
65
- )}
66
- </div>
67
- );
68
- };
@@ -1,58 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import '@dxos-theme';
6
-
7
- import { type Meta } from '@storybook/react-vite';
8
- import React, { useState } from 'react';
9
-
10
- import { faker } from '@dxos/random';
11
- import { withLayout, withTheme } from '@dxos/storybook-utils';
12
-
13
- import { filterObjectsSync } from '../../hooks';
14
-
15
- import { SearchResults, type SearchResultsProps } from './SearchResults';
16
-
17
- faker.seed(1);
18
-
19
- const DefaultStory = (args: SearchResultsProps) => {
20
- const [selected, setSelected] = useState<string>();
21
-
22
- return (
23
- <div className='flex grow justify-center overflow-hidden'>
24
- <div className='flex w-[300px] m-4 overflow-hidden'>
25
- <SearchResults {...args} selected={selected} onSelect={setSelected} />
26
- </div>
27
- </div>
28
- );
29
- };
30
-
31
- const word = 'hello';
32
-
33
- const objects = Array.from({ length: 100 }).map((_, i) => ({
34
- id: faker.string.uuid(),
35
- name: faker.lorem.sentence(4),
36
- content: faker.lorem.sentence() + ` ${word} ` + faker.lorem.sentence(),
37
- }));
38
-
39
- const match = new RegExp(word, 'i');
40
-
41
- export const Default = {
42
- args: {
43
- items: filterObjectsSync(objects, match),
44
- match,
45
- },
46
- };
47
-
48
- const meta: Meta<typeof SearchResults> = {
49
- title: 'plugins/plugin-search/SearchResults',
50
- component: SearchResults,
51
- render: DefaultStory,
52
- decorators: [withTheme, withLayout({ fullscreen: true })],
53
- parameters: {
54
- layout: 'fullscreen',
55
- },
56
- };
57
-
58
- export default meta;
@@ -1,86 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import React, { type FC, forwardRef } from 'react';
6
-
7
- import { Card } from '@dxos/react-ui-stack';
8
- import { ghostHover } from '@dxos/react-ui-theme';
9
-
10
- import { SEARCH_RESULT } from '../../meta';
11
- import { type SearchResult } from '../../types';
12
-
13
- export const Snippet: FC<{ text: string; match?: RegExp }> = ({ text, match }) => {
14
- let content = <>{text}</>;
15
- if (match) {
16
- const result = text.match(match);
17
- if (result?.index !== undefined) {
18
- // Break near to match.
19
- const maxOffset = 16;
20
- let before = text.slice(0, result.index);
21
- if (before.length > maxOffset) {
22
- const idx = before.indexOf(' ', result.index - maxOffset);
23
- before = '… ' + before.slice(idx);
24
- }
25
-
26
- const after = text.slice(result.index + result[0].length);
27
- content = (
28
- <>
29
- {before}
30
- <span className='text-blue-500'>{result[0]}</span>
31
- {after}
32
- </>
33
- );
34
- }
35
- }
36
-
37
- return <span className='text-xs mb-1 line-clamp-3 text-neutral-300'>{content}</span>;
38
- };
39
-
40
- export type SearchItemProps = SearchResult & { selected: boolean } & Pick<SearchResultsProps, 'onSelect'>;
41
-
42
- export const SearchItem = forwardRef<HTMLDivElement, SearchItemProps>((item, forwardRef) => {
43
- const { id, objectType, label, snippet, match, selected, onSelect } = item;
44
-
45
- return (
46
- <Card.StaticRoot
47
- ref={forwardRef}
48
- classNames={['mx-2 mt-2 cursor-pointer', selected && '!bg-activeSurface', ghostHover]}
49
- onClick={() => onSelect?.(id)}
50
- >
51
- {objectType && (
52
- <>
53
- <div className='text-xs text-neutral-400 ml-4'>{objectType}</div>
54
- </>
55
- )}
56
- <Card.Heading>{label ?? 'Untitled'}</Card.Heading>
57
- {snippet && <Snippet text={snippet} match={match} />}
58
- </Card.StaticRoot>
59
- );
60
- });
61
-
62
- export type SearchResultsProps = {
63
- match?: RegExp;
64
- items: SearchResult[];
65
- selected?: string;
66
- onSelect?: (id: string) => void;
67
- };
68
-
69
- // TODO(burdon): Key cursor up/down.
70
- export const SearchResults = ({ items, selected, onSelect }: SearchResultsProps) => {
71
- return (
72
- <div className='flex flex-col grow overflow-y-auto'>
73
- <div className='flex flex-col'>
74
- {items.map((item) => (
75
- <SearchItem
76
- key={item.id}
77
- type={SEARCH_RESULT}
78
- {...item}
79
- onSelect={onSelect}
80
- selected={selected === item.id}
81
- />
82
- ))}
83
- </div>
84
- </div>
85
- );
86
- };
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- export * from './SearchResults';
@@ -1,28 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import '@dxos-theme';
6
-
7
- import { type Meta } from '@storybook/react-vite';
8
-
9
- import { withTheme } from '@dxos/storybook-utils';
10
-
11
- import { Searchbar, type SearchbarProps } from './Searchbar';
12
-
13
- const meta: Meta<SearchbarProps> = {
14
- title: 'plugins/plugin-search/Searchbar',
15
- component: Searchbar,
16
- decorators: [withTheme],
17
- parameters: {
18
- layout: 'centered',
19
- },
20
- };
21
-
22
- export default meta;
23
-
24
- export const Default = {
25
- args: {
26
- placeholder: 'Search...',
27
- },
28
- };
@@ -1,67 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import React, { type KeyboardEvent, useEffect, useRef, useState } from 'react';
6
-
7
- import { Icon, Input, type TextInputProps } from '@dxos/react-ui';
8
-
9
- export type SearchbarProps = Pick<TextInputProps, 'variant' | 'placeholder'> & {
10
- classes?: {
11
- root?: string;
12
- input?: string;
13
- };
14
- value?: string;
15
- onChange?: (text?: string) => void;
16
- onSubmit?: (text?: string) => void;
17
- delay?: number;
18
- };
19
-
20
- export const Searchbar = ({ classes, variant, placeholder, value, onChange, onSubmit }: SearchbarProps) => {
21
- const inputRef = useRef<HTMLInputElement>(null);
22
- const [text, setText] = useState(value);
23
- useEffect(() => {
24
- setText(value);
25
- }, [value]);
26
- const handleChange = (text?: string) => {
27
- setText(text);
28
- onChange?.(text);
29
- };
30
-
31
- const handleReset = () => {
32
- handleChange(undefined);
33
- inputRef.current?.focus();
34
- };
35
-
36
- const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
37
- switch (event.key) {
38
- case 'Enter':
39
- onSubmit?.(text);
40
- break;
41
- case 'Escape':
42
- handleReset();
43
- break;
44
- }
45
- };
46
-
47
- return (
48
- <div className='flex shrink-0w-full items-center pli-1 pbs-1'>
49
- <Input.Root>
50
- <Input.TextInput
51
- ref={inputRef}
52
- placeholder={placeholder}
53
- variant={variant}
54
- value={text ?? ''}
55
- classNames={['pl-3 pr-10', classes?.input]}
56
- onChange={({ target }) => handleChange(target.value)}
57
- onKeyDown={handleKeyDown}
58
- />
59
-
60
- {/* TODO(burdon): Margin should be density specific. */}
61
- <div role='button' className='-ml-7 p-0 cursor-pointer' onClick={handleReset}>
62
- <Icon icon='ph--magnifying-glass--regular' size={5} />
63
- </div>
64
- </Input.Root>
65
- </div>
66
- );
67
- };
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- export * from './Searchbar';
@@ -1,16 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import { Schema } from 'effect';
6
-
7
- import { SEARCH_PLUGIN } from '../meta';
8
-
9
- export namespace SearchAction {
10
- const SEARCH_ACTION = `${SEARCH_PLUGIN}/action`;
11
-
12
- export class OpenSearch extends Schema.TaggedClass<OpenSearch>()(`${SEARCH_ACTION}/open-search`, {
13
- input: Schema.Void,
14
- output: Schema.Void,
15
- }) {}
16
- }