@contember/bindx-react 0.1.37 → 0.1.39

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.
@@ -27,6 +27,7 @@ interface UseEntityResultBase {
27
27
  export type LoadingEntityResult = UseEntityResultBase & {
28
28
  readonly $status: 'loading';
29
29
  readonly $isLoading: true;
30
+ readonly $isRefetching: false;
30
31
  readonly $isError: false;
31
32
  readonly $isNotFound: false;
32
33
  readonly $error: null;
@@ -35,6 +36,7 @@ export type LoadingEntityResult = UseEntityResultBase & {
35
36
  export type ErrorEntityResult = UseEntityResultBase & {
36
37
  readonly $status: 'error';
37
38
  readonly $isLoading: false;
39
+ readonly $isRefetching: false;
38
40
  readonly $isError: true;
39
41
  readonly $isNotFound: false;
40
42
  readonly $error: FieldError;
@@ -43,6 +45,7 @@ export type ErrorEntityResult = UseEntityResultBase & {
43
45
  export type NotFoundEntityResult = UseEntityResultBase & {
44
46
  readonly $status: 'not_found';
45
47
  readonly $isLoading: false;
48
+ readonly $isRefetching: false;
46
49
  readonly $isError: false;
47
50
  readonly $isNotFound: true;
48
51
  readonly $error: null;
@@ -50,10 +53,17 @@ export type NotFoundEntityResult = UseEntityResultBase & {
50
53
  };
51
54
  /**
52
55
  * Ready state — full EntityAccessor with status metadata.
56
+ *
57
+ * `$isRefetching` is `true` while a background re-fetch is in flight
58
+ * (triggered by a `queryKey` change while ready data is already present).
59
+ * The accessor identity and field values remain stable until the new data
60
+ * arrives, so the subtree does not unmount — useful for stale-while-revalidate
61
+ * indicators (subtle spinner, "stale" badge, etc.).
53
62
  */
54
63
  export type ReadyEntityResult<TEntity extends object, TSelected extends object = TEntity> = UseEntityResultBase & EntityAccessor<TEntity, TSelected> & {
55
64
  readonly $status: 'ready';
56
65
  readonly $isLoading: false;
66
+ readonly $isRefetching: boolean;
57
67
  readonly $isError: false;
58
68
  readonly $isNotFound: false;
59
69
  readonly $error: null;
@@ -1 +1 @@
1
- {"version":3,"file":"useEntity.d.ts","sourceRoot":"","sources":["../../src/hooks/useEntity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useEntity.d.ts","sourceRoot":"","sources":["../../src/hooks/useEntity.ts"],"names":[],"mappings":"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"}
@@ -28,18 +28,27 @@ interface EntityListResultBase {
28
28
  export type LoadingEntityListResult = EntityListResultBase & {
29
29
  readonly $status: 'loading';
30
30
  readonly $isLoading: true;
31
+ readonly $isRefetching: false;
31
32
  readonly $isError: false;
32
33
  readonly $error: null;
33
34
  };
34
35
  export type ErrorEntityListResult = EntityListResultBase & {
35
36
  readonly $status: 'error';
36
37
  readonly $isLoading: false;
38
+ readonly $isRefetching: false;
37
39
  readonly $isError: true;
38
40
  readonly $error: FieldError;
39
41
  };
42
+ /**
43
+ * `$isRefetching` is `true` while a background re-fetch is in flight
44
+ * (triggered by a `queryKey` change while ready data is already present).
45
+ * The accessor identity stays stable so the subtree does not unmount —
46
+ * stale-while-revalidate semantics.
47
+ */
40
48
  export type ReadyEntityListResult<T extends object> = EntityListResultBase & {
41
49
  readonly $status: 'ready';
42
50
  readonly $isLoading: false;
51
+ readonly $isRefetching: boolean;
43
52
  readonly $isError: false;
44
53
  readonly $error: null;
45
54
  readonly $isDirty: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"useEntityList.d.ts","sourceRoot":"","sources":["../../src/hooks/useEntityList.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useEntityList.d.ts","sourceRoot":"","sources":["../../src/hooks/useEntityList.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { scalar, enumScalar, hasOne, hasMany, defineSchema, entityDef, roleEntit
8
8
  export type { BindxProviderProps, BindxContextValue, BindxGraphQlClient, UseEntityOptions, UseEntityListOptions, LoadingEntityResult, ErrorEntityResult, NotFoundEntityResult, ReadyEntityResult, UseEntityResult, LoadingEntityListResult, ErrorEntityListResult, ReadyEntityListResult, UseEntityListResult, PersistApi, EntityPersistApi, AnyRefWithMeta, PersistWithFeedbackApi, } from './hooks/index.js';
9
9
  export type { DirtyEntity, PersistScope, AllScope, EntityScope as EntityPersistScope, FieldsScope, RelationScope, CustomScope, EntityPersistResult, PersistenceResult, BatchPersistOptions, } from '@contember/bindx';
10
10
  export type { FieldProps, HasManyProps, HasOneProps, IfProps, EntityComponentProps, HasManyComponentOptions, ShowProps, SwitchProps, CaseProps, DefaultProps, SelectionPropMeta, SelectionProvider, EntityPropKeys, EntityFromProp, SelectionFromProp, ImplicitFragmentProperties, BindxComponentBase, BindxComponent, ComponentBuilder, ComponentBuilderState, CreateComponentOptions, InterfaceEntityPropConfig, ImplicitInterfaceEntityConfig, ExplicitInterfaceEntityConfig, AddInterfaces, InterfaceSelectorsMap, AnyEntityPropConfig, EntityPropConfig, ImplicitEntityConfig, ExplicitEntityConfig, AddImplicitEntity, AddExplicitEntity, AddImplicitInterfaceEntity, AddExplicitInterfaceEntity, SetScalarProps, BuildEntityProps, BuildProps, BuildFragmentProps, InitialBuilderState, } from './jsx/index.js';
11
- export { BindxProvider, useBackendAdapter, useSnapshotStore, useDispatcher, useBatchPersister, useBindxContext, useSchemaRegistry, useEntity, useEntityList, usePersist, usePersistEntity, useUndo, useOnEvent, useOnEntityEvent, useOnFieldEvent, useIntercept, useInterceptEntity, useInterceptField, useAccessor, useField, useHasMany, useHasOne, useNotificationStore, useNotifications, useShowNotification, useDismissNotification, usePersistWithFeedback, ContemberBindxProvider, schemaNamesToDef, } from './hooks/index.js';
11
+ export { BindxProvider, useBackendAdapter, useSnapshotStore, useDispatcher, useBatchPersister, useBindxContext, useSchemaRegistry, useEntity, useEntityList, usePersist, usePersistEntity, useUndo, useOnEvent, useOnEntityEvent, useOnFieldEvent, useIntercept, useInterceptEntity, useInterceptField, useEntityBeforePersist, useAccessor, useField, useHasMany, useHasOne, useNotificationStore, useNotifications, useShowNotification, useDismissNotification, usePersistWithFeedback, ContemberBindxProvider, schemaNamesToDef, } from './hooks/index.js';
12
12
  export { RoleProvider, useHasRole, type RoleProviderProps } from './roles/index.js';
13
13
  export type { UndoHookResult } from './hooks/useUndo.js';
14
14
  export { Attribute, type AttributeProps, Field, HasMany, HasOne, If, Show, Switch, Case, Default, Entity, type EntityProps, EntityList, type EntityListProps, HasRole, type HasRoleProps, BINDX_COMPONENT, SCOPE_REF, cond, type Condition, createComponent, withCollector, isBindxComponent, mergeFragments, COMPONENT_MARKER, COMPONENT_BRAND, COMPONENT_SELECTIONS, createComponentBuilder, getComponentBrand, setBrandValidation, validateBrand, } from './jsx/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,13 @@ interface EntityBaseProps<TRoleMap extends Record<string, object>> {
19
19
  interface EntityByProps<TRoleMap extends Record<string, object>> extends EntityBaseProps<TRoleMap> {
20
20
  /** Unique field(s) to identify the entity (e.g., { id: '...' } or { slug: '...' }) */
21
21
  by: EntityUniqueWhere;
22
+ /**
23
+ * Cache-invalidation key. Changing this value re-fetches the entity from the
24
+ * server without unmounting the subtree (stale-while-revalidate). Use this
25
+ * instead of `key={...}` when external mutations (e.g. workflow RPC) need
26
+ * the bindx view refreshed but UI state (scroll, dialogs, drafts) must survive.
27
+ */
28
+ queryKey?: string;
22
29
  create?: never;
23
30
  onPersisted?: never;
24
31
  /** Loading fallback */
@@ -1 +1 @@
1
- {"version":3,"file":"Entity.d.ts","sourceRoot":"","sources":["../../../src/jsx/components/Entity.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuE,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAKrH,OAAO,KAAK,EAAkB,SAAS,EAAiB,MAAM,aAAa,CAAA;AAC3E,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAAiB,KAAK,UAAU,EAAgF,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAI1M;;;GAGG;AACH,UAAU,eAAe,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAChE,kCAAkC;IAClC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC3B,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;IACxE,qBAAqB;IACrB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,KAAK,CAAC,SAAS,CAAA;CAC9C;AAED;;GAEG;AACH,UAAU,aAAa,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAE,SAAQ,eAAe,CAAC,QAAQ,CAAC;IACjG,sFAAsF;IACtF,EAAE,EAAE,iBAAiB,CAAA;IACrB,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,WAAW,CAAC,EAAE,KAAK,CAAA;IACnB,uBAAuB;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED;;GAEG;AACH,UAAU,iBAAiB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAE,SAAQ,eAAe,CAAC,QAAQ,CAAC;IACrG,EAAE,CAAC,EAAE,KAAK,CAAA;IACV,8DAA8D;IAC9D,MAAM,EAAE,IAAI,CAAA;IACZ,wEAAwE;IACxE,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,OAAO,CAAC,EAAE,KAAK,CAAA;IACf,QAAQ,CAAC,EAAE,KAAK,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IACrF,aAAa,CAAC,QAAQ,CAAC,GACvB,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AA8O9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,iBAAS,UAAU,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1D,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAC1B,YAAY,GAAG,IAAI,CA0BrB;AAGD,eAAO,MAAM,MAAM,EAAkC,OAAO,UAAU,CAAA"}
1
+ {"version":3,"file":"Entity.d.ts","sourceRoot":"","sources":["../../../src/jsx/components/Entity.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuE,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAKrH,OAAO,KAAK,EAAkB,SAAS,EAAiB,MAAM,aAAa,CAAA;AAC3E,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAAiB,KAAK,UAAU,EAAgF,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAI1M;;;GAGG;AACH,UAAU,eAAe,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAChE,kCAAkC;IAClC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC3B,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;IACxE,qBAAqB;IACrB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,KAAK,CAAC,SAAS,CAAA;CAC9C;AAED;;GAEG;AACH,UAAU,aAAa,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAE,SAAQ,eAAe,CAAC,QAAQ,CAAC;IACjG,sFAAsF;IACtF,EAAE,EAAE,iBAAiB,CAAA;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,WAAW,CAAC,EAAE,KAAK,CAAA;IACnB,uBAAuB;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED;;GAEG;AACH,UAAU,iBAAiB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAE,SAAQ,eAAe,CAAC,QAAQ,CAAC;IACrG,EAAE,CAAC,EAAE,KAAK,CAAA;IACV,8DAA8D;IAC9D,MAAM,EAAE,IAAI,CAAA;IACZ,wEAAwE;IACxE,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,OAAO,CAAC,EAAE,KAAK,CAAA;IACf,QAAQ,CAAC,EAAE,KAAK,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IACrF,aAAa,CAAC,QAAQ,CAAC,GACvB,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AAsP9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,iBAAS,UAAU,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1D,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAC1B,YAAY,GAAG,IAAI,CA2BrB;AAGD,eAAO,MAAM,MAAM,EAAkC,OAAO,UAAU,CAAA"}
@@ -15,6 +15,12 @@ export interface EntityListProps<TRoleMap extends Record<string, object> = Recor
15
15
  limit?: number;
16
16
  /** Optional offset */
17
17
  offset?: number;
18
+ /**
19
+ * Cache-invalidation key. Changing this value re-fetches the list without
20
+ * unmounting the subtree (stale-while-revalidate). Use this when external
21
+ * mutations need the bindx view refreshed but UI state must survive.
22
+ */
23
+ queryKey?: string;
18
24
  /** Render function receiving typed entity accessor with direct field access */
19
25
  children: (entity: EntityAccessor<CommonEntity<TRoleMap>>, index: number) => React.ReactNode;
20
26
  /** Loading fallback */
@@ -42,7 +48,7 @@ export interface EntityListProps<TRoleMap extends Record<string, object> = Recor
42
48
  * </EntityList>
43
49
  * ```
44
50
  */
45
- declare function EntityListComponent<TRoleMap extends Record<string, object>>({ entity, filter, orderBy, limit, offset, children, loading, error: errorFallback, empty, }: EntityListProps<TRoleMap>): ReactElement | null;
51
+ declare function EntityListComponent<TRoleMap extends Record<string, object>>({ entity, filter, orderBy, limit, offset, queryKey: userQueryKey, children, loading, error: errorFallback, empty, }: EntityListProps<TRoleMap>): ReactElement | null;
46
52
  export declare const EntityList: typeof EntityListComponent;
47
53
  export {};
48
54
  //# sourceMappingURL=EntityList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/jsx/components/EntityList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAQ,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG3H,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAGjD;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAChG,kCAAkC;IAClC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC3B,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC5C,2DAA2D;IAC3D,OAAO,CAAC,EAAE,SAAS,aAAa,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAA;IAC1D,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;IAC5F,uBAAuB;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,qBAAqB;IACrB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,KAAK,CAAC,SAAS,CAAA;IAC9C,oDAAoD;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,iBAAS,mBAAmB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EACrE,MAAM,EACN,MAAM,EACN,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,KAAK,EAAE,aAAa,EACpB,KAAK,GACL,EAAE,eAAe,CAAC,QAAQ,CAAC,GAAG,YAAY,GAAG,IAAI,CAyDjD;AAGD,eAAO,MAAM,UAAU,EAA2C,OAAO,mBAAmB,CAAA"}
1
+ {"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/jsx/components/EntityList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAQ,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG3H,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAGjD;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAChG,kCAAkC;IAClC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC3B,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC5C,2DAA2D;IAC3D,OAAO,CAAC,EAAE,SAAS,aAAa,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAA;IAC1D,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;IAC5F,uBAAuB;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,qBAAqB;IACrB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,KAAK,CAAC,SAAS,CAAA;IAC9C,oDAAoD;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,iBAAS,mBAAmB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EACrE,MAAM,EACN,MAAM,EACN,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAQ,EAAE,YAAY,EACtB,QAAQ,EACR,OAAO,EACP,KAAK,EAAE,aAAa,EACpB,KAAK,GACL,EAAE,eAAe,CAAC,QAAQ,CAAC,GAAG,YAAY,GAAG,IAAI,CA8DjD;AAGD,eAAO,MAAM,UAAU,EAA2C,OAAO,mBAAmB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/bindx-react",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Type-safe React data binding framework",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -15,8 +15,8 @@
15
15
  "react": ">=18.0.0"
16
16
  },
17
17
  "dependencies": {
18
- "@contember/bindx": "0.1.37",
19
- "@contember/bindx-client": "0.1.37",
18
+ "@contember/bindx": "0.1.38",
19
+ "@contember/bindx-client": "0.1.38",
20
20
  "@contember/graphql-client": "^2.1.0-beta.1",
21
21
  "@radix-ui/primitive": "^1.1.3",
22
22
  "@radix-ui/react-slot": "^1.2.4"
@@ -1,4 +1,4 @@
1
- import { useRef, useEffect, useMemo, useCallback } from 'react'
1
+ import { useRef, useEffect, useMemo, useCallback, useState } from 'react'
2
2
  import type {
3
3
  EntityDef,
4
4
  EntityUniqueWhere,
@@ -18,7 +18,7 @@ import {
18
18
  EntityHandle,
19
19
  resolveSelectionMeta,
20
20
  buildQueryFromSelection,
21
- setEntityData,
21
+ refreshServerData,
22
22
  setLoadState,
23
23
  createLoadError,
24
24
  } from '@contember/bindx'
@@ -63,6 +63,7 @@ interface UseEntityResultBase {
63
63
  export type LoadingEntityResult = UseEntityResultBase & {
64
64
  readonly $status: 'loading'
65
65
  readonly $isLoading: true
66
+ readonly $isRefetching: false
66
67
  readonly $isError: false
67
68
  readonly $isNotFound: false
68
69
  readonly $error: null
@@ -72,6 +73,7 @@ export type LoadingEntityResult = UseEntityResultBase & {
72
73
  export type ErrorEntityResult = UseEntityResultBase & {
73
74
  readonly $status: 'error'
74
75
  readonly $isLoading: false
76
+ readonly $isRefetching: false
75
77
  readonly $isError: true
76
78
  readonly $isNotFound: false
77
79
  readonly $error: FieldError
@@ -81,6 +83,7 @@ export type ErrorEntityResult = UseEntityResultBase & {
81
83
  export type NotFoundEntityResult = UseEntityResultBase & {
82
84
  readonly $status: 'not_found'
83
85
  readonly $isLoading: false
86
+ readonly $isRefetching: false
84
87
  readonly $isError: false
85
88
  readonly $isNotFound: true
86
89
  readonly $error: null
@@ -89,11 +92,18 @@ export type NotFoundEntityResult = UseEntityResultBase & {
89
92
 
90
93
  /**
91
94
  * Ready state — full EntityAccessor with status metadata.
95
+ *
96
+ * `$isRefetching` is `true` while a background re-fetch is in flight
97
+ * (triggered by a `queryKey` change while ready data is already present).
98
+ * The accessor identity and field values remain stable until the new data
99
+ * arrives, so the subtree does not unmount — useful for stale-while-revalidate
100
+ * indicators (subtle spinner, "stale" badge, etc.).
92
101
  */
93
102
  export type ReadyEntityResult<TEntity extends object, TSelected extends object = TEntity> =
94
103
  UseEntityResultBase & EntityAccessor<TEntity, TSelected> & {
95
104
  readonly $status: 'ready'
96
105
  readonly $isLoading: false
106
+ readonly $isRefetching: boolean
97
107
  readonly $isError: false
98
108
  readonly $isNotFound: false
99
109
  readonly $error: null
@@ -236,6 +246,7 @@ export function useEntity(
236
246
 
237
247
  // --- Data loading ---
238
248
  const fetchingRef = useRef<string | null>(null)
249
+ const [isRefetching, setIsRefetching] = useState(false)
239
250
 
240
251
  useEffect(() => {
241
252
  // Check cache first
@@ -253,7 +264,17 @@ export function useEntity(
253
264
 
254
265
  const abortController = new AbortController()
255
266
 
256
- dispatcher.dispatch(setLoadState(entityType, id, 'loading'))
267
+ // Stale-while-revalidate: if we already have ready data for this entity,
268
+ // keep the ready state visible (no flicker) and only flag a background refetch.
269
+ // Otherwise, fall back to the explicit loading state.
270
+ const existing = store.getLoadState(entityType, id)
271
+ const haveReadyData = existing?.status === 'success' && store.hasEntity(entityType, id)
272
+
273
+ if (haveReadyData) {
274
+ setIsRefetching(true)
275
+ } else {
276
+ dispatcher.dispatch(setLoadState(entityType, id, 'loading'))
277
+ }
257
278
 
258
279
  const fetchData = async (): Promise<void> => {
259
280
  try {
@@ -269,8 +290,10 @@ export function useEntity(
269
290
  if (result.type === 'get' && result.data === null) {
270
291
  dispatcher.dispatch(setLoadState(entityType, id, 'not_found'))
271
292
  } else if (result.type === 'get' && result.data) {
293
+ // Revalidation: advance the server baseline but keep local dirty
294
+ // edits intact (see EntitySnapshotStore.refreshServerData).
272
295
  dispatcher.dispatch(
273
- setEntityData(entityType, id, result.data, true),
296
+ refreshServerData(entityType, id, result.data),
274
297
  )
275
298
  dispatcher.dispatch(setLoadState(entityType, id, 'success'))
276
299
  }
@@ -282,6 +305,10 @@ export function useEntity(
282
305
  dispatcher.dispatch(
283
306
  setLoadState(entityType, id, 'error', createLoadError(normalizedError)),
284
307
  )
308
+ } finally {
309
+ if (!abortController.signal.aborted) {
310
+ setIsRefetching(false)
311
+ }
285
312
  }
286
313
  }
287
314
 
@@ -324,20 +351,20 @@ export function useEntity(
324
351
  // --- Build result ---
325
352
  const result = useMemo((): UseEntityResult<object, object> => {
326
353
  if (!loadState || loadState.status === 'loading' || (!snapshot && loadState.status === 'success')) {
327
- return { $status: 'loading', $isLoading: true, $isError: false, $isNotFound: false, $error: null, id, $persist: persist, $reset: reset }
354
+ return { $status: 'loading', $isLoading: true, $isRefetching: false, $isError: false, $isNotFound: false, $error: null, id, $persist: persist, $reset: reset }
328
355
  }
329
356
 
330
357
  if (loadState.status === 'error') {
331
- return { $status: 'error', $isLoading: false, $isError: true, $isNotFound: false, $error: loadState.error!, id, $persist: persist, $reset: reset }
358
+ return { $status: 'error', $isLoading: false, $isRefetching: false, $isError: true, $isNotFound: false, $error: loadState.error!, id, $persist: persist, $reset: reset }
332
359
  }
333
360
 
334
361
  if (loadState.status === 'not_found') {
335
- return { $status: 'not_found', $isLoading: false, $isError: false, $isNotFound: true, $error: null, id, $persist: persist, $reset: reset }
362
+ return { $status: 'not_found', $isLoading: false, $isRefetching: false, $isError: false, $isNotFound: true, $error: null, id, $persist: persist, $reset: reset }
336
363
  }
337
364
 
338
365
  // Ready — layer status metadata on top of EntityHandle proxy
339
- return createReadyResult(handle, persist, reset)
340
- }, [snapshot, loadState, isPersisting, id, handle, persist, reset])
366
+ return createReadyResult(handle, persist, reset, isRefetching)
367
+ }, [snapshot, loadState, isPersisting, id, handle, persist, reset, isRefetching])
341
368
 
342
369
  // Proxy-based result satisfies the full UseEntityResult<T> at runtime via field access delegation
343
370
  return result as UseEntityResult<any, any>
@@ -351,10 +378,12 @@ function createReadyResult(
351
378
  handle: EntityAccessor<object, object>,
352
379
  persist: () => Promise<void>,
353
380
  reset: () => void,
381
+ isRefetching: boolean,
354
382
  ): UseEntityResult<object, object> {
355
383
  const meta: Record<string, unknown> = {
356
384
  $status: 'ready' as const,
357
385
  $isLoading: false as const,
386
+ $isRefetching: isRefetching,
358
387
  $isError: false as const,
359
388
  $isNotFound: false as const,
360
389
  $error: null,
@@ -1,6 +1,6 @@
1
1
  import { useRef, useEffect, useMemo, useCallback } from 'react'
2
2
  import type { EntityDef, EntityAccessor, SelectionInput, SelectionMeta, FieldError, SchemaRegistry, CommonEntity, EntityForRoles, RoleNames } from '@contember/bindx'
3
- import { EntityHandle, isTempId, resolveSelectionMeta, buildQueryFromSelection, setEntityData, createLoadError } from '@contember/bindx'
3
+ import { EntityHandle, isTempId, resolveSelectionMeta, buildQueryFromSelection, refreshServerData, createLoadError } from '@contember/bindx'
4
4
  import { useBindxContext, useSchemaRegistry } from './BackendAdapterContext.js'
5
5
  import { useStoreSubscription } from './useStoreSubscription.js'
6
6
 
@@ -43,6 +43,7 @@ interface EntityListResultBase {
43
43
  export type LoadingEntityListResult = EntityListResultBase & {
44
44
  readonly $status: 'loading'
45
45
  readonly $isLoading: true
46
+ readonly $isRefetching: false
46
47
  readonly $isError: false
47
48
  readonly $error: null
48
49
  }
@@ -50,13 +51,21 @@ export type LoadingEntityListResult = EntityListResultBase & {
50
51
  export type ErrorEntityListResult = EntityListResultBase & {
51
52
  readonly $status: 'error'
52
53
  readonly $isLoading: false
54
+ readonly $isRefetching: false
53
55
  readonly $isError: true
54
56
  readonly $error: FieldError
55
57
  }
56
58
 
59
+ /**
60
+ * `$isRefetching` is `true` while a background re-fetch is in flight
61
+ * (triggered by a `queryKey` change while ready data is already present).
62
+ * The accessor identity stays stable so the subtree does not unmount —
63
+ * stale-while-revalidate semantics.
64
+ */
57
65
  export type ReadyEntityListResult<T extends object> = EntityListResultBase & {
58
66
  readonly $status: 'ready'
59
67
  readonly $isLoading: false
68
+ readonly $isRefetching: boolean
60
69
  readonly $isError: false
61
70
  readonly $error: null
62
71
  readonly $isDirty: boolean
@@ -77,6 +86,7 @@ function createLoadingListResult(): LoadingEntityListResult {
77
86
  return {
78
87
  $status: 'loading',
79
88
  $isLoading: true,
89
+ $isRefetching: false,
80
90
  $isError: false,
81
91
  $error: null,
82
92
  $add() { throw new Error('Cannot add items while loading') },
@@ -89,6 +99,7 @@ function createErrorListResult(error: FieldError): ErrorEntityListResult {
89
99
  return {
90
100
  $status: 'error',
91
101
  $isLoading: false,
102
+ $isRefetching: false,
92
103
  $isError: true,
93
104
  $error: error,
94
105
  $add() { throw new Error('Cannot add items after error') },
@@ -199,9 +210,11 @@ export function useEntityList(
199
210
  status: 'loading' | 'error' | 'ready'
200
211
  items: Array<{ id: string; data: object }>
201
212
  error?: FieldError
213
+ isRefetching: boolean
202
214
  }>({
203
215
  status: 'loading',
204
216
  items: [],
217
+ isRefetching: false,
205
218
  })
206
219
 
207
220
  const versionRef = useRef(0)
@@ -210,6 +223,7 @@ export function useEntityList(
210
223
  version: number
211
224
  storeVersion: number
212
225
  status: string
226
+ isRefetching: boolean
213
227
  result: UseEntityListResult<any>
214
228
  } | null>(null)
215
229
 
@@ -276,7 +290,13 @@ export function useEntityList(
276
290
  const storeVersion = store.getVersion()
277
291
 
278
292
  const cache = listCacheRef.current
279
- if (cache && cache.version === version && cache.storeVersion === storeVersion && cache.status === state.status) {
293
+ if (
294
+ cache &&
295
+ cache.version === version &&
296
+ cache.storeVersion === storeVersion &&
297
+ cache.status === state.status &&
298
+ cache.isRefetching === state.isRefetching
299
+ ) {
280
300
  return cache.result
281
301
  }
282
302
 
@@ -300,6 +320,7 @@ export function useEntityList(
300
320
  result = {
301
321
  $status: 'ready',
302
322
  $isLoading: false,
323
+ $isRefetching: state.isRefetching,
303
324
  $isError: false,
304
325
  $error: null,
305
326
  $isDirty: false,
@@ -315,6 +336,7 @@ export function useEntityList(
315
336
  version,
316
337
  storeVersion,
317
338
  status: state.status,
339
+ isRefetching: state.isRefetching,
318
340
  result,
319
341
  }
320
342
 
@@ -338,8 +360,16 @@ export function useEntityList(
338
360
  useEffect(() => {
339
361
  const abortController = new AbortController()
340
362
 
341
- listStateRef.current = { status: 'loading', items: [] }
363
+ // Stale-while-revalidate: if we already have ready items, keep them visible
364
+ // and only flag a background refetch. Otherwise, show explicit loading.
365
+ const prev = listStateRef.current
366
+ if (prev.status === 'ready') {
367
+ listStateRef.current = { ...prev, isRefetching: true }
368
+ } else {
369
+ listStateRef.current = { status: 'loading', items: [], isRefetching: false }
370
+ }
342
371
  versionRef.current++
372
+ store.notify()
343
373
 
344
374
  const fetchData = async (): Promise<void> => {
345
375
  try {
@@ -371,13 +401,15 @@ export function useEntityList(
371
401
 
372
402
  const items = result.data.map((data: Record<string, unknown>) => {
373
403
  const id = data['id'] as string
404
+ // Revalidation: advance the server baseline but keep local dirty
405
+ // edits intact (see EntitySnapshotStore.refreshServerData).
374
406
  dispatcher.dispatch(
375
- setEntityData(entityType, id, data, true),
407
+ refreshServerData(entityType, id, data),
376
408
  )
377
409
  return { id, data: data as object }
378
410
  })
379
411
 
380
- listStateRef.current = { status: 'ready', items }
412
+ listStateRef.current = { status: 'ready', items, isRefetching: false }
381
413
  versionRef.current++
382
414
  store.notify()
383
415
  } catch (error) {
@@ -388,6 +420,7 @@ export function useEntityList(
388
420
  status: 'error',
389
421
  items: [],
390
422
  error: createLoadError(normalizedError),
423
+ isRefetching: false,
391
424
  }
392
425
  versionRef.current++
393
426
  store.notify()
package/src/index.ts CHANGED
@@ -302,6 +302,7 @@ export {
302
302
  useIntercept,
303
303
  useInterceptEntity,
304
304
  useInterceptField,
305
+ useEntityBeforePersist,
305
306
  // Ref → Accessor hooks
306
307
  useAccessor,
307
308
  useField,
@@ -27,6 +27,13 @@ interface EntityBaseProps<TRoleMap extends Record<string, object>> {
27
27
  interface EntityByProps<TRoleMap extends Record<string, object>> extends EntityBaseProps<TRoleMap> {
28
28
  /** Unique field(s) to identify the entity (e.g., { id: '...' } or { slug: '...' }) */
29
29
  by: EntityUniqueWhere
30
+ /**
31
+ * Cache-invalidation key. Changing this value re-fetches the entity from the
32
+ * server without unmounting the subtree (stale-while-revalidate). Use this
33
+ * instead of `key={...}` when external mutations (e.g. workflow RPC) need
34
+ * the bindx view refreshed but UI state (scroll, dialogs, drafts) must survive.
35
+ */
36
+ queryKey?: string
30
37
  create?: never
31
38
  onPersisted?: never
32
39
  /** Loading fallback */
@@ -60,6 +67,7 @@ export type EntityProps<TRoleMap extends Record<string, object> = Record<string,
60
67
  interface EntityByModeProps {
61
68
  entityType: string
62
69
  by: EntityUniqueWhere
70
+ queryKey?: string
63
71
  children: (entity: EntityAccessor<unknown>) => React.ReactNode
64
72
  loading?: React.ReactNode
65
73
  error?: (error: FieldError) => React.ReactNode
@@ -81,6 +89,7 @@ interface EntityCreateModeProps {
81
89
  function EntityByMode({
82
90
  entityType,
83
91
  by,
92
+ queryKey: userQueryKey,
84
93
  children,
85
94
  loading,
86
95
  error: errorFallback,
@@ -93,17 +102,23 @@ function EntityByMode({
93
102
  const byKey = useMemo(() => JSON.stringify(by), [by])
94
103
 
95
104
  // Phase 1: Collect JSX selection
96
- const { selection, queryKey } = useSelectionCollection({
105
+ const { selection, queryKey: selectionQueryKey } = useSelectionCollection({
97
106
  entityType,
98
107
  depsKey: byKey,
99
108
  collect: collector => children(collector as EntityAccessor<unknown>),
100
109
  })
101
110
 
111
+ // Combine internal selection key with user-supplied invalidation key so
112
+ // both selection changes and explicit refreshes trigger a refetch.
113
+ const effectiveQueryKey = userQueryKey !== undefined
114
+ ? `${selectionQueryKey}::${userQueryKey}`
115
+ : selectionQueryKey
116
+
102
117
  // Phase 2: Load data using unified hook
103
118
  const result = useEntity({ $name: entityType } as EntityDef, {
104
119
  by,
105
120
  selection,
106
- queryKey,
121
+ queryKey: effectiveQueryKey,
107
122
  })
108
123
 
109
124
  // Render based on status
@@ -347,6 +362,7 @@ function EntityImpl<TRoleMap extends Record<string, object>>(
347
362
  <EntityByMode
348
363
  entityType={byProps.entity.$name}
349
364
  by={byProps.by}
365
+ queryKey={byProps.queryKey}
350
366
  children={byProps.children as (entity: EntityAccessor<unknown>) => React.ReactNode}
351
367
  loading={byProps.loading}
352
368
  error={byProps.error}
@@ -19,6 +19,12 @@ export interface EntityListProps<TRoleMap extends Record<string, object> = Recor
19
19
  limit?: number
20
20
  /** Optional offset */
21
21
  offset?: number
22
+ /**
23
+ * Cache-invalidation key. Changing this value re-fetches the list without
24
+ * unmounting the subtree (stale-while-revalidate). Use this when external
25
+ * mutations need the bindx view refreshed but UI state must survive.
26
+ */
27
+ queryKey?: string
22
28
  /** Render function receiving typed entity accessor with direct field access */
23
29
  children: (entity: EntityAccessor<CommonEntity<TRoleMap>>, index: number) => React.ReactNode
24
30
  /** Loading fallback */
@@ -53,6 +59,7 @@ function EntityListComponent<TRoleMap extends Record<string, object>>({
53
59
  orderBy,
54
60
  limit,
55
61
  offset,
62
+ queryKey: userQueryKey,
56
63
  children,
57
64
  loading,
58
65
  error: errorFallback,
@@ -69,13 +76,18 @@ function EntityListComponent<TRoleMap extends Record<string, object>>({
69
76
  })
70
77
 
71
78
  // Phase 1: Collect JSX selection
72
- const { selection, queryKey } = useSelectionCollection({
79
+ const { selection, queryKey: selectionQueryKey } = useSelectionCollection({
73
80
  entityType,
74
81
  depsKey: optionsKey,
75
82
  collect: collector => children(collector as unknown as EntityAccessor<CommonEntity<TRoleMap>>, 0),
76
83
  queryKeyExtra: { filter, orderBy, limit, offset },
77
84
  })
78
85
 
86
+ // Combine internal selection key with user-supplied invalidation key
87
+ const effectiveQueryKey = userQueryKey !== undefined
88
+ ? `${selectionQueryKey}::${userQueryKey}`
89
+ : selectionQueryKey
90
+
79
91
  // Phase 2: Load data using unified hook
80
92
  const result = useEntityList(entity, {
81
93
  filter,
@@ -83,7 +95,7 @@ function EntityListComponent<TRoleMap extends Record<string, object>>({
83
95
  limit,
84
96
  offset,
85
97
  selection,
86
- queryKey,
98
+ queryKey: effectiveQueryKey,
87
99
  })
88
100
 
89
101
  // Render based on status