Releases: fabrix-framework/fabrix
@fabrix-framework/unstyled@0.1.1
@fabrix-framework/graphql-config@0.4.1
@fabrix-framework/fabrix@0.7.0
Minor Changes
-
#166
d433fe0Thanks @IzumiSy! - Support constraints for nested object field in fabrixForm directive API -
#155
b577afaThanks @IzumiSy! - This update contains the breaking changes specifically on functions that the children prop inFabrixComponentpasses down to bring more flexibility in rendering the view.See #168 for more about the motivation about this change.
Input and Output
The newly introduced functions in the children prop is
getInputandgetOutput.getInputis a function that plays a role as a form renderer, and also an accessor of the form context and form field control. Input fields are inferred from variable definitions in the corresponding GraphQL operation.getOutputis a function that works as a result renderer (the behaviour of it depends on the component registered in the component registry), and also a direct accessor of the query data. Output fields are inferred from selected fields in the corresponding GraphQL operation.
Here is the example implementation that renders the form to get the search condition for
Queryoperation alongside the result component like tables.<FabrixComponent query={gql` query getTodos($input: GetTodoInput!) { getTodos(input: $input) { edges { node { name priority } } } } `} > {({ getInput, getOutput }) => ( <> {/* * `getInput` renders the all form fields inferred from the variables * The rendered view by `getInput` without render props also has the button to execute the query. */} {getInput()} {/* * `getOuput` renders the result of the mutation * This example assumes that `getTodos` is rendered as a table component. */} {getOutput("getTodos")} </> )} </FabrixComponent>
The important point to mention is that
getOutputandgetInputwork in the same way both forQueryandMutationby this update.dataaccessorWith this update,
dataaccessor is accessible throughgetOuputfunction, since the data is tied from the query result (output).<FabrixComponent query={gql` query getTodo { getTodo { name priority } } `} > {({ getOutput }) => getOutput("getTodo", ({ data }) => <div>Todo name: {data.name}</div>) } </FabrixComponent>
More customizable, layoutable form
Here is the complex example to create an update form to show the customizability and layoutability.
<FabrixComponent query={gql` mutation updateTodo($id: ID!, $input: CreateTodoInput!) { updateTodo(id: $id, input: $input) { id } } `} > {({ getInput }) => /* * `getInput` is a function to render form view which can acess functions to build forms. * `Field` and `getAction` are the key functions (see their explanation below) */ getInput({ /* * If the form is the one to update resource, set `defaultValues` here to prefill the form fields. * The data structure should be matched with the variables of query/mutation. */ defaultValues: { id: "user-id", input: { name: "John Doe" } } }, ({ Field, getAction }) => ( {/* * `getAction` is expcted to be passed as an descructive props to `form` element. * It is an object that contains `onSubmit` function as a member that kicks off the query execution. */} <form {...getAction()}> {/* * `Field` is a React component that renders the form field that autotimacally deciding * the corresponding component according to GraphQL type for the path specified in the `name` prop. * * `extraProps` is the prop to carry information to the form field. * In this example, I assume the component that is registered in the component registry * as the form field handles `label` to show it as a text content in the `label` element. * * The props for the `extraProps` should have more variety (e.g., `disabled`, `placeholder`, ...), * but I will work on adding them in other PRs later on. */} <HStack> <Field name="input.name" extraProps={{ label: "Task Name" }} /> <Field name="input.priority" extraProps={{ label: "Task Priority" }} /> </HStack> <Button type="submit">Add</Button> </form> )) } </FabrixComponent>
Additionally, for more page-by-page customization for the form,
getInputfunctions offers more functions in its render props, mostly powered by react-hook-form that fabrix internal uses.Field-level handler
In the case that the field component automatially decided by GraphQL type does not fit the requirement in the form,
getInputfunction provides the another customizable point at the field level in the form.getFieldfunction returns the value ofUseFormRegisterReturnin react-hook-form. Users would be able to use the another input component on the spot with this.<FabrixComponent query={`/* ... */`}> {({ getInput }) => getInput({}, ({ Field, getAction, getField }) => { <form {...getAction()}> <Field name="input.name" /> <Field name="input.priority" /> <input {...getField("input.email")} type="text" /> </form>; }) } </FabrixComponent>
Form context
The render props of
getInputfunction also passes downformContextthat is the react-hook-form context that the form rendered bygetInputinternally maintains.This helps users create the flexible form-wide funcionality as they want by lerveraging the functionality of react-hook-form like inter-field interactibity.
import { UseFormReturn } from "react-hook-form"; const Page = () => ( <FabrixComponent query={`/* ... */`}> {({ getInput }) => getInput({}, ({ getAction, formContext }) => { <form {...getAction()}> <WatchingField formContext={formContext} /> </form>; }) } </FabrixComponent> ); const WatchingField = (props: { formContext: UseFormReturn }) => { /* * Watches the value on the form field using `watch` method in the form context of react-hook-form */ const status = formContext.watch("input.priority"); };
Backward incompatibility
The previous behaviour of
FabrixComponentis that only the component for the result was rendered inQueryand only the form forMutationon the contrary.
However, from this relelase,FabrixComponentwill render both the form and the result of the component regardless of operation type.If you would like to maintain the previous behaviour, use directives to guide the query render only the specific component that you want.
/* * `@fabrixForm` directive does not */ <FabrixComponent query={gql` mutation updateTodo($id: ID!, $input: CreateTodoInput!) { updateTodo(id: $id, input: $input) @fabrixForm { id } } `} />
fabrixViewalso works forQueryoperation in the same way.
Patch Changes
@fabrix-framework/chakra-ui@0.6.1
@fabrix-framework/fabrix@0.6.0
@fabrix-framework/chakra-ui@0.6.0
@fabrix-framework/graphql-config@0.4.0
@fabrix-framework/fabrix@0.5.0
Minor Changes
-
#153
7c104b0Thanks @IzumiSy! - AddTypedDocumentNodesupport: now when theTypedDocumentNodequery is given,dataandvariablesare typed.Also,
getComponenthas the first argument that is typed to help users select the component associated to the query. -
#152
d474f8cThanks @IzumiSy! - RemovegetOperationfunction from children props in FabrixComponent.Now
queryprop inFabrixComponentsupports only a single query to get it future compatible with TypedDocumentNode.