@contember/bindx-react 0.1.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.
Files changed (194) hide show
  1. package/dist/batching/QueryBatcher.d.ts +31 -0
  2. package/dist/batching/QueryBatcher.d.ts.map +1 -0
  3. package/dist/batching/index.d.ts +2 -0
  4. package/dist/batching/index.d.ts.map +1 -0
  5. package/dist/components/EntityScope.d.ts +28 -0
  6. package/dist/components/EntityScope.d.ts.map +1 -0
  7. package/dist/dataview/DataGrid.d.ts +45 -0
  8. package/dist/dataview/DataGrid.d.ts.map +1 -0
  9. package/dist/dataview/DataGridPagination.d.ts +24 -0
  10. package/dist/dataview/DataGridPagination.d.ts.map +1 -0
  11. package/dist/dataview/DataGridToolbar.d.ts +16 -0
  12. package/dist/dataview/DataGridToolbar.d.ts.map +1 -0
  13. package/dist/dataview/DataViewContext.d.ts +32 -0
  14. package/dist/dataview/DataViewContext.d.ts.map +1 -0
  15. package/dist/dataview/columns.d.ts +115 -0
  16. package/dist/dataview/columns.d.ts.map +1 -0
  17. package/dist/dataview/contextHooks.d.ts +48 -0
  18. package/dist/dataview/contextHooks.d.ts.map +1 -0
  19. package/dist/dataview/dataAttribute.d.ts +6 -0
  20. package/dist/dataview/dataAttribute.d.ts.map +1 -0
  21. package/dist/dataview/export.d.ts +46 -0
  22. package/dist/dataview/export.d.ts.map +1 -0
  23. package/dist/dataview/filterComponents.d.ts +127 -0
  24. package/dist/dataview/filterComponents.d.ts.map +1 -0
  25. package/dist/dataview/filterContext.d.ts +10 -0
  26. package/dist/dataview/filterContext.d.ts.map +1 -0
  27. package/dist/dataview/filterHooks.d.ts +74 -0
  28. package/dist/dataview/filterHooks.d.ts.map +1 -0
  29. package/dist/dataview/filterScope.d.ts +54 -0
  30. package/dist/dataview/filterScope.d.ts.map +1 -0
  31. package/dist/dataview/filterWrappers.d.ts +65 -0
  32. package/dist/dataview/filterWrappers.d.ts.map +1 -0
  33. package/dist/dataview/index.d.ts +21 -0
  34. package/dist/dataview/index.d.ts.map +1 -0
  35. package/dist/dataview/infiniteLoad.d.ts +32 -0
  36. package/dist/dataview/infiniteLoad.d.ts.map +1 -0
  37. package/dist/dataview/loaderComponents.d.ts +80 -0
  38. package/dist/dataview/loaderComponents.d.ts.map +1 -0
  39. package/dist/dataview/pagingComponents.d.ts +50 -0
  40. package/dist/dataview/pagingComponents.d.ts.map +1 -0
  41. package/dist/dataview/renderCellValue.d.ts +9 -0
  42. package/dist/dataview/renderCellValue.d.ts.map +1 -0
  43. package/dist/dataview/selectionComponents.d.ts +62 -0
  44. package/dist/dataview/selectionComponents.d.ts.map +1 -0
  45. package/dist/dataview/sortingComponents.d.ts +39 -0
  46. package/dist/dataview/sortingComponents.d.ts.map +1 -0
  47. package/dist/dataview/stateStorage.d.ts +19 -0
  48. package/dist/dataview/stateStorage.d.ts.map +1 -0
  49. package/dist/dataview/useDataView.d.ts +58 -0
  50. package/dist/dataview/useDataView.d.ts.map +1 -0
  51. package/dist/dataview/useDataViewState.d.ts +89 -0
  52. package/dist/dataview/useDataViewState.d.ts.map +1 -0
  53. package/dist/hooks/BackendAdapterContext.d.ts +110 -0
  54. package/dist/hooks/BackendAdapterContext.d.ts.map +1 -0
  55. package/dist/hooks/ContemberBindxProvider.d.ts +67 -0
  56. package/dist/hooks/ContemberBindxProvider.d.ts.map +1 -0
  57. package/dist/hooks/createBindx.d.ts +39 -0
  58. package/dist/hooks/createBindx.d.ts.map +1 -0
  59. package/dist/hooks/index.d.ts +10 -0
  60. package/dist/hooks/index.d.ts.map +1 -0
  61. package/dist/hooks/useBindxEvents.d.ts +83 -0
  62. package/dist/hooks/useBindxEvents.d.ts.map +1 -0
  63. package/dist/hooks/useEntity.d.ts +123 -0
  64. package/dist/hooks/useEntity.d.ts.map +1 -0
  65. package/dist/hooks/useEntityBeforePersist.d.ts +22 -0
  66. package/dist/hooks/useEntityBeforePersist.d.ts.map +1 -0
  67. package/dist/hooks/useEntityCore.d.ts +52 -0
  68. package/dist/hooks/useEntityCore.d.ts.map +1 -0
  69. package/dist/hooks/useEntityImpl.d.ts +105 -0
  70. package/dist/hooks/useEntityImpl.d.ts.map +1 -0
  71. package/dist/hooks/useEntityList.d.ts +102 -0
  72. package/dist/hooks/useEntityList.d.ts.map +1 -0
  73. package/dist/hooks/useEntityListCore.d.ts +49 -0
  74. package/dist/hooks/useEntityListCore.d.ts.map +1 -0
  75. package/dist/hooks/useEntityListImpl.d.ts +70 -0
  76. package/dist/hooks/useEntityListImpl.d.ts.map +1 -0
  77. package/dist/hooks/useErrors.d.ts +72 -0
  78. package/dist/hooks/useErrors.d.ts.map +1 -0
  79. package/dist/hooks/usePersist.d.ts +115 -0
  80. package/dist/hooks/usePersist.d.ts.map +1 -0
  81. package/dist/hooks/useSelectionCollection.d.ts +41 -0
  82. package/dist/hooks/useSelectionCollection.d.ts.map +1 -0
  83. package/dist/hooks/useSelectionCollectionForList.d.ts +40 -0
  84. package/dist/hooks/useSelectionCollectionForList.d.ts.map +1 -0
  85. package/dist/hooks/useStableSelectionMeta.d.ts +11 -0
  86. package/dist/hooks/useStableSelectionMeta.d.ts.map +1 -0
  87. package/dist/hooks/useStoreSubscription.d.ts +19 -0
  88. package/dist/hooks/useStoreSubscription.d.ts.map +1 -0
  89. package/dist/hooks/useUndo.d.ts +45 -0
  90. package/dist/hooks/useUndo.d.ts.map +1 -0
  91. package/dist/index.d.ts +17 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/jsx/SelectionMeta.d.ts +2 -0
  94. package/dist/jsx/SelectionMeta.d.ts.map +1 -0
  95. package/dist/jsx/analyzer.d.ts +22 -0
  96. package/dist/jsx/analyzer.d.ts.map +1 -0
  97. package/dist/jsx/collectorProxy.d.ts +14 -0
  98. package/dist/jsx/collectorProxy.d.ts.map +1 -0
  99. package/dist/jsx/componentBuilder.d.ts +51 -0
  100. package/dist/jsx/componentBuilder.d.ts.map +1 -0
  101. package/dist/jsx/componentBuilder.types.d.ts +268 -0
  102. package/dist/jsx/componentBuilder.types.d.ts.map +1 -0
  103. package/dist/jsx/componentBuilderCompat.d.ts +17 -0
  104. package/dist/jsx/componentBuilderCompat.d.ts.map +1 -0
  105. package/dist/jsx/componentFactory.d.ts +39 -0
  106. package/dist/jsx/componentFactory.d.ts.map +1 -0
  107. package/dist/jsx/components/Entity.d.ts +82 -0
  108. package/dist/jsx/components/Entity.d.ts.map +1 -0
  109. package/dist/jsx/components/EntityList.d.ts +48 -0
  110. package/dist/jsx/components/EntityList.d.ts.map +1 -0
  111. package/dist/jsx/components/Field.d.ts +27 -0
  112. package/dist/jsx/components/Field.d.ts.map +1 -0
  113. package/dist/jsx/components/HasMany.d.ts +34 -0
  114. package/dist/jsx/components/HasMany.d.ts.map +1 -0
  115. package/dist/jsx/components/HasOne.d.ts +25 -0
  116. package/dist/jsx/components/HasOne.d.ts.map +1 -0
  117. package/dist/jsx/components/HasRole.d.ts +51 -0
  118. package/dist/jsx/components/HasRole.d.ts.map +1 -0
  119. package/dist/jsx/components/If.d.ts +51 -0
  120. package/dist/jsx/components/If.d.ts.map +1 -0
  121. package/dist/jsx/components/Show.d.ts +33 -0
  122. package/dist/jsx/components/Show.d.ts.map +1 -0
  123. package/dist/jsx/components/index.d.ts +8 -0
  124. package/dist/jsx/components/index.d.ts.map +1 -0
  125. package/dist/jsx/conditions.d.ts +310 -0
  126. package/dist/jsx/conditions.d.ts.map +1 -0
  127. package/dist/jsx/createComponent.d.ts +44 -0
  128. package/dist/jsx/createComponent.d.ts.map +1 -0
  129. package/dist/jsx/index.d.ts +19 -0
  130. package/dist/jsx/index.d.ts.map +1 -0
  131. package/dist/jsx/inlineProxy.d.ts +14 -0
  132. package/dist/jsx/inlineProxy.d.ts.map +1 -0
  133. package/dist/jsx/legacyTypes.d.ts +26 -0
  134. package/dist/jsx/legacyTypes.d.ts.map +1 -0
  135. package/dist/jsx/proxy.d.ts +2 -0
  136. package/dist/jsx/proxy.d.ts.map +1 -0
  137. package/dist/jsx/proxyShared.d.ts +14 -0
  138. package/dist/jsx/proxyShared.d.ts.map +1 -0
  139. package/dist/jsx/runtimeProxy.d.ts +11 -0
  140. package/dist/jsx/runtimeProxy.d.ts.map +1 -0
  141. package/dist/jsx/standaloneCreateComponent.d.ts +30 -0
  142. package/dist/jsx/standaloneCreateComponent.d.ts.map +1 -0
  143. package/dist/jsx/types.d.ts +109 -0
  144. package/dist/jsx/types.d.ts.map +1 -0
  145. package/dist/jsx/withCollector.d.ts +39 -0
  146. package/dist/jsx/withCollector.d.ts.map +1 -0
  147. package/dist/roles/RoleContext.d.ts +31 -0
  148. package/dist/roles/RoleContext.d.ts.map +1 -0
  149. package/dist/roles/index.d.ts +2 -0
  150. package/dist/roles/index.d.ts.map +1 -0
  151. package/package.json +34 -0
  152. package/src/batching/QueryBatcher.ts +114 -0
  153. package/src/batching/index.ts +1 -0
  154. package/src/components/EntityScope.tsx +43 -0
  155. package/src/hooks/BackendAdapterContext.tsx +214 -0
  156. package/src/hooks/ContemberBindxProvider.tsx +158 -0
  157. package/src/hooks/index.ts +61 -0
  158. package/src/hooks/useBindxEvents.ts +229 -0
  159. package/src/hooks/useEntity.ts +489 -0
  160. package/src/hooks/useEntityBeforePersist.ts +32 -0
  161. package/src/hooks/useEntityList.ts +444 -0
  162. package/src/hooks/useErrors.ts +150 -0
  163. package/src/hooks/usePersist.ts +377 -0
  164. package/src/hooks/useSelectionCollection.ts +122 -0
  165. package/src/hooks/useStoreSubscription.ts +51 -0
  166. package/src/hooks/useUndo.ts +83 -0
  167. package/src/index.ts +357 -0
  168. package/src/jsx/SelectionMeta.ts +2 -0
  169. package/src/jsx/analyzer.ts +261 -0
  170. package/src/jsx/collectorProxy.ts +282 -0
  171. package/src/jsx/componentBuilder.ts +180 -0
  172. package/src/jsx/componentBuilder.types.ts +463 -0
  173. package/src/jsx/componentBuilderCompat.ts +39 -0
  174. package/src/jsx/componentFactory.ts +400 -0
  175. package/src/jsx/components/Entity.tsx +383 -0
  176. package/src/jsx/components/EntityList.tsx +147 -0
  177. package/src/jsx/components/Field.tsx +79 -0
  178. package/src/jsx/components/HasMany.tsx +109 -0
  179. package/src/jsx/components/HasOne.tsx +78 -0
  180. package/src/jsx/components/HasRole.tsx +95 -0
  181. package/src/jsx/components/If.tsx +127 -0
  182. package/src/jsx/components/Show.tsx +56 -0
  183. package/src/jsx/components/index.ts +20 -0
  184. package/src/jsx/conditions.ts +472 -0
  185. package/src/jsx/createComponent.ts +175 -0
  186. package/src/jsx/index.ts +135 -0
  187. package/src/jsx/legacyTypes.ts +30 -0
  188. package/src/jsx/proxy.ts +1 -0
  189. package/src/jsx/proxyShared.ts +42 -0
  190. package/src/jsx/standaloneCreateComponent.ts +47 -0
  191. package/src/jsx/types.ts +192 -0
  192. package/src/jsx/withCollector.ts +45 -0
  193. package/src/roles/RoleContext.tsx +57 -0
  194. package/src/roles/index.ts +1 -0
