Skip to content

Commit d474f8c

Browse files
authored
Remove getOperation function in children props (#152)
* Remove getOperation function * Fix conflict * Fix exmaple app * Add a changeset * Remove TData * Modified changeset
1 parent fda8492 commit d474f8c

File tree

6 files changed

+66
-167
lines changed

6 files changed

+66
-167
lines changed

.changeset/quick-teachers-melt.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@fabrix-framework/fabrix": minor
3+
---
4+
5+
Remove `getOperation` function from children props in FabrixComponent.
6+
7+
Now `query` prop in `FabrixComponent` supports only a single query to get it future compatible with TypedDocumentNode.

examples/vite-todoapp/src/App.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ function App() {
3232
id
3333
}
3434
}
35-
35+
`}
36+
/>
37+
<FabrixComponent
38+
containerClassName={containerClassName}
39+
query={gql`
3640
query todos {
3741
allTodos
3842
@fabrixView(

packages/fabrix/__tests__/componentRegistry.test.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ describe("getFabrixComponent", () => {
136136
title: "Custom Table",
137137
}}
138138
query={gql`
139-
query getUsers {
139+
query {
140140
users {
141141
collection {
142142
id
@@ -149,9 +149,7 @@ describe("getFabrixComponent", () => {
149149
>
150150
{({ getComponent }) => {
151151
return (
152-
<div data-testid="component-wrapper">
153-
{getComponent("getUsers", "users")}
154-
</div>
152+
<div data-testid="component-wrapper">{getComponent("users")}</div>
155153
);
156154
}}
157155
</CustomTable>,

packages/fabrix/__tests__/query.test.tsx

+14-18
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,10 @@ describe("collection", () => {
8484
const testPatterns = [
8585
["collection", collectionQuery, undefined],
8686
["edges", edgeQuery, undefined],
87-
[
88-
"getOperation",
89-
collectionQuery,
90-
({ getOperation }) => getOperation("getUsers"),
91-
],
92-
[
93-
"getOperation/getComponent",
94-
collectionQuery,
95-
({ getOperation }) =>
96-
getOperation("getUsers", ({ getComponent }) => getComponent("users")),
97-
],
9887
[
9988
"getComponent",
10089
collectionQuery,
101-
({ getComponent }) => getComponent("getUsers", "users"),
90+
({ getComponent }) => getComponent("users"),
10291
],
10392
] satisfies [string, string, FabrixComponentChildrenProps][];
10493

@@ -236,12 +225,19 @@ describe("collection", () => {
236225

237226
it("should be able to access the response data for by an operation", async () => {
238227
await testWithUnmount(
239-
<FabrixComponent query={`query getUsers { users { size } }`}>
240-
{({ getOperation }) =>
241-
getOperation<{ users: { size: number } }>("getUsers", ({ data }) => (
242-
<div role="result-size">{data.users.size}</div>
243-
))
244-
}
228+
<FabrixComponent
229+
query={`
230+
query getUsers {
231+
users {
232+
size
233+
}
234+
}
235+
`}
236+
>
237+
{({ data }) => (
238+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
239+
<div role="result-size">{data.users.size}</div>
240+
)}
245241
</FabrixComponent>,
246242
async () => {
247243
const result = await screen.findByRole("result-size");

packages/fabrix/src/fetcher.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import { useClient, useQuery } from "urql";
44
export const useDataFetch = (props: {
55
query: DocumentNode | string;
66
variables?: Record<string, unknown>;
7+
pause?: boolean;
78
}) => {
89
const [{ data, fetching, error }] = useQuery<FabrixComponentData>({
9-
query: props.query,
10-
variables: props.variables,
10+
...props,
1111
});
1212

1313
return {

packages/fabrix/src/renderer.tsx

+36-142
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DirectiveNode, DocumentNode, OperationTypeNode, parse } from "graphql";
2-
import { ReactNode, useCallback, useContext, useMemo } from "react";
2+
import { ReactNode, useContext, useMemo } from "react";
33
import { findDirective, parseDirectiveArguments } from "@directive";
44
import { ViewRenderer } from "@renderers/fields";
55
import { FormRenderer } from "@renderers/form";
@@ -185,57 +185,25 @@ export type FabrixComponentProps = FabrixComponentCommonProps & {
185185

186186
type FabrixComponentChildrenExtraProps = { key?: string; className?: string };
187187

188-
type FabrixGetComponentFn = (
189-
/**
190-
* The name that corresponds to the GQL query.
191-
*/
192-
name: string,
193-
extraProps?: FabrixComponentChildrenExtraProps,
194-
fieldsRenderer?: FabrixComponentFieldsRenderer,
195-
) => ReactNode;
196-
197-
export type FabrixGetOperationFn = <
198-
T extends Record<string, unknown> = Record<string, unknown>,
199-
>(
200-
indexOrName: number | string,
201-
renderer?: (props: {
202-
data: T;
203-
getComponent: FabrixGetComponentFn;
204-
}) => ReactNode,
205-
) => ReactNode;
206-
207188
export type FabrixComponentChildrenProps = {
208189
/**
209-
* Get the operation result by operation name or index
210-
*
211-
* ```tsx
212-
* <FabrixComponent query={getUsersQuery}>
213-
* {({ getOperation }) => (
214-
* {getOperation("getUsers", ({ data, getComponent }) => (
215-
* <>
216-
* <h2>{data.users.size} users</h2>
217-
* {getComponent("users")}
218-
* </>
219-
* ))}
220-
* )}
221-
* </FabrixComponent>
222-
* ```
190+
* The data fetched from the query
223191
*/
224-
getOperation: FabrixGetOperationFn;
192+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
193+
data: any;
225194

226195
/**
227196
* Get the component by root field name
228197
*
229198
* ```tsx
230199
* <FabrixComponent query={getUsersQuery}>
231200
* {({ getComponent }) => (
232-
* {getComponent("getUsers", "users")}
201+
* {getComponent("users")}
233202
* )}
234203
* </FabrixComponent>
235204
* ```
236205
*/
237206
getComponent: (
238-
operationIndexOrName: number | string,
239207
rootFieldName: string,
240208
extraProps?: FabrixComponentChildrenExtraProps,
241209
fieldsRenderer?: FabrixComponentFieldsRenderer,
@@ -306,48 +274,41 @@ export const getComponentRendererFn = (
306274
props: FabrixComponentProps,
307275
getComponent: ReturnType<typeof getComponentFn>,
308276
) => {
277+
const context = useContext(FabrixContext);
309278
const { fieldConfigs } = useFieldConfigs(props.query);
310-
const getOperation: FabrixComponentChildrenProps["getOperation"] =
311-
useCallback(
312-
(indexOrName, renderer) => {
313-
const fieldConfig =
314-
typeof indexOrName === "number"
315-
? fieldConfigs[indexOrName]
316-
: fieldConfigs.find(({ name }) => name == indexOrName);
317-
if (!fieldConfig) {
318-
throw new Error(`No operation found for indexOrName: ${indexOrName}`);
319-
}
320-
321-
return (
322-
<OperationRenderer
323-
key={`fabrix-operation${typeof indexOrName === "number" ? `-${indexOrName}` : ""}-${fieldConfig.name}`}
324-
operation={fieldConfig}
325-
variables={props.variables}
326-
getComponentFn={getComponent}
327-
renderer={renderer as Parameters<FabrixGetOperationFn>[1]}
328-
/>
329-
);
330-
},
331-
[fieldConfigs, props.variables],
332-
);
279+
const fieldConfig = fieldConfigs[0];
280+
if (!fieldConfig) {
281+
throw new Error(`No operation found`);
282+
}
333283

334284
return () => {
285+
const { fetching, error, data } = useDataFetch({
286+
query: fieldConfig.document,
287+
variables: props.variables,
288+
pause: fieldConfig.type !== OperationTypeNode.QUERY,
289+
});
290+
291+
if (fetching) {
292+
return <Loader />;
293+
}
294+
295+
if (error) {
296+
throw error;
297+
}
298+
299+
const component = getComponent(fieldConfig, data, context);
335300
if (props.children) {
336301
return props.children({
337-
getOperation,
338-
getComponent: (
339-
operationIndexOrName,
340-
rootFieldName,
341-
extraProps,
342-
fieldsRenderer,
343-
) =>
344-
getOperation(operationIndexOrName, ({ getComponent }) =>
345-
getComponent(rootFieldName, extraProps, fieldsRenderer),
346-
),
302+
data,
303+
getComponent: component,
347304
});
348305
}
349306

350-
return fieldConfigs.map((_, i) => getOperation(i));
307+
return fieldConfig.fields.map((field) =>
308+
component(field.name, {
309+
key: `fabrix-${fieldConfig.name}-${field.name}`,
310+
}),
311+
);
351312
};
352313
};
353314

@@ -362,7 +323,7 @@ export const getComponentFn =
362323
(props: FabrixComponentProps, rendererFn: RendererFn) =>
363324
(
364325
fieldConfig: FieldConfigs,
365-
data: FabrixComponentData,
326+
data: FabrixComponentData | undefined,
366327
context: FabrixContextType,
367328
) =>
368329
(
@@ -375,81 +336,14 @@ export const getComponentFn =
375336
throw new Error(`No root field found for name: ${name}`);
376337
}
377338

339+
const dataByName = data ? (name in data ? data[name] : {}) : {};
340+
378341
return (
379342
<div
380343
key={extraProps?.key}
381344
className={`fabrix renderer container ${props.containerClassName ?? ""} ${extraProps?.className ?? ""}`}
382345
>
383-
{rendererFn(field, data[name], context, componentFieldsRenderer)}
346+
{rendererFn(field, dataByName, context, componentFieldsRenderer)}
384347
</div>
385348
);
386349
};
387-
388-
type GetComponentFn = (
389-
op: FieldConfigs,
390-
data: FabrixComponentData,
391-
context: FabrixContextType,
392-
) => FabrixGetComponentFn;
393-
394-
type RendererCommonProps = {
395-
key: string;
396-
operation: FieldConfigs;
397-
variables: Record<string, unknown> | undefined;
398-
renderer?: Parameters<FabrixGetOperationFn>[1];
399-
getComponentFn: GetComponentFn;
400-
extraClassName?: string;
401-
};
402-
403-
const OperationRenderer = (props: RendererCommonProps) => {
404-
return props.operation.type === OperationTypeNode.MUTATION ? (
405-
<MutateOperationRenderer {...props} />
406-
) : (
407-
<QueryOperationRenderer {...props} />
408-
);
409-
};
410-
411-
const QueryOperationRenderer = ({
412-
operation,
413-
variables,
414-
renderer,
415-
getComponentFn,
416-
}: RendererCommonProps) => {
417-
const context = useContext(FabrixContext);
418-
const { fetching, error, data } = useDataFetch({
419-
query: operation.document,
420-
variables,
421-
});
422-
423-
if (fetching || !data) {
424-
return <Loader />;
425-
}
426-
427-
if (error) {
428-
throw error;
429-
}
430-
431-
const getComponent = getComponentFn(operation, data, context);
432-
return renderer
433-
? renderer({ data, getComponent })
434-
: operation.fields.map((field) =>
435-
getComponent(field.name, {
436-
key: `fabrix-query-${operation.name}-${field.name}`,
437-
}),
438-
);
439-
};
440-
441-
const MutateOperationRenderer = ({
442-
operation,
443-
renderer,
444-
getComponentFn,
445-
}: RendererCommonProps) => {
446-
const context = useContext(FabrixContext);
447-
const getComponent = getComponentFn(operation, {}, context);
448-
return renderer
449-
? renderer({ data: {}, getComponent })
450-
: operation.fields.map((field) =>
451-
getComponent(field.name, {
452-
key: `fabrix-mutation-${operation.name}-${field.name}`,
453-
}),
454-
);
455-
};

0 commit comments

Comments
 (0)