@contember/react-select 1.3.0-alpha.20 → 1.3.0-alpha.21

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 (81) hide show
  1. package/dist/development/components/MultiSelect.cjs +15 -8
  2. package/dist/development/components/MultiSelect.cjs.map +1 -1
  3. package/dist/development/components/MultiSelect.js +16 -9
  4. package/dist/development/components/MultiSelect.js.map +1 -1
  5. package/dist/development/components/Select.cjs +15 -8
  6. package/dist/development/components/Select.cjs.map +1 -1
  7. package/dist/development/components/Select.js +16 -9
  8. package/dist/development/components/Select.js.map +1 -1
  9. package/dist/development/components/SelectDataView.cjs +23 -5
  10. package/dist/development/components/SelectDataView.cjs.map +1 -1
  11. package/dist/development/components/SelectDataView.js +24 -6
  12. package/dist/development/components/SelectDataView.js.map +1 -1
  13. package/dist/development/components/SortableMultiSelect.cjs +30 -10
  14. package/dist/development/components/SortableMultiSelect.cjs.map +1 -1
  15. package/dist/development/components/SortableMultiSelect.js +32 -12
  16. package/dist/development/components/SortableMultiSelect.js.map +1 -1
  17. package/dist/development/contexts.cjs +5 -0
  18. package/dist/development/contexts.cjs.map +1 -1
  19. package/dist/development/contexts.js +6 -1
  20. package/dist/development/contexts.js.map +1 -1
  21. package/dist/development/hooks/useSelectFilter.cjs +31 -0
  22. package/dist/development/hooks/useSelectFilter.cjs.map +1 -0
  23. package/dist/development/hooks/useSelectFilter.js +31 -0
  24. package/dist/development/hooks/useSelectFilter.js.map +1 -0
  25. package/dist/development/index.cjs +4 -0
  26. package/dist/development/index.cjs.map +1 -1
  27. package/dist/development/index.js +6 -2
  28. package/dist/development/index.js.map +1 -1
  29. package/dist/production/components/MultiSelect.cjs +6 -3
  30. package/dist/production/components/MultiSelect.cjs.map +1 -1
  31. package/dist/production/components/MultiSelect.js +7 -4
  32. package/dist/production/components/MultiSelect.js.map +1 -1
  33. package/dist/production/components/Select.cjs +6 -3
  34. package/dist/production/components/Select.cjs.map +1 -1
  35. package/dist/production/components/Select.js +7 -4
  36. package/dist/production/components/Select.js.map +1 -1
  37. package/dist/production/components/SelectDataView.cjs +15 -1
  38. package/dist/production/components/SelectDataView.cjs.map +1 -1
  39. package/dist/production/components/SelectDataView.js +16 -2
  40. package/dist/production/components/SelectDataView.js.map +1 -1
  41. package/dist/production/components/SortableMultiSelect.cjs +19 -3
  42. package/dist/production/components/SortableMultiSelect.cjs.map +1 -1
  43. package/dist/production/components/SortableMultiSelect.js +21 -5
  44. package/dist/production/components/SortableMultiSelect.js.map +1 -1
  45. package/dist/production/contexts.cjs +5 -0
  46. package/dist/production/contexts.cjs.map +1 -1
  47. package/dist/production/contexts.js +6 -1
  48. package/dist/production/contexts.js.map +1 -1
  49. package/dist/production/hooks/useSelectFilter.cjs +31 -0
  50. package/dist/production/hooks/useSelectFilter.cjs.map +1 -0
  51. package/dist/production/hooks/useSelectFilter.js +31 -0
  52. package/dist/production/hooks/useSelectFilter.js.map +1 -0
  53. package/dist/production/index.cjs +4 -0
  54. package/dist/production/index.cjs.map +1 -1
  55. package/dist/production/index.js +6 -2
  56. package/dist/production/index.js.map +1 -1
  57. package/dist/types/components/MultiSelect.d.ts +5 -4
  58. package/dist/types/components/MultiSelect.d.ts.map +1 -1
  59. package/dist/types/components/Select.d.ts +5 -4
  60. package/dist/types/components/Select.d.ts.map +1 -1
  61. package/dist/types/components/SelectDataView.d.ts.map +1 -1
  62. package/dist/types/components/SortableMultiSelect.d.ts +5 -4
  63. package/dist/types/components/SortableMultiSelect.d.ts.map +1 -1
  64. package/dist/types/contexts.d.ts +4 -0
  65. package/dist/types/contexts.d.ts.map +1 -1
  66. package/dist/types/hooks/index.d.ts +2 -0
  67. package/dist/types/hooks/index.d.ts.map +1 -0
  68. package/dist/types/hooks/useSelectFilter.d.ts +8 -0
  69. package/dist/types/hooks/useSelectFilter.d.ts.map +1 -0
  70. package/dist/types/index.d.ts +1 -0
  71. package/dist/types/index.d.ts.map +1 -1
  72. package/dist/types/tsconfig.tsbuildinfo +1 -1
  73. package/package.json +6 -6
  74. package/src/components/MultiSelect.tsx +11 -5
  75. package/src/components/Select.tsx +12 -5
  76. package/src/components/SelectDataView.tsx +15 -4
  77. package/src/components/SortableMultiSelect.tsx +41 -6
  78. package/src/contexts.ts +6 -0
  79. package/src/hooks/index.ts +1 -0
  80. package/src/hooks/useSelectFilter.ts +35 -0
  81. package/src/index.ts +1 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contember/react-select",