@@ -0,0 +1,135 @@
1
+ // Types
2
+ export {
3
+ BINDX_COMPONENT,
4
+ FIELD_REF_META,
5
+ type FieldRefMeta,
6
+ // Full types
7
+ type FieldRef,
8
+ type HasManyRef,
9
+ type HasOneRef,
10
+ type HasOneAccessor,
11
+ type EntityRef,
12
+ type EntityAccessor,
13
+ // Base types
14
+ type FieldRefBase,
15
+ type HasManyRefBase,
16
+ type HasOneRefBase,
17
+ type HasOneAccessorBase,
18
+ type EntityRefBase,
19
+ type EntityAccessorBase,
20
+ // Field mapping types
21
+ type EntityFields,
22
+ type SelectedEntityFields,
23
+ type SelectedEntityFieldsBase,
24
+ // Component props
25
+ type FieldProps,
26
+ type HasManyProps,
27
+ type HasOneProps,
28
+ type IfProps,
29
+ type EntityComponentProps,
30
+ type SelectionMeta,
31
+ type SelectionFieldMeta,
32
+ type HasManyComponentOptions,
33
+ type SelectionProvider,
34
+ type AnyBrand,
35
+ } from './types.js'
36
+
37
+ // Selection metadata
38
+ export {
39
+ SelectionMetaCollector,
40
+ mergeSelections,
41
+ createEmptySelection,
42
+ } from './SelectionMeta.js'
43
+
44
+ // Proxy creation
45
+ export {
46
+ createCollectorProxy,
47
+ } from './proxy.js'
48
+
49
+ // JSX Analyzer
50
+ export {
51
+ analyzeJsx,
52
+ collectSelection,
53
+ convertToQuerySelection,
54
+ debugSelection,
55
+ } from './analyzer.js'
56
+
57
+ // Components
58
+ export { Field, FieldWithMeta } from './components/Field.js'
59
+ export { HasMany, HasManyWithMeta } from './components/HasMany.js'
60
+ export { HasOne, HasOneWithMeta } from './components/HasOne.js'
61
+ export { If, IfWithMeta } from './components/If.js'
62
+ export { Show, ShowWithMeta, type ShowProps } from './components/Show.js'
63
+ export { Entity, type EntityProps } from './components/Entity.js'
64
+ export { EntityList, type EntityListProps } from './components/EntityList.js'
65
+ export { HasRole, type HasRoleProps } from './components/HasRole.js'
66
+
67
+ // Condition DSL for <If> component
68
+ export {
69
+ cond,
70
+ isCondition,
71
+ evaluateCondition,
72
+ collectConditionFields,
73
+ CONDITION_META,
74
+ type Condition,
75
+ type ConditionMeta,
76
+ } from './conditions.js'
77
+
78
+ // Component builder (unified API)
79
+ export {
80
+ isBindxComponent,
81
+ mergeFragments,
82
+ COMPONENT_MARKER,
83
+ COMPONENT_BRAND,
84
+ COMPONENT_SELECTIONS,
85
+ createComponentBuilder,
86
+ ComponentBuilderImpl,
87
+ getComponentBrand,
88
+ setBrandValidation,
89
+ validateBrand,
90
+ } from './createComponent.js'
91
+
92
+ // Standalone createComponent function
93
+ export { createComponent } from './standaloneCreateComponent.js'
94
+
95
+ // withCollector — attach staticRender to a component for selection collection
96
+ export { withCollector } from './withCollector.js'
97
+
98
+ export type {
99
+ SelectionPropMeta,
100
+ BindxComponentBase,
101
+ BindxComponent,
102
+ ComponentBuilder,
103
+ ComponentBuilderState,
104
+ CreateComponentOptions,
105
+ // Interface types
106
+ InterfaceEntityPropConfig,
107
+ ImplicitInterfaceEntityConfig,
108
+ ExplicitInterfaceEntityConfig,
109
+ AddInterfaces,
110
+ InterfaceSelectorsMap,
111
+ AnyEntityPropConfig,
112
+ // Entity prop config types
113
+ EntityPropConfig,
114
+ ImplicitEntityConfig,
115
+ ExplicitEntityConfig,
116
+ // State helpers
117
+ AddImplicitEntity,
118
+ AddExplicitEntity,
119
+ AddImplicitInterfaceEntity,
120
+ AddExplicitInterfaceEntity,
121
+ SetScalarProps,
122
+ // Props building
123
+ BuildEntityProps,
124
+ BuildProps,
125
+ BuildFragmentProps,
126
+ InitialBuilderState,
127
+ } from './createComponent.js'
128
+
129
+ // Legacy type exports for backwards compatibility
130
+ export type {
131
+ EntityPropKeys,
132
+ EntityFromProp,
133
+ SelectionFromProp,
134
+ ImplicitFragmentProperties,
135
+ } from './legacyTypes.js'
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Legacy type exports for backwards compatibility.
3
+ * These types were previously exported from createComponent.ts
4
+ */
5
+
6
+ import type { EntityRef, FluentFragment } from '@contember/bindx'
7
+
8
+ /**
9
+ * Extract keys from props type where value is EntityRef<any, any>
10
+ */
11
+ export type EntityPropKeys<P> = {
12
+ [K in keyof P]: P[K] extends EntityRef<infer _T, infer _S> ? K : never
13
+ }[keyof P]
14
+
15
+ /**
16
+ * Extract the full entity type from an EntityRef prop
17
+ */
18
+ export type EntityFromProp<P, K extends keyof P> = P[K] extends EntityRef<infer T, infer _S> ? T : never
19
+
20
+ /**
21
+ * Extract the selection type from an EntityRef prop
22
+ */
23
+ export type SelectionFromProp<P, K extends keyof P> = P[K] extends EntityRef<infer _T, infer S> ? S : never
24
+
25
+ /**
26
+ * Fragment properties for implicit mode - $propName for each entity prop
27
+ */
28
+ export type ImplicitFragmentProperties<P> = {
29
+ [K in EntityPropKeys<P> as `$${K & string}`]: FluentFragment<EntityFromProp<P, K>, SelectionFromProp<P, K>>
30
+ }
@@ -0,0 +1 @@
1
+ export { createCollectorProxy } from './collectorProxy.js'
@@ -0,0 +1,42 @@
1
+ import {
2
+ type EntityRef,
3
+ type EntityAccessor,
4
+ type EntityFields,
5
+ } from './types.js'
6
+
7
+ /**
8
+ * Known properties on entity accessor that should NOT be treated as field access.
9
+ * Properties are accessed with $ prefix for consistency with EntityHandle.
10
+ * Used by collector proxy.
11
+ */
12
+ export const ENTITY_ACCESSOR_PROPERTIES = new Set([
13
+ 'id',
14
+ '$fields', '$data', '$isDirty', '$persistedId', '$isNew',
15
+ '$errors', '$hasError', '$addError', '$clearErrors', '$clearAllErrors',
16
+ '$on', '$intercept', '$onPersisted', '$interceptPersisting',
17
+ '__entityType', '__entityName',
18
+ ])
19
+
20
+ /**
21
+ * Wraps an EntityRef in a Proxy that supports direct field access.
22
+ * - `entity.fieldName` is equivalent to `entity.$fields.fieldName`
23
+ * - Known accessor properties pass through to the target
24
+ */
25
+ export function wrapEntityRefWithFieldAccessProxy<T>(ref: EntityRef<T>): EntityAccessor<T> {
26
+ return new Proxy(ref, {
27
+ get(target, prop) {
28
+ // Symbols - pass through
29
+ if (typeof prop !== 'string') {
30
+ return Reflect.get(target, prop)
31
+ }
32
+
33
+ // Known accessor properties - pass through
34
+ if (ENTITY_ACCESSOR_PROPERTIES.has(prop)) {
35
+ return Reflect.get(target, prop)
36
+ }
37
+
38
+ // Otherwise, treat as field access
39
+ return target.$fields[prop as keyof EntityFields<T>]
40
+ },
41
+ }) as EntityAccessor<T>
42
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Standalone createComponent function.
3
+ *
4
+ * Unlike the old createBindx()-returned createComponent, this function
5
+ * does not need a schema-bound closure. The SchemaRegistry is passed as null
6
+ * and components resolve it from context at render time if needed.
7
+ */
8
+
9
+ import type {
10
+ ComponentBuilder,
11
+ ComponentBuilderState,
12
+ CreateComponentOptions,
13
+ } from './componentBuilder.types.js'
14
+ import { createComponentBuilder } from './componentBuilder.js'
15
+
16
+ /**
17
+ * Creates a component builder for defining bindx components.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { createComponent } from '@contember/bindx-react'
22
+ * import { schema } from './generated'
23
+ *
24
+ * const ArticleCard = createComponent()
25
+ * .entity('article', schema.Article, e => e.title().author(a => a.name()))
26
+ * .props<{ className?: string }>()
27
+ * .render(({ article, className }) => (
28
+ * <div className={className}>
29
+ * <h2>{article.$data?.title}</h2>
30
+ * <span>{article.$data?.author?.name}</span>
31
+ * </div>
32
+ * ))
33
+ * ```
34
+ */
35
+ // eslint-disable-next-line @typescript-eslint/ban-types
36
+ export function createComponent(): ComponentBuilder<ComponentBuilderState<{}, object, readonly string[]>>
37
+ export function createComponent<const TRoles extends readonly string[]>(
38
+ options: CreateComponentOptions<TRoles>,
39
+ // eslint-disable-next-line @typescript-eslint/ban-types
40
+ ): ComponentBuilder<ComponentBuilderState<{}, object, TRoles>>
41
+ export function createComponent(options?: CreateComponentOptions<readonly string[]>): ComponentBuilder<ComponentBuilderState> {
42
+ const roles = options?.roles ?? []
43
+ return createComponentBuilder(
44
+ null,
45
+ roles,
46
+ )
47
+ }
@@ -0,0 +1,192 @@
1
+ import type { ReactNode } from 'react'
2
+ import type {
3
+ SelectionMeta,
4
+ SelectionFieldMeta,
5
+ EntityFields,
6
+ FieldRefMeta,
7
+ ScalarKeys,
8
+ HasManyKeys,
9
+ HasOneKeys,
10
+ SelectedEntityFields,
11
+ SelectedEntityFieldsBase,
12
+ // Full types
13
+ FieldRef,
14
+ HasManyRef,
15
+ HasOneRef,
16
+ HasOneAccessor,
17
+ EntityRef,
18
+ EntityAccessor,
19
+ // Base types (for component props - accept both)
20
+ FieldRefBase,
21
+ HasManyRefBase,
22
+ HasOneRefBase,
23
+ HasOneAccessorBase,
24
+ EntityRefBase,
25
+ EntityAccessorBase,
26
+ AnyBrand,
27
+ } from '@contember/bindx'
28
+ import { Condition } from './conditions.js'
29
+
30
+ // Re-export unified types for backwards compatibility
31
+ export type { SelectionMeta, SelectionFieldMeta }
32
+
33
+ // Re-export from @contember/bindx
34
+ export { FIELD_REF_META } from '@contember/bindx'
35
+ export type {
36
+ EntityFields,
37
+ FieldRefMeta,
38
+ ScalarKeys,
39
+ HasManyKeys,
40
+ HasOneKeys,
41
+ SelectedEntityFields,
42
+ SelectedEntityFieldsBase,
43
+ // Full types
44
+ FieldRef,
45
+ HasManyRef,
46
+ HasOneRef,
47
+ HasOneAccessor,
48
+ EntityRef,
49
+ EntityAccessor,
50
+ // Base types
51
+ FieldRefBase,
52
+ HasManyRefBase,
53
+ HasOneRefBase,
54
+ HasOneAccessorBase,
55
+ EntityRefBase,
56
+ EntityAccessorBase,
57
+ AnyBrand,
58
+ }
59
+
60
+ /**
61
+ * Marker symbol for identifying bindx components
62
+ */
63
+ export const BINDX_COMPONENT = Symbol('BINDX_COMPONENT')
64
+
65
+ /**
66
+ * Symbol for direct scope access on collector proxies.
67
+ * Replaces NESTED_SELECTION_REF - carries the SelectionScope directly.
68
+ * Used when passing relation entities to nested createComponent components.
69
+ */
70
+ export const SCOPE_REF = Symbol('SCOPE_REF')
71
+
72
+
73
+ /**
74
+ * Props for Field component.
75
+ * Accepts FieldRefBase, so both FieldRef (explicit) and FieldRefBase (implicit) work.
76
+ */
77
+ export interface FieldProps<T> {
78
+ field: FieldRefBase<T>
79
+ children?: (accessor: FieldRef<T>) => ReactNode
80
+ format?: (value: T | null) => ReactNode
81
+ }
82
+
83
+ /**
84
+ * Options for HasMany relation
85
+ */
86
+ export interface HasManyComponentOptions {
87
+ filter?: unknown
88
+ orderBy?: unknown
89
+ limit?: number
90
+ offset?: number
91
+ }
92
+
93
+ /**
94
+ * Props for HasMany component.
95
+ * Selection-aware: children callback receives EntityAccessor with direct field access.
96
+ * Accepts HasManyRefBase, so both HasManyRef (explicit) and HasManyRefBase (implicit) work.
97
+ *
98
+ * @typeParam TEntity - The full entity type
99
+ * @typeParam TSelected - The selected subset of fields (defaults to TEntity for backwards compatibility)
100
+ * @typeParam TBrand - Component brand type for validation (defaults to AnyBrand)
101
+ * @typeParam TEntityName - Entity name as string literal for type narrowing
102
+ * @typeParam TSchema - Schema for entity name lookup in nested relations
103
+ */
104
+ export interface HasManyProps<
105
+ TEntity,
106
+ TSelected = TEntity,
107
+ TBrand extends AnyBrand = AnyBrand,
108
+ TEntityName extends string = string,
109
+ TSchema extends Record<string, object> = Record<string, object>,
110
+ > {
111
+ field: HasManyRefBase<TEntity, TSelected, TBrand, TEntityName, TSchema>
112
+ children: (item: EntityAccessor<TEntity, TSelected, TBrand, TEntityName, TSchema>, index: number) => ReactNode
113
+ filter?: unknown
114
+ orderBy?: unknown
115
+ limit?: number
116
+ offset?: number
117
+ }
118
+
119
+ /**
120
+ * Props for HasOne component.
121
+ * Selection-aware: children callback receives EntityAccessor with direct field access.
122
+ * Accepts HasOneRefBase, so both HasOneRef (explicit) and HasOneRefBase (implicit) work.
123
+ *
124
+ * @typeParam TEntity - The full entity type
125
+ * @typeParam TSelected - The selected subset of fields (defaults to TEntity for backwards compatibility)
126
+ * @typeParam TBrand - Component brand type for validation (defaults to AnyBrand)
127
+ * @typeParam TEntityName - Entity name as string literal for type narrowing
128
+ * @typeParam TSchema - Schema for entity name lookup in nested relations
129
+ */
130
+ export interface HasOneProps<
131
+ TEntity,
132
+ TSelected = TEntity,
133
+ TBrand extends AnyBrand = AnyBrand,
134
+ TEntityName extends string = string,
135
+ TSchema extends Record<string, object> = Record<string, object>,
136
+ > {
137
+ field: HasOneRefBase<TEntity, TSelected, TBrand, TEntityName, TSchema>
138
+ children: (entity: EntityAccessor<TEntity, TSelected, TBrand, TEntityName, TSchema>) => ReactNode
139
+ }
140
+
141
+ /**
142
+ * Props for Entity component.
143
+ * Entity name is preserved for proper HasRole type narrowing.
144
+ * Children receive EntityAccessor with direct field access.
145
+ */
146
+ export interface EntityComponentProps<TSchema extends Record<string, object>, K extends keyof TSchema & string> {
147
+ name: K
148
+ id: string
149
+ children: (entity: EntityAccessor<TSchema[K], TSchema[K], import('@contember/bindx').AnyBrand, K, TSchema>) => ReactNode
150
+ }
151
+
152
+ /**
153
+ * Props for If conditional component.
154
+ *
155
+ * Supports three types of conditions:
156
+ * 1. Boolean literals: `condition={true}` or `condition={someBoolean}`
157
+ * 2. FieldRef<boolean>: `condition={task.isActive}` - field value is used
158
+ * 3. Condition objects: `condition={cond.hasItems(task.developers)}` - composable DSL
159
+ *
160
+ * Using the Condition DSL is recommended for implicit selection mode as it ensures
161
+ * all referenced fields are collected for the GraphQL query.
162
+ */
163
+ export interface IfProps {
164
+ /**
165
+ * Condition to evaluate. Can be:
166
+ * - A boolean literal
167
+ * - A FieldRef<boolean>
168
+ * - A Condition object from the condition builders (hasItems, isEmpty, eq, and, or, not, etc.)
169
+ */
170
+ condition: boolean | FieldRef<boolean> | Condition
171
+ then: ReactNode
172
+ else?: ReactNode
173
+ }
174
+
175
+ /**
176
+ * Interface for components that can provide selection info
177
+ */
178
+ export interface SelectionProvider {
179
+ getSelection(
180
+ props: unknown,
181
+ collectNested: (children: ReactNode) => SelectionMeta,
182
+ ): SelectionFieldMeta | SelectionFieldMeta[] | null
183
+ }
184
+
185
+ // Re-export component types
186
+ export type {
187
+ EntityPropKeys,
188
+ EntityFromProp,
189
+ SelectionFromProp,
190
+ ImplicitFragmentProperties,
191
+ } from './legacyTypes.js'
192
+ export { COMPONENT_MARKER, COMPONENT_SELECTIONS } from './componentBuilder.js'
@@ -0,0 +1,45 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ /**
4
+ * Attaches a static render function to a component for selection collection.
5
+ *
6
+ * During the collection phase, the analyzer calls `staticRender(props)` instead of
7
+ * analyzing runtime children. Props contain collector proxies, so field accesses
8
+ * are tracked automatically. The returned JSX is analyzed for nested components.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // Simple: children is a render prop receiving has-one entity
13
+ * export const SelectField = withCollector(
14
+ * function SelectField({ field, children, ... }) { ... },
15
+ * (props) => props.children(props.field.$entity)
16
+ * )
17
+ *
18
+ * // Composing with HasMany for iteration
19
+ * export const DefaultRepeater = withCollector(
20
+ * function DefaultRepeater({ field, children, ... }) { ... },
21
+ * (props) => (
22
+ * <HasMany field={props.field}>
23
+ * {item => props.children(item, collectionItemInfo)}
24
+ * </HasMany>
25
+ * )
26
+ * )
27
+ *
28
+ * // Programmatic field access (no JSX needed)
29
+ * export const Uploader = withCollector(
30
+ * function Uploader({ field, fileType }) { ... },
31
+ * (props) => {
32
+ * const entity = props.field.$entity
33
+ * for (const ext of props.fileType.extractors) entity[ext.fieldName]
34
+ * return null
35
+ * }
36
+ * )
37
+ * ```
38
+ */
39
+ export function withCollector<TComponent extends (...args: never[]) => ReactNode>(
40
+ component: TComponent,
41
+ staticRender: (props: Parameters<TComponent>[0]) => ReactNode,
42
+ ): TComponent {
43
+ (component as TComponent & { staticRender: typeof staticRender }).staticRender = staticRender
44
+ return component
45
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Role provider context for runtime role checking.
3
+ *
4
+ * HasRole uses this to determine if the current user has the required roles.
5
+ * Without a RoleProvider, HasRole always renders (no gating).
6
+ */
7
+
8
+ import React, { createContext, useContext, type ReactNode, type ReactElement } from 'react'
9
+
10
+ // ============================================================================
11
+ // Context
12
+ // ============================================================================
13
+
14
+ type HasRoleFn = (role: string) => boolean
15
+
16
+ const RoleContext = createContext<HasRoleFn | null>(null)
17
+
18
+ // ============================================================================
19
+ // Provider
20
+ // ============================================================================
21
+
22
+ export interface RoleProviderProps {
23
+ children: ReactNode
24
+ /** Function that checks if the current user has a given role */
25
+ hasRole: HasRoleFn
26
+ }
27
+
28
+ /**
29
+ * Provides runtime role checking for HasRole components.
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * <RoleProvider hasRole={role => currentUser.roles.includes(role)}>
34
+ * <App />
35
+ * </RoleProvider>
36
+ * ```
37
+ */
38
+ export function RoleProvider({ children, hasRole }: RoleProviderProps): ReactElement {
39
+ return <RoleContext.Provider value={hasRole}>{children}</RoleContext.Provider>
40
+ }
41
+
42
+ // ============================================================================
43
+ // Hook
44
+ // ============================================================================
45
+
46
+ /**
47
+ * Returns a function to check if the current user has a given role.
48
+ * If no RoleProvider is present, returns a function that always returns true.
49
+ */
50
+ export function useHasRole(): HasRoleFn {
51
+ const hasRole = useContext(RoleContext)
52
+ return hasRole ?? alwaysTrue
53
+ }
54
+
55
+ function alwaysTrue(): boolean {
56
+ return true
57
+ }
@@ -0,0 +1 @@
1
+ export { RoleProvider, useHasRole, type RoleProviderProps } from './RoleContext.js'