@open-pioneer/search 0.1.0 → 0.3.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/CHANGELOG.md +63 -7
- package/Search.js +2 -1
- package/Search.js.map +1 -1
- package/api.d.ts +2 -26
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,72 @@
|
|
|
1
1
|
# @open-pioneer/search
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ee7c2d4: Update runtime version.
|
|
8
|
+
- 0456500: Add interface `BaseFeature` to Map API.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- 0883bbd: Add property `menuPosition` to React Select.
|
|
13
|
+
- Updated dependencies [ee7c2d4]
|
|
14
|
+
- Updated dependencies [a582e5e]
|
|
15
|
+
- Updated dependencies [0456500]
|
|
16
|
+
- Updated dependencies [762e7b9]
|
|
17
|
+
- @open-pioneer/map@0.3.0
|
|
18
|
+
- @open-pioneer/react-utils@0.2.1
|
|
19
|
+
|
|
20
|
+
## 0.2.0
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- 70349a8: Update to new core packages major versions
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [70349a8]
|
|
29
|
+
- @open-pioneer/map@0.2.0
|
|
30
|
+
- @open-pioneer/react-utils@0.2.0
|
|
31
|
+
|
|
32
|
+
## 0.1.0
|
|
33
|
+
|
|
34
|
+
### Minor Changes
|
|
35
|
+
|
|
36
|
+
- 6209d6c: Initial release
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- 565bd8b: Fix usage via touch (NOTE: currently requires a patch to react-select; see repository's `package.json` file).
|
|
41
|
+
- Updated dependencies [08bffbc]
|
|
42
|
+
- Updated dependencies [a58546b]
|
|
43
|
+
- Updated dependencies [a58546b]
|
|
44
|
+
- Updated dependencies [0c4ce04]
|
|
45
|
+
- @open-pioneer/map@0.1.1
|
|
46
|
+
|
|
47
|
+
## 0.2.0
|
|
48
|
+
|
|
49
|
+
### Minor Changes
|
|
50
|
+
|
|
51
|
+
- 70349a8: Update to new core packages major versions
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- Updated dependencies [70349a8]
|
|
56
|
+
- @open-pioneer/map@0.2.0
|
|
57
|
+
- @open-pioneer/react-utils@0.2.0
|
|
58
|
+
|
|
3
59
|
## 0.1.0
|
|
4
60
|
|
|
5
61
|
### Minor Changes
|
|
6
62
|
|
|
7
|
-
-
|
|
63
|
+
- 6209d6c: Initial release
|
|
8
64
|
|
|
9
65
|
### Patch Changes
|
|
10
66
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
67
|
+
- 565bd8b: Fix usage via touch (NOTE: currently requires a patch to react-select; see repository's `package.json` file).
|
|
68
|
+
- Updated dependencies [08bffbc]
|
|
69
|
+
- Updated dependencies [a58546b]
|
|
70
|
+
- Updated dependencies [a58546b]
|
|
71
|
+
- Updated dependencies [0c4ce04]
|
|
72
|
+
- @open-pioneer/map@0.1.1
|
package/Search.js
CHANGED
package/Search.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Search.js","sources":["Search.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box, useToken } from \"@open-pioneer/chakra-integration\";\nimport { createLogger, isAbortError } from \"@open-pioneer/core\";\nimport { MapModel, useMapModel } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps, useEvent } from \"@open-pioneer/react-utils\";\nimport {\n ActionMeta,\n AriaLiveMessages,\n AriaOnChange,\n AriaOnFocus,\n ChakraStylesConfig,\n InputActionMeta,\n Select,\n SelectInstance,\n SingleValue,\n Props as SelectProps\n} from \"chakra-react-select\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, useCallback, useEffect, useMemo, useReducer, useRef, useState } from \"react\";\nimport {\n ClearIndicator,\n HighlightOption,\n IndicatorsContainer,\n Input,\n LoadingMessage,\n MenuComp,\n NoOptionsMessage,\n SingleValue as SingleValueComp,\n ValueContainer\n} from \"./CustomComponents\";\nimport { SearchController, SuggestionGroup } from \"./SearchController\";\nimport { SearchSource, SearchResult } from \"./api\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\n\nconst LOG = createLogger(\"search:Search\");\n\nexport interface SearchOption {\n /** Unique value for this option. */\n value: string;\n\n /** Display text shown in menu. */\n label: string;\n\n /** Search source that returned the suggestion. */\n source: SearchSource;\n\n /** The raw result from the search source. */\n result: SearchResult;\n}\n\nexport interface SearchGroupOption {\n /** Display text shown in menu. */\n label: string;\n\n /** Set of options that belong to this group. */\n options: SearchOption[];\n}\n\n/**\n * Event type emitted when the user selects an item.\n */\nexport interface SearchSelectEvent {\n /** The source that returned the {@link result}. */\n source: SearchSource;\n\n /** The search result selected by the user. */\n result: SearchResult;\n}\n\n/**\n * Properties supported by the {@link Search} component.\n */\nexport interface SearchProps extends CommonComponentProps {\n /**\n * The id of the map.\n */\n mapId: string;\n\n /**\n * Data sources to be searched on.\n */\n sources: SearchSource[];\n\n /**\n * Typing delay (in milliseconds) before the async search query starts after the user types in the search term.\n * Defaults to `200`.\n */\n searchTypingDelay?: number;\n\n /**\n * The maximum number of results shown per group.\n * Defaults to `5`.\n */\n maxResultsPerGroup?: number;\n\n /**\n * This event handler will be called when the user selects a search result.\n */\n onSelect?: (event: SearchSelectEvent) => void;\n\n /**\n * This event handler will be called when the user clears the search input.\n */\n onClear?: () => void;\n}\n\n/**\n * A component that allows the user to search a given set of {@link SearchSource | SearchSources}.\n */\nexport const Search: FC<SearchProps> = (props) => {\n const { mapId, sources, searchTypingDelay, maxResultsPerGroup, onSelect, onClear } = props;\n const { containerProps } = useCommonComponentProps(\"search\", props);\n const { map } = useMapModel(mapId);\n const intl = useIntl();\n const controller = useController(sources, searchTypingDelay, maxResultsPerGroup, map);\n const { input, search, selectedOption, onInputChanged, onResultConfirmed } =\n useSearchState(controller);\n\n const chakraStyles = useChakraStyles();\n const ariaMessages = useAriaMessages(intl);\n const components = useCustomComponents();\n\n const handleInputChange = useEvent((newValue: string, actionMeta: InputActionMeta) => {\n // Only update the input if the user actually typed something.\n // This keeps the input content if the user focuses another element or if the menu is closed.\n if (actionMeta.action === \"input-change\") {\n onInputChanged(newValue);\n }\n });\n\n const handleSelectChange = useEvent(\n (value: SingleValue<SearchOption>, actionMeta: ActionMeta<SearchOption>) => {\n switch (actionMeta.action) {\n case \"select-option\":\n if (value) {\n // Updates the input field with the option label\n onResultConfirmed(value);\n onSelect?.({\n source: value.source,\n result: value.result\n });\n }\n break;\n case \"clear\":\n // Updates the input field\n onInputChanged(\"\");\n\n // the next two lines are a workaround for the open bug in react-select regarding the\n // cursor not being shown after clearing, although the component is focussed:\n // https://github.com/JedWatson/react-select/issues/3871\n selectRef.current?.blur();\n selectRef.current?.focus();\n onClear?.();\n break;\n default:\n LOG.debug(`Unhandled action type '${actionMeta.action}'.`);\n break;\n }\n }\n );\n\n const selectRef = useRef<SelectInstance<SearchOption, false, SearchGroupOption>>(null);\n return (\n <Box {...containerProps}>\n <Select<SearchOption, false, SearchGroupOption>\n className=\"search-component\"\n classNamePrefix=\"react-select\"\n ref={selectRef}\n inputValue={input}\n onInputChange={handleInputChange}\n aria-label={intl.formatMessage({ id: \"ariaLabel.search\" })}\n ariaLiveMessages={ariaMessages}\n colorScheme=\"trails\"\n selectedOptionStyle=\"color\"\n selectedOptionColorScheme=\"trails\"\n chakraStyles={chakraStyles}\n isClearable={true}\n placeholder={intl.formatMessage({ id: \"searchPlaceholder\" })}\n closeMenuOnSelect={true}\n isLoading={search.kind === \"loading\"}\n options={search.kind === \"ready\" ? search.results : undefined}\n filterOption={() => true} // always show all options (don't filter based on input text)\n tabSelectsValue={false}\n components={components}\n onChange={handleSelectChange}\n value={selectedOption}\n />\n </Box>\n );\n};\n\n/**\n * Provides custom aria messages for the select component.\n */\nfunction useAriaMessages(\n intl: PackageIntl\n): AriaLiveMessages<SearchOption, false, SearchGroupOption> {\n return useMemo(() => {\n /**\n * Method to create Aria-String for focus-Event\n */\n const onFocus: AriaOnFocus<SearchOption> = ({ focused }) => {\n return `${focused.label} ${intl.formatMessage({ id: \"ariaLabel.searchFocus\" })}.`;\n };\n\n /**\n * Method to create Aria-String for value-change-Event\n */\n const onChange: AriaOnChange<SearchOption, boolean> = ({ action, label }) => {\n let message = \"\";\n switch (action) {\n case \"select-option\":\n message = `${label} ${intl.formatMessage({ id: \"ariaLabel.searchSelect\" })}.`;\n break;\n case \"clear\":\n message = `${label} ${intl.formatMessage({ id: \"ariaLabel.searchClear\" })}.`;\n break;\n default:\n break;\n }\n return message;\n };\n\n /**\n * Method to create Aria-String for instruction\n */\n const guidance = () => {\n return `${intl.formatMessage({ id: \"ariaLabel.instructions\" })}`;\n };\n\n /**\n * Method to create Aria-String for result length\n */\n const onFilter = () => {\n return \"\";\n };\n\n return {\n onFocus,\n onChange,\n guidance,\n onFilter\n };\n }, [intl]);\n}\n\n/**\n * Customizes the inner components used by the select component.\n */\nfunction useCustomComponents(): SelectProps<SearchOption, false, SearchGroupOption>[\"components\"] {\n return useMemo(() => {\n return {\n Menu: MenuComp,\n Input: Input,\n SingleValue: SingleValueComp,\n Option: HighlightOption,\n NoOptionsMessage: NoOptionsMessage,\n LoadingMessage: LoadingMessage,\n ValueContainer: ValueContainer,\n IndicatorsContainer: IndicatorsContainer,\n ClearIndicator: ClearIndicator\n };\n }, []);\n}\n\n/**\n * Customizes components styles within the select component.\n */\nfunction useChakraStyles() {\n const [groupHeadingBg, focussedItemBg] = useToken(\n \"colors\",\n [\"trails.100\", \"trails.50\"],\n [\"#d5e5ec\", \"#eaf2f5\"]\n );\n return useMemo(() => {\n const chakraStyles: ChakraStylesConfig<SearchOption, false, SearchGroupOption> = {\n groupHeading: (provided) => ({\n ...provided,\n backgroundColor: groupHeadingBg,\n padding: \"8px 12px\",\n // make Header look like normal options:\n fontSize: \"inherit\",\n fontWeight: \"inherit\"\n }),\n option: (provided) => ({\n ...provided,\n backgroundColor: \"inherit\",\n _focus: {\n backgroundColor: focussedItemBg\n }\n }),\n dropdownIndicator: (provided) => ({\n ...provided,\n display: \"none\" // always hide\n })\n };\n return chakraStyles;\n }, [groupHeadingBg, focussedItemBg]);\n}\n\n/**\n * Creates a controller to search on the given sources.\n */\nfunction useController(\n sources: SearchSource[],\n searchTypingDelay: number | undefined,\n maxResultsPerGroup: number | undefined,\n map: MapModel | undefined\n) {\n const [controller, setController] = useState<SearchController | undefined>(undefined);\n useEffect(() => {\n if (!map) {\n return;\n }\n const controller = new SearchController(map, sources);\n setController(controller);\n return () => {\n controller.destroy();\n setController(undefined);\n };\n }, [map, sources]);\n\n useEffect(() => {\n controller && (controller.searchTypingDelay = searchTypingDelay);\n }, [controller, searchTypingDelay]);\n useEffect(() => {\n controller && (controller.maxResultsPerSource = maxResultsPerGroup);\n }, [controller, maxResultsPerGroup]);\n return controller;\n}\n\ntype SearchResultsReady = {\n kind: \"ready\";\n results: SearchGroupOption[];\n};\n\ntype SearchResultsLoading = {\n kind: \"loading\";\n};\n\ntype SearchResultsState = SearchResultsReady | SearchResultsLoading;\n\n/**\n * Keeps track of the current input text, active searches and their results.\n *\n * NOTE: it would be great to merge this state handling with the search controller\n * in a future revision.\n */\nfunction useSearchState(controller: SearchController | undefined) {\n interface FullSearchState {\n query: string;\n selectedOption: SearchOption | null;\n search: SearchResultsState;\n }\n\n type Action =\n | { kind: \"input\"; query: string }\n | { kind: \"select-option\"; option: SearchOption }\n | { kind: \"load-results\" }\n | { kind: \"accept-results\"; results: SearchGroupOption[] };\n\n const [state, dispatch] = useReducer(\n (current: FullSearchState, action: Action): FullSearchState => {\n switch (action.kind) {\n case \"input\":\n return {\n ...current,\n query: action.query,\n selectedOption: null\n };\n case \"select-option\":\n return {\n ...current,\n selectedOption: action.option,\n query: action.option.label\n };\n case \"load-results\":\n return {\n ...current,\n search: {\n kind: \"loading\"\n }\n };\n case \"accept-results\":\n return {\n ...current,\n search: {\n kind: \"ready\",\n results: action.results\n }\n };\n }\n },\n undefined,\n (): FullSearchState => ({\n query: \"\",\n selectedOption: null,\n search: {\n kind: \"ready\",\n results: []\n }\n })\n );\n\n // Stores the promise for the current search.\n // Any results from outdated searches are ignored.\n const currentSearch = useRef<Promise<unknown>>();\n const startSearch = useEvent((query: string) => {\n if (!controller) {\n currentSearch.current = undefined;\n dispatch({ kind: \"accept-results\", results: [] });\n return;\n }\n\n LOG.isDebug() && LOG.debug(`Starting new search for query ${JSON.stringify(query)}.`);\n dispatch({ kind: \"load-results\" });\n const promise = (currentSearch.current = search(controller, query).then((results) => {\n // Check if this job is still current\n if (currentSearch.current === promise) {\n dispatch({ kind: \"accept-results\", results });\n }\n }));\n });\n\n // Called when the user confirms a search result\n const onResultConfirmed = useCallback((option: SearchOption) => {\n // Do not start a new search when the user confirms a result\n dispatch({ kind: \"select-option\", option });\n }, []);\n\n // Called when a user types into the input field\n const onInputChanged = useCallback(\n (newValue: string) => {\n // Trigger a new search if the user changes the query by typing\n dispatch({ kind: \"input\", query: newValue });\n startSearch(newValue);\n },\n [startSearch]\n );\n\n return {\n input: state.query,\n search: state.search,\n selectedOption: state.selectedOption,\n onResultConfirmed,\n onInputChanged\n };\n}\n\nasync function search(controller: SearchController, query: string): Promise<SearchGroupOption[]> {\n let suggestions: SuggestionGroup[];\n try {\n suggestions = await controller.search(query);\n } catch (error) {\n if (!isAbortError(error)) {\n LOG.error(`Search failed`, error);\n }\n suggestions = [];\n }\n return mapSuggestions(suggestions);\n}\n\nfunction mapSuggestions(suggestions: SuggestionGroup[]): SearchGroupOption[] {\n const options = suggestions.map(\n (group, groupIndex): SearchGroupOption => ({\n label: group.label,\n options: group.results.map((suggestion): SearchOption => {\n return {\n value: `${groupIndex}-${suggestion.id}`,\n label: suggestion.label,\n source: group.source,\n result: suggestion\n };\n })\n })\n );\n return options;\n}\n"],"names":["search","SingleValueComp","controller"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Search.js","sources":["Search.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Box, useToken } from \"@open-pioneer/chakra-integration\";\nimport { createLogger, isAbortError } from \"@open-pioneer/core\";\nimport { MapModel, useMapModel } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps, useEvent } from \"@open-pioneer/react-utils\";\nimport {\n ActionMeta,\n AriaLiveMessages,\n AriaOnChange,\n AriaOnFocus,\n ChakraStylesConfig,\n InputActionMeta,\n Select,\n SelectInstance,\n SingleValue,\n Props as SelectProps\n} from \"chakra-react-select\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, useCallback, useEffect, useMemo, useReducer, useRef, useState } from \"react\";\nimport {\n ClearIndicator,\n HighlightOption,\n IndicatorsContainer,\n Input,\n LoadingMessage,\n MenuComp,\n NoOptionsMessage,\n SingleValue as SingleValueComp,\n ValueContainer\n} from \"./CustomComponents\";\nimport { SearchController, SuggestionGroup } from \"./SearchController\";\nimport { SearchSource, SearchResult } from \"./api\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\n\nconst LOG = createLogger(\"search:Search\");\n\nexport interface SearchOption {\n /** Unique value for this option. */\n value: string;\n\n /** Display text shown in menu. */\n label: string;\n\n /** Search source that returned the suggestion. */\n source: SearchSource;\n\n /** The raw result from the search source. */\n result: SearchResult;\n}\n\nexport interface SearchGroupOption {\n /** Display text shown in menu. */\n label: string;\n\n /** Set of options that belong to this group. */\n options: SearchOption[];\n}\n\n/**\n * Event type emitted when the user selects an item.\n */\nexport interface SearchSelectEvent {\n /** The source that returned the {@link result}. */\n source: SearchSource;\n\n /** The search result selected by the user. */\n result: SearchResult;\n}\n\n/**\n * Properties supported by the {@link Search} component.\n */\nexport interface SearchProps extends CommonComponentProps {\n /**\n * The id of the map.\n */\n mapId: string;\n\n /**\n * Data sources to be searched on.\n */\n sources: SearchSource[];\n\n /**\n * Typing delay (in milliseconds) before the async search query starts after the user types in the search term.\n * Defaults to `200`.\n */\n searchTypingDelay?: number;\n\n /**\n * The maximum number of results shown per group.\n * Defaults to `5`.\n */\n maxResultsPerGroup?: number;\n\n /**\n * This event handler will be called when the user selects a search result.\n */\n onSelect?: (event: SearchSelectEvent) => void;\n\n /**\n * This event handler will be called when the user clears the search input.\n */\n onClear?: () => void;\n}\n\n/**\n * A component that allows the user to search a given set of {@link SearchSource | SearchSources}.\n */\nexport const Search: FC<SearchProps> = (props) => {\n const { mapId, sources, searchTypingDelay, maxResultsPerGroup, onSelect, onClear } = props;\n const { containerProps } = useCommonComponentProps(\"search\", props);\n const { map } = useMapModel(mapId);\n const intl = useIntl();\n const controller = useController(sources, searchTypingDelay, maxResultsPerGroup, map);\n const { input, search, selectedOption, onInputChanged, onResultConfirmed } =\n useSearchState(controller);\n\n const chakraStyles = useChakraStyles();\n const ariaMessages = useAriaMessages(intl);\n const components = useCustomComponents();\n\n const handleInputChange = useEvent((newValue: string, actionMeta: InputActionMeta) => {\n // Only update the input if the user actually typed something.\n // This keeps the input content if the user focuses another element or if the menu is closed.\n if (actionMeta.action === \"input-change\") {\n onInputChanged(newValue);\n }\n });\n\n const handleSelectChange = useEvent(\n (value: SingleValue<SearchOption>, actionMeta: ActionMeta<SearchOption>) => {\n switch (actionMeta.action) {\n case \"select-option\":\n if (value) {\n // Updates the input field with the option label\n onResultConfirmed(value);\n onSelect?.({\n source: value.source,\n result: value.result\n });\n }\n break;\n case \"clear\":\n // Updates the input field\n onInputChanged(\"\");\n\n // the next two lines are a workaround for the open bug in react-select regarding the\n // cursor not being shown after clearing, although the component is focussed:\n // https://github.com/JedWatson/react-select/issues/3871\n selectRef.current?.blur();\n selectRef.current?.focus();\n onClear?.();\n break;\n default:\n LOG.debug(`Unhandled action type '${actionMeta.action}'.`);\n break;\n }\n }\n );\n\n const selectRef = useRef<SelectInstance<SearchOption, false, SearchGroupOption>>(null);\n return (\n <Box {...containerProps}>\n <Select<SearchOption, false, SearchGroupOption>\n className=\"search-component\"\n classNamePrefix=\"react-select\"\n ref={selectRef}\n inputValue={input}\n onInputChange={handleInputChange}\n aria-label={intl.formatMessage({ id: \"ariaLabel.search\" })}\n ariaLiveMessages={ariaMessages}\n colorScheme=\"trails\"\n selectedOptionStyle=\"color\"\n selectedOptionColorScheme=\"trails\"\n chakraStyles={chakraStyles}\n isClearable={true}\n placeholder={intl.formatMessage({ id: \"searchPlaceholder\" })}\n closeMenuOnSelect={true}\n isLoading={search.kind === \"loading\"}\n options={search.kind === \"ready\" ? search.results : undefined}\n filterOption={() => true} // always show all options (don't filter based on input text)\n tabSelectsValue={false}\n components={components}\n onChange={handleSelectChange}\n value={selectedOption}\n menuPosition=\"fixed\"\n />\n </Box>\n );\n};\n\n/**\n * Provides custom aria messages for the select component.\n */\nfunction useAriaMessages(\n intl: PackageIntl\n): AriaLiveMessages<SearchOption, false, SearchGroupOption> {\n return useMemo(() => {\n /**\n * Method to create Aria-String for focus-Event\n */\n const onFocus: AriaOnFocus<SearchOption> = ({ focused }) => {\n return `${focused.label} ${intl.formatMessage({ id: \"ariaLabel.searchFocus\" })}.`;\n };\n\n /**\n * Method to create Aria-String for value-change-Event\n */\n const onChange: AriaOnChange<SearchOption, boolean> = ({ action, label }) => {\n let message = \"\";\n switch (action) {\n case \"select-option\":\n message = `${label} ${intl.formatMessage({ id: \"ariaLabel.searchSelect\" })}.`;\n break;\n case \"clear\":\n message = `${label} ${intl.formatMessage({ id: \"ariaLabel.searchClear\" })}.`;\n break;\n default:\n break;\n }\n return message;\n };\n\n /**\n * Method to create Aria-String for instruction\n */\n const guidance = () => {\n return `${intl.formatMessage({ id: \"ariaLabel.instructions\" })}`;\n };\n\n /**\n * Method to create Aria-String for result length\n */\n const onFilter = () => {\n return \"\";\n };\n\n return {\n onFocus,\n onChange,\n guidance,\n onFilter\n };\n }, [intl]);\n}\n\n/**\n * Customizes the inner components used by the select component.\n */\nfunction useCustomComponents(): SelectProps<SearchOption, false, SearchGroupOption>[\"components\"] {\n return useMemo(() => {\n return {\n Menu: MenuComp,\n Input: Input,\n SingleValue: SingleValueComp,\n Option: HighlightOption,\n NoOptionsMessage: NoOptionsMessage,\n LoadingMessage: LoadingMessage,\n ValueContainer: ValueContainer,\n IndicatorsContainer: IndicatorsContainer,\n ClearIndicator: ClearIndicator\n };\n }, []);\n}\n\n/**\n * Customizes components styles within the select component.\n */\nfunction useChakraStyles() {\n const [groupHeadingBg, focussedItemBg] = useToken(\n \"colors\",\n [\"trails.100\", \"trails.50\"],\n [\"#d5e5ec\", \"#eaf2f5\"]\n );\n return useMemo(() => {\n const chakraStyles: ChakraStylesConfig<SearchOption, false, SearchGroupOption> = {\n groupHeading: (provided) => ({\n ...provided,\n backgroundColor: groupHeadingBg,\n padding: \"8px 12px\",\n // make Header look like normal options:\n fontSize: \"inherit\",\n fontWeight: \"inherit\"\n }),\n option: (provided) => ({\n ...provided,\n backgroundColor: \"inherit\",\n _focus: {\n backgroundColor: focussedItemBg\n }\n }),\n dropdownIndicator: (provided) => ({\n ...provided,\n display: \"none\" // always hide\n })\n };\n return chakraStyles;\n }, [groupHeadingBg, focussedItemBg]);\n}\n\n/**\n * Creates a controller to search on the given sources.\n */\nfunction useController(\n sources: SearchSource[],\n searchTypingDelay: number | undefined,\n maxResultsPerGroup: number | undefined,\n map: MapModel | undefined\n) {\n const [controller, setController] = useState<SearchController | undefined>(undefined);\n useEffect(() => {\n if (!map) {\n return;\n }\n const controller = new SearchController(map, sources);\n setController(controller);\n return () => {\n controller.destroy();\n setController(undefined);\n };\n }, [map, sources]);\n\n useEffect(() => {\n controller && (controller.searchTypingDelay = searchTypingDelay);\n }, [controller, searchTypingDelay]);\n useEffect(() => {\n controller && (controller.maxResultsPerSource = maxResultsPerGroup);\n }, [controller, maxResultsPerGroup]);\n return controller;\n}\n\ntype SearchResultsReady = {\n kind: \"ready\";\n results: SearchGroupOption[];\n};\n\ntype SearchResultsLoading = {\n kind: \"loading\";\n};\n\ntype SearchResultsState = SearchResultsReady | SearchResultsLoading;\n\n/**\n * Keeps track of the current input text, active searches and their results.\n *\n * NOTE: it would be great to merge this state handling with the search controller\n * in a future revision.\n */\nfunction useSearchState(controller: SearchController | undefined) {\n interface FullSearchState {\n query: string;\n selectedOption: SearchOption | null;\n search: SearchResultsState;\n }\n\n type Action =\n | { kind: \"input\"; query: string }\n | { kind: \"select-option\"; option: SearchOption }\n | { kind: \"load-results\" }\n | { kind: \"accept-results\"; results: SearchGroupOption[] };\n\n const [state, dispatch] = useReducer(\n (current: FullSearchState, action: Action): FullSearchState => {\n switch (action.kind) {\n case \"input\":\n return {\n ...current,\n query: action.query,\n selectedOption: null\n };\n case \"select-option\":\n return {\n ...current,\n selectedOption: action.option,\n query: action.option.label\n };\n case \"load-results\":\n return {\n ...current,\n search: {\n kind: \"loading\"\n }\n };\n case \"accept-results\":\n return {\n ...current,\n search: {\n kind: \"ready\",\n results: action.results\n }\n };\n }\n },\n undefined,\n (): FullSearchState => ({\n query: \"\",\n selectedOption: null,\n search: {\n kind: \"ready\",\n results: []\n }\n })\n );\n\n // Stores the promise for the current search.\n // Any results from outdated searches are ignored.\n const currentSearch = useRef<Promise<unknown>>();\n const startSearch = useEvent((query: string) => {\n if (!controller) {\n currentSearch.current = undefined;\n dispatch({ kind: \"accept-results\", results: [] });\n return;\n }\n\n LOG.isDebug() && LOG.debug(`Starting new search for query ${JSON.stringify(query)}.`);\n dispatch({ kind: \"load-results\" });\n const promise = (currentSearch.current = search(controller, query).then((results) => {\n // Check if this job is still current\n if (currentSearch.current === promise) {\n dispatch({ kind: \"accept-results\", results });\n }\n }));\n });\n\n // Called when the user confirms a search result\n const onResultConfirmed = useCallback((option: SearchOption) => {\n // Do not start a new search when the user confirms a result\n dispatch({ kind: \"select-option\", option });\n }, []);\n\n // Called when a user types into the input field\n const onInputChanged = useCallback(\n (newValue: string) => {\n // Trigger a new search if the user changes the query by typing\n dispatch({ kind: \"input\", query: newValue });\n startSearch(newValue);\n },\n [startSearch]\n );\n\n return {\n input: state.query,\n search: state.search,\n selectedOption: state.selectedOption,\n onResultConfirmed,\n onInputChanged\n };\n}\n\nasync function search(controller: SearchController, query: string): Promise<SearchGroupOption[]> {\n let suggestions: SuggestionGroup[];\n try {\n suggestions = await controller.search(query);\n } catch (error) {\n if (!isAbortError(error)) {\n LOG.error(`Search failed`, error);\n }\n suggestions = [];\n }\n return mapSuggestions(suggestions);\n}\n\nfunction mapSuggestions(suggestions: SuggestionGroup[]): SearchGroupOption[] {\n const options = suggestions.map(\n (group, groupIndex): SearchGroupOption => ({\n label: group.label,\n options: group.results.map((suggestion): SearchOption => {\n return {\n value: `${groupIndex}-${suggestion.id}`,\n label: suggestion.label,\n source: group.source,\n result: suggestion\n };\n })\n })\n );\n return options;\n}\n"],"names":["search","SingleValueComp","controller"],"mappings":"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"}
|
package/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseFeature } from "@open-pioneer/map/api/BaseFeature";
|
|
2
2
|
import { Projection } from "ol/proj";
|
|
3
3
|
/**
|
|
4
4
|
* An object that allows searching some set of data.
|
|
@@ -76,34 +76,10 @@ export interface SearchOptions {
|
|
|
76
76
|
/**
|
|
77
77
|
* Represent the result of a search.
|
|
78
78
|
*/
|
|
79
|
-
export interface SearchResult {
|
|
80
|
-
/**
|
|
81
|
-
* Identifier for the result object.
|
|
82
|
-
* Values used here should be unique within the context of the search source that returns them.
|
|
83
|
-
*
|
|
84
|
-
* If your source cannot provide a useful id on its own, another strategy to generate unique ids is to
|
|
85
|
-
* generate a [UUID](https://www.npmjs.com/package/uuid#uuidv4options-buffer-offset) instead.
|
|
86
|
-
*/
|
|
87
|
-
id: number | string;
|
|
79
|
+
export interface SearchResult extends BaseFeature {
|
|
88
80
|
/**
|
|
89
81
|
* Display text representing this result.
|
|
90
82
|
* Will be shown in the search widget's suggestion list.
|
|
91
83
|
*/
|
|
92
84
|
label: string;
|
|
93
|
-
/**
|
|
94
|
-
* Optional geometry.
|
|
95
|
-
*
|
|
96
|
-
* If a geometry is provided, one should also specify the {@link projection}.
|
|
97
|
-
*
|
|
98
|
-
* If no projection has been specified, calling code should assume the map's projection.
|
|
99
|
-
*/
|
|
100
|
-
geometry?: Geometry;
|
|
101
|
-
/**
|
|
102
|
-
* The projection of the {@link geometry}.
|
|
103
|
-
*/
|
|
104
|
-
projection?: string;
|
|
105
|
-
/**
|
|
106
|
-
* Arbitrary additional properties.
|
|
107
|
-
*/
|
|
108
|
-
properties?: Readonly<Record<string, unknown>>;
|
|
109
85
|
}
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@open-pioneer/search",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"peerDependencies": {
|
|
7
7
|
"@open-pioneer/chakra-integration": "^1.1.1",
|
|
8
|
-
"@open-pioneer/runtime": "^2.0
|
|
8
|
+
"@open-pioneer/runtime": "^2.1.0",
|
|
9
9
|
"@open-pioneer/core": "^1.2.1",
|
|
10
10
|
"ol": "^8.2.0",
|
|
11
11
|
"react": "^18.2.0",
|
|
12
12
|
"classnames": "^2.3.2",
|
|
13
13
|
"chakra-react-select": "^4.7.6",
|
|
14
14
|
"@chakra-ui/icons": "^2.1.1",
|
|
15
|
-
"@open-pioneer/map": "^0.
|
|
16
|
-
"@open-pioneer/react-utils": "^0.1
|
|
15
|
+
"@open-pioneer/map": "^0.3.0",
|
|
16
|
+
"@open-pioneer/react-utils": "^0.2.1"
|
|
17
17
|
},
|
|
18
18
|
"exports": {
|
|
19
19
|
"./package.json": "./package.json",
|