3
3
  "license": "Apache-2.0",
4
- "version": "1.3.0-alpha.20",
4
+ "version": "1.3.0-alpha.21",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "main": "./dist/production/index.js",
@@ -40,11 +40,11 @@
40
40
  "directory": "packages/react-select"
41
41
  },
42
42
  "dependencies": {
43
- "@contember/react-binding": "1.3.0-alpha.20",
44
- "@contember/react-dataview": "1.3.0-alpha.20",
45
- "@contember/react-repeater": "1.3.0-alpha.20",
46
- "@contember/react-utils": "1.3.0-alpha.20",
47
- "@contember/utilities": "1.3.0-alpha.20",
43
+ "@contember/react-binding": "1.3.0-alpha.21",
44
+ "@contember/react-dataview": "1.3.0-alpha.21",
45
+ "@contember/react-repeater": "1.3.0-alpha.21",
46
+ "@contember/react-utils": "1.3.0-alpha.21",
47
+ "@contember/utilities": "1.3.0-alpha.21",
48
48
  "@radix-ui/react-slot": "^1.0.2"
49
49
  },
50
50
  "peerDependencies": {
@@ -1,19 +1,23 @@
1
1
  import React, { ReactNode, useCallback, useMemo } from 'react'
2
- import { SelectCurrentEntitiesContext, SelectHandler, SelectHandleSelectContext, SelectIsSelectedContext, SelectOptionsContext } from '../contexts'
2
+ import { SelectCurrentEntitiesContext, SelectHandler, SelectHandleSelectContext, SelectIsSelectedContext, SelectOptionsContext, SelectOptionsFilterContext } from '../contexts'
3
3
  import { Component, EntityAccessor, HasMany, SugaredQualifiedEntityList, SugaredRelativeEntityList, useEntityList } from '@contember/react-binding'
4
4
  import { useReferentiallyStableCallback } from '@contember/react-utils'
5
5
  import { SelectEvents } from '../types'
6
+ import { SelectFilterFieldProps, useSelectFilter } from '../hooks'
6
7
 
7
8
  export type MultiSelectProps =
8
9
  & {
9
10
  children: ReactNode
10
11
  field: SugaredRelativeEntityList['field']
11
- options: SugaredQualifiedEntityList['entities']
12
+ options?: SugaredQualifiedEntityList['entities']
12
13
  }
14
+ & SelectFilterFieldProps
13
15
  & SelectEvents
14
16
 
15
- export const MultiSelect = Component(({ field, children, options, onSelect, onUnselect }: MultiSelectProps) => {
17
+ export const MultiSelect = Component(({ field, children, options, onSelect, onUnselect, filterField }: MultiSelectProps) => {
16
18
  const entities = useEntityList({ field })
19
+ options ??= entities.name
20
+ const filter = useSelectFilter({ filterField, marker: entities.getMarker() })
17
21
  const entitiesArr = useMemo(() => Array.from(entities), [entities])
18
22
  const selectedEntities = useMemo(() => Array.from(entities).map(it => it.id), [entities])
19
23
 
@@ -39,7 +43,9 @@ export const MultiSelect = Component(({ field, children, options, onSelect, onUn
39
43
  <SelectIsSelectedContext.Provider value={isSelected}>
40
44
  <SelectHandleSelectContext.Provider value={handler}>
41
45
  <SelectOptionsContext.Provider value={options}>
42
- {children}
46
+ <SelectOptionsFilterContext.Provider value={filter}>
47
+ {children}
48
+ </SelectOptionsFilterContext.Provider>
43
49
  </SelectOptionsContext.Provider>
44
50
  </SelectHandleSelectContext.Provider>
45
51
  </SelectIsSelectedContext.Provider>
@@ -47,7 +53,7 @@ export const MultiSelect = Component(({ field, children, options, onSelect, onUn
47
53
  )
48
54
  }, ({ field, children }) => {
49
55
  return (
50
- <HasMany field={field}>
56
+ <HasMany field={field} expectedMutation="connectOrDisconnect">
51
57
  {children}
52
58
  </HasMany>
53
59
  )
@@ -1,20 +1,25 @@
1
1
  import React, { ReactNode, useCallback, useMemo } from 'react'
2
- import { SelectCurrentEntitiesContext, SelectHandler, SelectHandleSelectContext, SelectIsSelectedContext, SelectOptionsContext } from '../contexts'
2
+ import { SelectCurrentEntitiesContext, SelectHandler, SelectHandleSelectContext, SelectIsSelectedContext, SelectOptionsContext, SelectOptionsFilterContext } from '../contexts'
3
3
  import { Component, EntityAccessor, HasOne, SugaredQualifiedEntityList, SugaredRelativeSingleEntity, useEntity } from '@contember/react-binding'
4
4
  import { useReferentiallyStableCallback } from '@contember/react-utils'
5
5
  import { SelectEvents } from '../types'
6
+ import { SelectFilterFieldProps, useSelectFilter } from '../hooks'
6
7
 
7
8
  export type SelectProps =
8
9
  & {
9
10
  children: ReactNode
10
11
  field: SugaredRelativeSingleEntity['field']
11
- options: SugaredQualifiedEntityList['entities']
12
+ options?: SugaredQualifiedEntityList['entities']
12
13
  }
14
+ & SelectFilterFieldProps
13
15
  & SelectEvents
14
16
 
15
- export const Select = Component(({ field, children, onUnselect, onSelect, options }: SelectProps) => {
17
+ export const Select = Component(({ field, children, onUnselect, onSelect, options, filterField }: SelectProps) => {
16
18
  const entity = useEntity()
17
19
  const selectedEntity = entity.getEntity({ field })
20
+ options ??= selectedEntity.name
21
+ const filter = useSelectFilter({ filterField, marker: selectedEntity.getMarker() })
22
+
18
23
  const entityExists = selectedEntity.existsOnServer || selectedEntity.hasUnpersistedChanges
19
24
  const entitiesArr = useMemo(() => entityExists ? [selectedEntity] : [], [entityExists, selectedEntity])
20
25
 
@@ -37,7 +42,9 @@ export const Select = Component(({ field, children, onUnselect, onSelect, option
37
42
  <SelectIsSelectedContext.Provider value={isSelected}>
38
43
  <SelectHandleSelectContext.Provider value={handleSelect}>
39
44
  <SelectOptionsContext.Provider value={options}>
40
- {children}
45
+ <SelectOptionsFilterContext.Provider value={filter}>
46
+ {children}
47
+ </SelectOptionsFilterContext.Provider>
41
48
  </SelectOptionsContext.Provider>
42
49
  </SelectHandleSelectContext.Provider>
43
50
  </SelectIsSelectedContext.Provider>
@@ -45,7 +52,7 @@ export const Select = Component(({ field, children, onUnselect, onSelect, option
45
52
  )
46
53
  }, ({ field, children }) => {
47
54
  return (
48
- <HasOne field={field}>
55
+ <HasOne field={field} expectedMutation="connectOrDisconnect">
49
56
  {children}
50
57
  </HasOne>
51
58
  )
@@ -1,6 +1,6 @@
1
- import React, { ReactNode } from 'react'
2
- import { useSelectHandleSelect, useSelectOptions } from '../contexts'
3
- import { DataViewProps, DataView } from '@contember/react-dataview'
1
+ import React, { ReactNode, useMemo } from 'react'
2
+ import { useSelectHandleSelect, useSelectOptions, useSelectOptionsFilter } from '../contexts'
3
+ import { DataViewProps, DataView, DataViewFilterHandlerRegistry } from '@contember/react-dataview'
4
4
 
5
5
  export type SelectDataViewProps =
6
6
  & Omit<DataViewProps, 'entities'>
@@ -11,7 +11,18 @@ export type SelectDataViewProps =
11
11
  export const SelectDataView = (props: SelectDataViewProps) => {
12
12
  const handleSelect = useSelectHandleSelect()
13
13
  const entities = useSelectOptions()
14
+ const filter = useSelectOptionsFilter()
15
+ const defaultFilterTypes = useMemo((): DataViewFilterHandlerRegistry => filter ? { query: filter } : {}, [filter])
16
+
14
17
  return (
15
- <DataView {...props} onSelectHighlighted={handleSelect} entities={entities} />
18
+ <DataView
19
+ filterTypes={defaultFilterTypes}
20
+ {...props}
21
+ onSelectHighlighted={handleSelect}
22
+ entities={entities}
23
+ filteringStateStorage="null"
24
+ sortingStateStorage="null"
25
+ currentPageStateStorage="null"
26
+ />
16
27
  )
17
28
  }
@@ -1,24 +1,57 @@
1
1
  import React, { ReactNode, useCallback, useMemo } from 'react'
2
- import { SelectCurrentEntitiesContext, SelectHandler, SelectHandleSelectContext, SelectIsSelectedContext, SelectOptionsContext } from '../contexts'
3
- import { Component, EntityAccessor, HasOne, SugaredQualifiedEntityList, SugaredRelativeEntityList, SugaredRelativeSingleEntity, SugaredRelativeSingleField, useEntityList } from '@contember/react-binding'
2
+ import { SelectCurrentEntitiesContext, SelectHandler, SelectHandleSelectContext, SelectIsSelectedContext, SelectOptionsContext, SelectOptionsFilterContext } from '../contexts'
3
+ import {
4
+ Component,
5
+ EntityAccessor,
6
+ FieldMarker,
7
+ HasOne,
8
+ MeaningfulMarker,
9
+ PlaceholderGenerator,
10
+ QueryLanguage,
11
+ SugaredQualifiedEntityList,
12
+ SugaredRelativeEntityList,
13
+ SugaredRelativeSingleEntity,
14
+ SugaredRelativeSingleField,
15
+ useEntityList,
16
+ } from '@contember/react-binding'
4
17
  import { useReferentiallyStableCallback } from '@contember/react-utils'
5
18
  import { Repeater } from '@contember/react-repeater'
6
19
  import { SelectEvents } from '../types'
20
+ import { SelectFilterFieldProps, useSelectFilter } from '../hooks'
7
21
 
8
22
  export type SortableMultiSelectProps =
9
23
  & {
10
24
  children: ReactNode
11
25
  field: SugaredRelativeEntityList['field']
12
- options: SugaredQualifiedEntityList['entities']
26
+ options?: SugaredQualifiedEntityList['entities']
13
27
  sortableBy: SugaredRelativeSingleField['field']
14
28
  connectAt: SugaredRelativeSingleEntity['field']
15
29
  }
30
+ & SelectFilterFieldProps
16
31
  & SelectEvents
17
32
 
18
- export const SortableMultiSelect = Component(({ field, children, sortableBy, connectAt, options, onSelect, onUnselect }: SortableMultiSelectProps) => {
33
+ export const SortableMultiSelect = Component(({ field, children, sortableBy, connectAt, options, onSelect, onUnselect, filterField }: SortableMultiSelectProps) => {
19
34
  const list = useEntityList({ field })
20
35
  const entitiesArr = useMemo(() => Array.from(list), [list])
21
36
 
37
+ const optionsMarker = useMemo(() => {
38
+ const desugared = QueryLanguage.desugarRelativeSingleEntity({ field: connectAt }, list.environment)
39
+ let marker: Exclude<MeaningfulMarker, FieldMarker> = list.getMarker()
40
+ for (let relation of desugared.hasOneRelationPath) {
41
+ const placeholder = PlaceholderGenerator.getHasOneRelationPlaceholder(relation)
42
+ const relationMarker = marker.fields.markers.get(placeholder)
43
+ if (!relationMarker || relationMarker instanceof FieldMarker) {
44
+ throw new Error('Invalid marker')
45
+ }
46
+ marker = relationMarker
47
+ }
48
+ return marker
49
+ }, [connectAt, list])
50
+
51
+ options ??= optionsMarker.environment.getSubTreeNode().entity.name
52
+
53
+ const filter = useSelectFilter({ filterField, marker: optionsMarker })
54
+
22
55
  const selectedEntities = useMemo(() => Array.from(list).map(it => it.getEntity({ field: connectAt }).id), [connectAt, list])
23
56
 
24
57
  const handler = useReferentiallyStableCallback<SelectHandler>((entity, action = 'toggle') => {
@@ -46,7 +79,9 @@ export const SortableMultiSelect = Component(({ field, children, sortableBy, con
46
79
  <SelectIsSelectedContext.Provider value={isSelected}>
47
80
  <SelectHandleSelectContext.Provider value={handler}>
48
81
  <SelectOptionsContext.Provider value={options}>
49
- {children}
82
+ <SelectOptionsFilterContext.Provider value={filter}>
83
+ {children}
84
+ </SelectOptionsFilterContext.Provider>
50
85
  </SelectOptionsContext.Provider>
51
86
  </SelectHandleSelectContext.Provider>
52
87
  </SelectIsSelectedContext.Provider>
@@ -56,7 +91,7 @@ export const SortableMultiSelect = Component(({ field, children, sortableBy, con
56
91
  }, ({ children, field, sortableBy, connectAt }) => {
57
92
  return (
58
93
  <Repeater field={field} sortableBy={sortableBy} initialEntityCount={0}>
59
- <HasOne field={connectAt}>
94
+ <HasOne field={connectAt} expectedMutation="connectOrDisconnect">
60
95
  {children}
61
96
  </HasOne>
62
97
  </Repeater>
package/src/contexts.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createRequiredContext } from '@contember/react-utils'
2
2
  import { EntityAccessor, SugaredQualifiedEntityList } from '@contember/react-binding'
3
+ import { DataViewFilterHandler, TextFilterArtifacts } from '@contember/react-dataview'
3
4
 
4
5
  const _SelectCurrentEntitiesContext = createRequiredContext<EntityAccessor[]>('SelectCurrentEntitiesContext')
5
6
  /** @internal */
@@ -23,3 +24,8 @@ const _SelectOptionsContext = createRequiredContext<SugaredQualifiedEntityList['
23
24
  /** @internal */
24
25
  export const SelectOptionsContext = _SelectOptionsContext[0]
25
26
  export const useSelectOptions = _SelectOptionsContext[1]
27
+
28
+ const _SelectOptionsFilterContext = createRequiredContext<DataViewFilterHandler<TextFilterArtifacts> | undefined>('SelectOptionsFilterContext')
29
+ /** @internal */
30
+ export const SelectOptionsFilterContext = _SelectOptionsFilterContext[0]
31
+ export const useSelectOptionsFilter = _SelectOptionsFilterContext[1]
@@ -0,0 +1 @@
1
+ export * from './useSelectFilter'
@@ -0,0 +1,35 @@
1
+ import { FieldMarker, HasOneRelationMarker, MeaningfulMarker, SugaredRelativeSingleField } from '@contember/react-binding'
2
+ import { createUnionTextFilter } from '@contember/react-dataview'
3
+ import { useMemo } from 'react'
4
+
5
+ export type SelectFilterFieldProps = {
6
+ filterField?: SugaredRelativeSingleField['field'] | SugaredRelativeSingleField['field'][]
7
+ }
8
+
9
+ export const useSelectFilter = ({ filterField, marker }: SelectFilterFieldProps & {
10
+ marker: Exclude<MeaningfulMarker, FieldMarker>
11
+ }) => {
12
+ return useMemo(() => {
13
+ const filter = filterField ?? extractStringFields(marker)
14
+ if (!filter || (Array.isArray(filter) && filter.length === 0)) {
15
+ return undefined
16
+ }
17
+ return createUnionTextFilter(Array.isArray(filter) ? filter : [filter])
18
+ }, [filterField, marker])
19
+ }
20
+
21
+ const extractStringFields = (marker: Exclude<MeaningfulMarker, FieldMarker>): string[] => {
22
+ const node = marker.environment.getSubTreeNode()
23
+ const textFields = []
24
+ for (const field of marker.fields.markers.values()) {
25
+ if (field instanceof FieldMarker) {
26
+ const columnInfo = node.entity.fields.get(field.fieldName)
27
+ if (columnInfo?.type === 'String') {
28
+ textFields.push(field.fieldName)
29
+ }
30
+ } else if (field instanceof HasOneRelationMarker) {
31
+ textFields.push(...extractStringFields(field).map(it => `${field.parameters.field}.${it}`))
32
+ }
33
+ }
34
+ return textFields
35
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './components'
2
2
  export * from './contexts'
3
+ export * from './hooks'
3
4
  export * from './types'