@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,463 @@
1
+ /**
2
+ * Type definitions for the unified createComponent builder API.
3
+ *
4
+ * This provides a fluent builder interface for creating bindx components
5
+ * with support for both implicit (JSX-analyzed) and explicit (selector-based)
6
+ * entity props, scalar props, and optional role constraints.
7
+ */
8
+
9
+ import type { ReactNode, ComponentType } from 'react'
10
+ import type {
11
+ EntityRef,
12
+ EntityAccessor,
13
+ EntityAccessorBase,
14
+ FluentFragment,
15
+ SelectionBuilder,
16
+ AnyBrand,
17
+ SelectionMeta,
18
+ EntityDef,
19
+ ResolveEntity,
20
+ } from '@contember/bindx'
21
+ import type { SelectionProvider } from './types.js'
22
+ import type { Condition } from './conditions.js'
23
+
24
+ // ============================================================================
25
+ // Symbols (re-exported from createComponent.ts)
26
+ // ============================================================================
27
+
28
+ export declare const COMPONENT_MARKER: unique symbol
29
+ export declare const COMPONENT_BRAND: unique symbol
30
+ export declare const COMPONENT_SELECTIONS: unique symbol
31
+
32
+ // ============================================================================
33
+ // Entity Prop Configuration
34
+ // ============================================================================
35
+
36
+ /**
37
+ * Configuration for a single entity prop.
38
+ * Can be implicit (selection from JSX) or explicit (selection from selector).
39
+ * Stores the entity type directly (not entity name).
40
+ */
41
+ export interface EntityPropConfig<
42
+ TEntity extends object = object,
43
+ TSelected extends object = object,
44
+ TIsImplicit extends boolean = boolean,
45
+ > {
46
+ readonly __entity: TEntity
47
+ readonly isImplicit: TIsImplicit
48
+ readonly __selected: TSelected
49
+ }
50
+
51
+ /**
52
+ * Creates an implicit entity prop config type.
53
+ */
54
+ export type ImplicitEntityConfig<TEntity extends object> =
55
+ EntityPropConfig<TEntity, TEntity, true>
56
+
57
+ /**
58
+ * Creates an explicit entity prop config type.
59
+ */
60
+ export type ExplicitEntityConfig<TEntity extends object, TSelected extends object> =
61
+ EntityPropConfig<TEntity, TSelected, false>
62
+
63
+ // ============================================================================
64
+ // Interface Entity Prop Configuration
65
+ // ============================================================================
66
+
67
+ /**
68
+ * Configuration for an interface-based entity prop.
69
+ * Unlike EntityPropConfig, this doesn't require a specific entity type.
70
+ * Instead, it constrains the TSelected type to extend TInterface.
71
+ */
72
+ export interface InterfaceEntityPropConfig<
73
+ TInterface extends object = object,
74
+ TIsImplicit extends boolean = boolean,
75
+ > {
76
+ readonly isInterface: true
77
+ readonly isImplicit: TIsImplicit
78
+ readonly __interface: TInterface
79
+ }
80
+
81
+ /**
82
+ * Creates an implicit interface entity prop config type.
83
+ */
84
+ export type ImplicitInterfaceEntityConfig<TInterface extends object> =
85
+ InterfaceEntityPropConfig<TInterface, true>
86
+
87
+ /**
88
+ * Creates an explicit interface entity prop config type.
89
+ */
90
+ export type ExplicitInterfaceEntityConfig<TInterface extends object> =
91
+ InterfaceEntityPropConfig<TInterface, false>
92
+
93
+ // ============================================================================
94
+ // Builder State
95
+ // ============================================================================
96
+
97
+ /**
98
+ * Union type for all entity prop config types.
99
+ */
100
+ export type AnyEntityPropConfig = EntityPropConfig | InterfaceEntityPropConfig
101
+
102
+ /**
103
+ * Accumulated builder state (type-level).
104
+ * Grows as you chain builder methods.
105
+ */
106
+ export interface ComponentBuilderState<
107
+ // eslint-disable-next-line @typescript-eslint/ban-types
108
+ TEntityProps extends Record<string, AnyEntityPropConfig> = {},
109
+ TScalarProps extends object = object,
110
+ TRoles extends readonly string[] = readonly string[],
111
+ > {
112
+ readonly __entityProps: TEntityProps
113
+ readonly __scalarProps: TScalarProps
114
+ readonly __roles: TRoles
115
+ }
116
+
117
+ // ============================================================================
118
+ // State Update Helpers
119
+ // ============================================================================
120
+
121
+ /**
122
+ * Add an implicit entity to builder state.
123
+ * Entity type comes directly from the EntityDef.
124
+ */
125
+ export type AddImplicitEntity<
126
+ TState extends ComponentBuilderState,
127
+ TPropName extends string,
128
+ TEntity extends object,
129
+ > = ComponentBuilderState<
130
+ TState['__entityProps'] & {
131
+ readonly [K in TPropName]: ImplicitEntityConfig<TEntity>
132
+ },
133
+ TState['__scalarProps'],
134
+ TState['__roles']
135
+ >
136
+
137
+ /**
138
+ * Add an explicit entity to builder state.
139
+ * Entity type comes directly from the EntityDef.
140
+ */
141
+ export type AddExplicitEntity<
142
+ TState extends ComponentBuilderState,
143
+ TPropName extends string,
144
+ TEntity extends object,
145
+ TSelected extends object,
146
+ > = ComponentBuilderState<
147
+ TState['__entityProps'] & {
148
+ readonly [K in TPropName]: ExplicitEntityConfig<TEntity, TSelected>
149
+ },
150
+ TState['__scalarProps'],
151
+ TState['__roles']
152
+ >
153
+
154
+ /**
155
+ * Add an implicit interface entity to builder state.
156
+ */
157
+ export type AddImplicitInterfaceEntity<
158
+ TState extends ComponentBuilderState,
159
+ TPropName extends string,
160
+ TInterface extends object,
161
+ > = ComponentBuilderState<
162
+ TState['__entityProps'] & {
163
+ readonly [K in TPropName]: ImplicitInterfaceEntityConfig<TInterface>
164
+ },
165
+ TState['__scalarProps'],
166
+ TState['__roles']
167
+ >
168
+
169
+ /**
170
+ * Add an explicit interface entity to builder state.
171
+ */
172
+ export type AddExplicitInterfaceEntity<
173
+ TState extends ComponentBuilderState,
174
+ TPropName extends string,
175
+ TInterface extends object,
176
+ > = ComponentBuilderState<
177
+ TState['__entityProps'] & {
178
+ readonly [K in TPropName]: ExplicitInterfaceEntityConfig<TInterface>
179
+ },
180
+ TState['__scalarProps'],
181
+ TState['__roles']
182
+ >
183
+
184
+ /**
185
+ * Add multiple interface entities to builder state.
186
+ * Each key in TInterfaces becomes a prop.
187
+ */
188
+ export type AddInterfaces<
189
+ TState extends ComponentBuilderState,
190
+ TInterfaces extends Record<string, object>,
191
+ > = ComponentBuilderState<
192
+ TState['__entityProps'] & {
193
+ readonly [K in keyof TInterfaces]: InterfaceEntityPropConfig<TInterfaces[K]>
194
+ },
195
+ TState['__scalarProps'],
196
+ TState['__roles']
197
+ >
198
+
199
+ /**
200
+ * Type for selectors parameter in interfaces() method.
201
+ * Maps prop names to selector functions.
202
+ */
203
+ export type InterfaceSelectorsMap<TInterfaces extends Record<string, object>> = {
204
+ readonly [K in keyof TInterfaces]?: (
205
+ e: SelectionBuilder<TInterfaces[K]>,
206
+ ) => SelectionBuilder<TInterfaces[K], TInterfaces[K], object>
207
+ }
208
+
209
+ /**
210
+ * Set scalar props in builder state.
211
+ */
212
+ export type SetScalarProps<
213
+ TState extends ComponentBuilderState,
214
+ TNewScalarProps extends object,
215
+ > = ComponentBuilderState<
216
+ TState['__entityProps'],
217
+ TNewScalarProps,
218
+ TState['__roles']
219
+ >
220
+
221
+ // ============================================================================
222
+ // Props Building
223
+ // ============================================================================
224
+
225
+ /**
226
+ * Build EntityAccessor props from entity config.
227
+ *
228
+ * For explicit selection (selector provided): Returns EntityAccessor with full access
229
+ * - Allows direct field access: `entity.fieldName.value`
230
+ * - Allows relation access: `entity.relation.length`, `entity.relation.$entity`
231
+ *
232
+ * For implicit selection (no selector): Returns EntityAccessorBase with restricted access
233
+ * - Blocks direct field access to enforce declarative patterns
234
+ * - Users must use components: `<Field field={entity.fieldName} />`
235
+ * - Users must use condition DSL: `<If condition={cond.hasItems(entity.relation)} />`
236
+ */
237
+ export type BuildEntityProps<
238
+ TEntityProps extends Record<string, AnyEntityPropConfig>,
239
+ TRoles extends readonly string[],
240
+ > = {
241
+ readonly [K in keyof TEntityProps]: TEntityProps[K] extends EntityPropConfig<
242
+ infer TEntity,
243
+ infer TSelected,
244
+ infer TIsImplicit
245
+ >
246
+ ? TIsImplicit extends true
247
+ // Implicit selection -> restricted EntityAccessorBase (no .value, .length access)
248
+ ? EntityAccessorBase<TEntity, TSelected, AnyBrand, string>
249
+ // Explicit selection -> full EntityAccessor (full access)
250
+ : EntityAccessor<TEntity, TSelected, AnyBrand, string>
251
+ : TEntityProps[K] extends InterfaceEntityPropConfig<infer TInterface, infer TIsImplicit>
252
+ ? TIsImplicit extends true
253
+ // Implicit interface -> restricted
254
+ ? EntityAccessorBase<TInterface, TInterface, AnyBrand, string>
255
+ // Explicit interface -> full access
256
+ : EntityAccessor<TInterface, TInterface, AnyBrand, string>
257
+ : never
258
+ }
259
+
260
+ /**
261
+ * Build complete props type from builder state.
262
+ */
263
+ export type BuildProps<TState extends ComponentBuilderState> =
264
+ TState['__scalarProps'] &
265
+ BuildEntityProps<TState['__entityProps'], TState['__roles']>
266
+
267
+ /**
268
+ * Build fragment properties ($propName) from entity config.
269
+ */
270
+ export type BuildFragmentProps<
271
+ TEntityProps extends Record<string, AnyEntityPropConfig>,
272
+ TRoles extends readonly string[],
273
+ > = {
274
+ readonly [K in keyof TEntityProps as `$${K & string}`]: TEntityProps[K] extends EntityPropConfig<
275
+ infer TEntity,
276
+ infer TSelected,
277
+ infer _TIsImplicit
278
+ >
279
+ ? FluentFragment<TEntity, TSelected, AnyBrand>
280
+ : TEntityProps[K] extends InterfaceEntityPropConfig<infer TInterface, infer _TIsImplicit>
281
+ ? FluentFragment<TInterface, TInterface, AnyBrand>
282
+ : never
283
+ }
284
+
285
+ // ============================================================================
286
+ // Result Component Types
287
+ // ============================================================================
288
+
289
+ /**
290
+ * Metadata for entity prop selections.
291
+ */
292
+ export interface SelectionPropMeta {
293
+ readonly selection: SelectionMeta
294
+ readonly fragment: FluentFragment<unknown, object>
295
+ }
296
+
297
+ /**
298
+ * Base component type with markers.
299
+ */
300
+ export type BindxComponentBase<TProps extends object> = ComponentType<TProps> &
301
+ SelectionProvider & {
302
+ readonly [COMPONENT_MARKER]: true
303
+ readonly [COMPONENT_SELECTIONS]: Map<string, SelectionPropMeta>
304
+ readonly __componentRoles?: readonly string[]
305
+ }
306
+
307
+ /**
308
+ * Complete bindx component type with fragment properties.
309
+ */
310
+ export type BindxComponent<
311
+ TState extends ComponentBuilderState,
312
+ > = BindxComponentBase<BuildProps<TState>> &
313
+ BuildFragmentProps<TState['__entityProps'], TState['__roles']>
314
+
315
+ // ============================================================================
316
+ // Builder Interface
317
+ // ============================================================================
318
+
319
+ /**
320
+ * Fluent builder for creating bindx components.
321
+ *
322
+ * @typeParam TState - Accumulated builder state
323
+ *
324
+ * @example
325
+ * ```typescript
326
+ * createComponent()
327
+ * .entity('article', schema.Article) // implicit
328
+ * .entity('author', schema.Author, e => e.id().name()) // explicit
329
+ * .props<{ className?: string }>()
330
+ * .render(({ article, author, className }) => ...)
331
+ * ```
332
+ */
333
+ export interface ComponentBuilder<
334
+ TState extends ComponentBuilderState = ComponentBuilderState,
335
+ > {
336
+ /**
337
+ * Add an entity prop with implicit selection (collected from JSX).
338
+ * Entity type is resolved based on the builder's roles via ResolveEntity.
339
+ *
340
+ * @param propName - Name of the prop
341
+ * @param entity - EntityDef reference
342
+ */
343
+ entity<TPropName extends string, TRoleMap extends Record<string, object>>(
344
+ propName: TPropName,
345
+ entity: EntityDef<TRoleMap>,
346
+ ): ComponentBuilder<AddImplicitEntity<TState, TPropName, ResolveEntity<TRoleMap, TState['__roles'][number]>>>
347
+
348
+ /**
349
+ * Add an entity prop with explicit selection (from selector function).
350
+ * Entity type is resolved based on the builder's roles via ResolveEntity.
351
+ *
352
+ * @param propName - Name of the prop
353
+ * @param entity - EntityDef reference
354
+ * @param selector - Selection builder function
355
+ */
356
+ entity<
357
+ TPropName extends string,
358
+ TRoleMap extends Record<string, object>,
359
+ TSelected extends object,
360
+ >(
361
+ propName: TPropName,
362
+ entity: EntityDef<TRoleMap>,
363
+ selector: (e: SelectionBuilder<ResolveEntity<TRoleMap, TState['__roles'][number]>>) => SelectionBuilder<ResolveEntity<TRoleMap, TState['__roles'][number]>, TSelected, object>,
364
+ ): ComponentBuilder<AddExplicitEntity<TState, TPropName, ResolveEntity<TRoleMap, TState['__roles'][number]>, TSelected>>
365
+
366
+ /**
367
+ * Add interface-based entity props that accept any EntityRef with matching fields.
368
+ * Each key in TInterfaces becomes a prop name, and the value defines required fields.
369
+ *
370
+ * Props without selectors use implicit mode (selection collected from JSX).
371
+ * Props with selectors use explicit mode (selection from selector function).
372
+ *
373
+ * @example
374
+ * ```typescript
375
+ * interface HasName { name: string }
376
+ * interface HasArchivedAt { archivedAt: string | null }
377
+ *
378
+ * // Implicit mode - selection from JSX
379
+ * const NameCard = createComponent()
380
+ * .interfaces<{ item: HasName }>()
381
+ * .render(({ item }) => <span>{item.fields.name.value}</span>)
382
+ *
383
+ * // Explicit mode - selection from selector
384
+ * const ArchiveIndicator = createComponent()
385
+ * .interfaces<{ item: HasArchivedAt }>({
386
+ * item: e => e.archivedAt(),
387
+ * })
388
+ * .render(({ item }) => <span>{item.data?.archivedAt ? 'Archived' : 'Active'}</span>)
389
+ *
390
+ * // Mixed mode - some implicit, some explicit
391
+ * const Card = createComponent()
392
+ * .interfaces<{ item: HasName; status: HasArchivedAt }>({
393
+ * status: e => e.archivedAt(), // explicit
394
+ * // item has no selector -> implicit from JSX
395
+ * })
396
+ * .render(({ item, status }) => ...)
397
+ * ```
398
+ */
399
+ interfaces<TInterfaces extends Record<string, object>>(
400
+ selectors?: InterfaceSelectorsMap<TInterfaces>,
401
+ ): ComponentBuilder<AddInterfaces<TState, TInterfaces>>
402
+
403
+ /**
404
+ * Define additional scalar (non-entity) props.
405
+ * This is a type-only operation - no runtime effect.
406
+ *
407
+ * @example
408
+ * ```typescript
409
+ * .props<{ className?: string; onClick?: () => void }>()
410
+ * ```
411
+ */
412
+ props<TNewScalarProps extends object>(): ComponentBuilder<SetScalarProps<TState, TNewScalarProps>>
413
+
414
+ /**
415
+ * Add a condition that must be true for the component to render.
416
+ * If the condition is false, the component renders null.
417
+ *
418
+ * Fields used in the condition are automatically collected for the GraphQL query.
419
+ *
420
+ * @param conditionFn - Function that receives entity props and returns a Condition
421
+ *
422
+ * @example
423
+ * ```typescript
424
+ * createComponent()
425
+ * .entity('task', schema.Task)
426
+ * .if(({ task }) => cond.isTruthy(task.project.company.canSeeTimeEstimates))
427
+ * .render(({ task }) => (
428
+ * // Only renders if canSeeTimeEstimates is truthy
429
+ * <div>...</div>
430
+ * ))
431
+ * ```
432
+ */
433
+ if(conditionFn: (props: BuildEntityProps<TState['__entityProps'], TState['__roles']>) => Condition): ComponentBuilder<TState>
434
+
435
+ /**
436
+ * Build the component with the render function.
437
+ *
438
+ * @param renderFn - React render function receiving typed props
439
+ * @returns Bindx component with fragment properties
440
+ */
441
+ render(renderFn: (props: BuildProps<TState>) => ReactNode): BindxComponent<TState>
442
+ }
443
+
444
+ // ============================================================================
445
+ // Factory Types
446
+ // ============================================================================
447
+
448
+ /**
449
+ * Initial builder state with empty entity props and scalar props.
450
+ * Note: Uses {} instead of Record<string, never> to avoid index signature issues
451
+ * when combining with scalar props.
452
+ */
453
+ export type InitialBuilderState<
454
+ TRoles extends readonly string[] = readonly string[],
455
+ // eslint-disable-next-line @typescript-eslint/ban-types
456
+ > = ComponentBuilderState<{}, object, TRoles>
457
+
458
+ /**
459
+ * Options for createComponent.
460
+ */
461
+ export interface CreateComponentOptions<TRoles extends readonly string[] = readonly string[]> {
462
+ readonly roles?: TRoles
463
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Backwards compatibility exports for createComponent.
3
+ * These are used by other parts of the codebase that haven't been migrated yet.
4
+ */
5
+
6
+ import type { ComponentType } from 'react'
7
+ import type { SelectionPropMeta } from './componentBuilder.types.js'
8
+ import { COMPONENT_MARKER, COMPONENT_SELECTIONS } from './componentBuilder.js'
9
+ import { BINDX_COMPONENT } from './types.js'
10
+
11
+ /**
12
+ * Assigns $propName fragment properties to a component.
13
+ * @internal
14
+ */
15
+ export function assignFragmentProperties(
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ component: ComponentType<any>,
18
+ selectionsMap: Map<string, SelectionPropMeta>,
19
+ ): void {
20
+ const result = component as unknown as Record<string, unknown>
21
+ for (const [propName, meta] of selectionsMap) {
22
+ result[`$${propName}`] = meta.fragment
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Assigns standard bindx component markers to a component.
28
+ * @internal
29
+ */
30
+ export function assignComponentMarkers(
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ component: ComponentType<any>,
33
+ selectionsMap: Map<string, SelectionPropMeta>,
34
+ ): void {
35
+ const comp = component as unknown as Record<symbol, unknown>
36
+ comp[BINDX_COMPONENT] = true
37
+ comp[COMPONENT_MARKER] = true
38
+ comp[COMPONENT_SELECTIONS] = selectionsMap
39
+ }