Skip to content
This repository was archived by the owner on Dec 25, 2025. It is now read-only.

Commit 8add9ba

Browse files
authored
Merge branch 'main' into add_date_field_in_example
2 parents e2739f8 + b577afa commit 8add9ba

42 files changed

Lines changed: 1977 additions & 730 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@fabrix-framework/chakra-ui": patch
3+
"@fabrix-framework/fabrix": patch
4+
"@fabrix-framework/graphql-config": patch
5+
---
6+
7+
Use turbo cache on CI

.changeset/dirty-snakes-own.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"@fabrix-framework/unstyled": minor
3+
---
4+
5+
Introduced unstyled component package
6+
7+
Supported GraphQL types are as follows:
8+
9+
* String
10+
* Int
11+
* Float
12+
* Boolean
13+
* Date
14+
* DateTime
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@fabrix-framework/chakra-ui": patch
3+
"@fabrix-framework/fabrix": patch
4+
"@fabrix-framework/graphql-config": patch
5+
---
6+
7+
Add path to GitHub Actions' trigger.

.changeset/lemon-seas-trade.md

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
---
2+
"@fabrix-framework/fabrix": minor
3+
---
4+
5+
This update contains the breaking changes specifically on functions that the children prop in `FabrixComponent` passes down to bring more flexibility in rendering the view.
6+
7+
See [#168](https://github.com/fabrix-framework/fabrix/issues/168) for more about the motivation about this change.
8+
9+
## Input and Output
10+
11+
The newly introduced functions in the children prop is `getInput` and `getOutput`.
12+
13+
* `getInput` is 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.
14+
* `getOutput` is 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.
15+
16+
Here is the example implementation that renders the form to get the search condition for `Query` operation alongside the result component like tables.
17+
18+
```tsx
19+
<FabrixComponent
20+
query={gql`
21+
query getTodos($input: GetTodoInput!) {
22+
getTodos(input: $input) {
23+
edges {
24+
node {
25+
name
26+
priority
27+
}
28+
}
29+
}
30+
}
31+
`}
32+
>
33+
{({ getInput, getOutput }) => (
34+
<>
35+
{/*
36+
* `getInput` renders the all form fields inferred from the variables
37+
* The rendered view by `getInput` without render props also has the button to execute the query.
38+
*/}
39+
{getInput()}
40+
41+
{/*
42+
* `getOuput` renders the result of the mutation
43+
* This example assumes that `getTodos` is rendered as a table component.
44+
*/}
45+
{getOutput("getTodos")}
46+
</>
47+
)}
48+
</FabrixComponent>
49+
```
50+
51+
The important point to mention is that `getOutput` and `getInput` work in the same way both for `Query` and `Mutation` by this update.
52+
53+
### `data` accessor
54+
55+
With this update, `data` accessor is accessible through `getOuput` function, since the data is tied from the query result (output).
56+
57+
```tsx
58+
<FabrixComponent
59+
query={gql`
60+
query getTodo {
61+
getTodo {
62+
name
63+
priority
64+
}
65+
}
66+
`}
67+
>
68+
{({ getOutput }) =>
69+
getOutput("getTodo", ({ data }) => (
70+
<div>Todo name: {data.name}</div>
71+
))
72+
}
73+
</FabrixComponent>
74+
```
75+
76+
## More customizable, layoutable form
77+
78+
Here is the complex example to create an update form to show the customizability and layoutability.
79+
80+
```tsx
81+
<FabrixComponent
82+
query={gql`
83+
mutation updateTodo($id: ID!, $input: CreateTodoInput!) {
84+
updateTodo(id: $id, input: $input) {
85+
id
86+
}
87+
}
88+
`}
89+
>
90+
{({ getInput }) =>
91+
/*
92+
* `getInput` is a function to render form view which can acess functions to build forms.
93+
* `Field` and `getAction` are the key functions (see their explanation below)
94+
*/
95+
getInput({
96+
/*
97+
* If the form is the one to update resource, set `defaultValues` here to prefill the form fields.
98+
* The data structure should be matched with the variables of query/mutation.
99+
*/
100+
defaultValues: {
101+
id: "user-id",
102+
input: {
103+
name: "John Doe"
104+
}
105+
}
106+
}, ({ Field, getAction }) => (
107+
{/*
108+
* `getAction` is expcted to be passed as an descructive props to `form` element.
109+
* It is an object that contains `onSubmit` function as a member that kicks off the query execution.
110+
*/}
111+
<form {...getAction()}>
112+
{/*
113+
* `Field` is a React component that renders the form field that autotimacally deciding
114+
* the corresponding component according to GraphQL type for the path specified in the `name` prop.
115+
*
116+
* `extraProps` is the prop to carry information to the form field.
117+
* In this example, I assume the component that is registered in the component registry
118+
* as the form field handles `label` to show it as a text content in the `label` element.
119+
*
120+
* The props for the `extraProps` should have more variety (e.g., `disabled`, `placeholder`, ...),
121+
* but I will work on adding them in other PRs later on.
122+
*/}
123+
<HStack>
124+
<Field name="input.name" extraProps={{ label: "Task Name" }} />
125+
<Field name="input.priority" extraProps={{ label: "Task Priority" }} />
126+
</HStack>
127+
<Button type="submit">Add</Button>
128+
</form>
129+
))
130+
}
131+
</FabrixComponent>
132+
```
133+
134+
Additionally, for more page-by-page customization for the form, `getInput` functions offers more functions in its render props, mostly powered by react-hook-form that fabrix internal uses.
135+
136+
### Field-level handler
137+
138+
In the case that the field component automatially decided by GraphQL type does not fit the requirement in the form, `getInput` function provides the another customizable point at the field level in the form.
139+
140+
`getField` function returns the value of `UseFormRegisterReturn` in react-hook-form. Users would be able to use the another input component on the spot with this.
141+
142+
```tsx
143+
<FabrixComponent query={`/* ... */`}>
144+
{({ getInput }) =>
145+
getInput({}, ({ Field, getAction, getField }) => {
146+
<form {...getAction()}>
147+
<Field name="input.name" />
148+
<Field name="input.priority" />
149+
<input {...getField("input.email")} type="text" />
150+
</form>
151+
})
152+
}
153+
</FabrixComponent>
154+
```
155+
156+
### Form context
157+
158+
The render props of `getInput` function also passes down `formContext` that is the react-hook-form context that the form rendered by `getInput` internally maintains.
159+
160+
This helps users create the flexible form-wide funcionality as they want by lerveraging the functionality of react-hook-form like inter-field interactibity.
161+
162+
```tsx
163+
import { UseFormReturn } from "react-hook-form";
164+
165+
const Page = () =>
166+
<FabrixComponent query={`/* ... */`}>
167+
{({ getInput }) =>
168+
getInput({}, ({ getAction, formContext }) => {
169+
<form {...getAction()}>
170+
<WatchingField formContext={formContext} />
171+
</form>
172+
})
173+
}
174+
</FabrixComponent>
175+
176+
const WatchingField = (props: {
177+
formContext: UseFormReturn,
178+
}) => {
179+
/*
180+
* Watches the value on the form field using `watch` method in the form context of react-hook-form
181+
*/
182+
const status = formContext.watch("input.priority");
183+
}
184+
```
185+
186+
## Backward incompatibility
187+
188+
The previous behaviour of `FabrixComponent` is that only the component for the result was rendered in `Query` and only the form for `Mutation` on the contrary.
189+
However, from this relelase, `FabrixComponent` will render both the form and the result of the component regardless of operation type.
190+
191+
If you would like to maintain the previous behaviour, use directives to guide the query render only the specific component that you want.
192+
193+
```tsx
194+
/*
195+
* `@fabrixForm` directive does not
196+
*/
197+
<FabrixComponent
198+
query={gql`
199+
mutation updateTodo($id: ID!, $input: CreateTodoInput!) {
200+
updateTodo(id: $id, input: $input) @fabrixForm {
201+
id
202+
}
203+
}
204+
`}
205+
/>
206+
```
207+
208+
`fabrixView` also works for `Query` operation in the same way.

.github/actions/ci/action.yaml

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
name: Lint
2+
description: Run linter and type-checker and test
23

3-
inputs:
4-
filter:
5-
description: 'The package to lint'
6-
required: true
7-
8-
# Run linter and type-checker
94
runs:
105
using: composite
116
steps:
@@ -21,6 +16,8 @@ runs:
2116
- name: Install dependencies
2217
run: pnpm install
2318
shell: bash
24-
- name: Lint
25-
run: npx turbo run lint test type-check --filter="./${{ inputs.filter }}"
19+
- name: Launch Turbo Remote Cache Server
20+
uses: dtinth/setup-github-actions-caching-for-turbo@v1.3.0
21+
- name: Run lint / test / type-check
22+
run: npx turbo run lint test type-check
2623
shell: bash

.github/workflows/ci-examples.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
paths:
66
- 'examples/**'
77
- '.github/workflows/ci-examples.yaml'
8+
- '.github/actions/build/action.yaml'
89

910
concurrency:
1011
group: ${{ github.workflow }}-${{ github.ref }}

.github/workflows/ci-packages.yaml

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,20 @@ on:
55
paths:
66
- 'packages/**'
77
- '.github/workflows/ci-packages.yaml'
8+
- '.github/actions/ci/action.yaml'
89

910
concurrency:
1011
group: ${{ github.workflow }}-${{ github.ref }}
1112
cancel-in-progress: true
1213

1314
jobs:
1415
ci:
15-
strategy:
16-
matrix:
17-
packages:
18-
- fabrix
19-
- graphql-config
20-
- chakra-ui
2116
runs-on: ubuntu-latest
2217
steps:
2318
- uses: actions/checkout@v4
2419
with:
2520
fetch-depth: 2
26-
- uses: tj-actions/changed-files@v45
27-
id: changed-files
28-
with:
29-
files: |
30-
packages/${{ matrix.packages }}/**
3121
- uses: ./.github/actions/ci
32-
if: steps.changed-files.outputs.any_changed == 'true'
33-
with:
34-
filter: "packages/${{ matrix.packages }}"
3522

3623
# A job to check if all examples can be built successfully to detect unwanted breaking changes
3724
build-examples:

examples/vite-todoapp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"react-icons": "^5.4.0"
2525
},
2626
"devDependencies": {
27-
"@eslint/js": "^9.15.0",
27+
"@eslint/js": "^9.19.0",
2828
"@fabrix-framework/eslint-config": "workspace:*",
2929
"@fabrix-framework/prettier-config": "workspace:*",
3030
"@graphql-codegen/cli": "^5.0.4",

examples/vite-todoapp/src/App.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,17 @@ function App() {
1919
}
2020
}
2121
`)}
22-
/>
22+
>
23+
{({ getInput }) =>
24+
getInput({}, ({ Field, getAction }) => (
25+
<form {...getAction()}>
26+
<Field name="input.name" />
27+
<Field name="input.priority" />
28+
<Button type="submit">Add</Button>
29+
</form>
30+
))
31+
}
32+
</FabrixComponent>
2333
<FabrixComponent
2434
containerClassName={containerClassName}
2535
query={graphql(`

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
"devDependencies": {
1515
"@changesets/changelog-github": "^0.5.0",
1616
"@changesets/cli": "^2.27.12",
17-
"turbo": "^2.3.3"
17+
"turbo": "^2.4.0"
1818
}
1919
}

0 commit comments

Comments
 (0)