Skip to content

Commit

Permalink
Convert Nav and ApplicationBase to functional components
Browse files Browse the repository at this point in the history
This PR is fairly long, but it converts the two components into its functional
counterpart.

With the `Nav` we converted to `Navigation`that exports a `NavigationProvider`
component and a `NavigationContext`, the latter is handy if we wanted to
access visit, remote, pageKey, and navigateTo to help users build a custom
`<Link>` component or if they want to use the functions without passing it
from parent to child.

With `Application`, we removed `ApplicationBase`. In doing so, we've simplified
the component to the point that if someone wanted fine grain control of building
the redux `Provider` or `Navigation`, they can just refer to the source code and
build their own using the same helper methods in `lib/index.ts`.

We also updated the docs.
  • Loading branch information
jho406 committed Oct 19, 2024
1 parent 0bb4ecd commit 85e50f9
Show file tree
Hide file tree
Showing 15 changed files with 685 additions and 576 deletions.
27 changes: 6 additions & 21 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,28 +54,14 @@ const pageIdentifierToPageComponent = {

## `application.js`

!!! hint
Normally you wouldn't need to configure this class as it'll be generated
for you.

Your `Application` component inherits from Superglue's [ApplicationBase]
abstract class and is the entry point for your Superglue app. It overrides
the methods [buildStore], [visitAndRemote], and [mapping], to perform
setup of redux, UJS, and other functionality.


```js
import { ApplicationBase } from '@thoughtbot/superglue'

export default class Application extends ApplicationBase {
...
}
```

This is the entry point of your application and uses Superglue's [Application]
component. There's nothing to do here, but if you need finer control of
how redux is setup, you can build your own Application using the [source] as
inspiration.

<div class="grid cards" markdown>
- [:octicons-arrow-right-24: See complete reference](reference/index.md#abstract-applicationbase)
for `ApplicationBase`
- [:octicons-arrow-right-24: See complete reference](reference/index.md#application)
for `Application` and source reference under [Defined in](reference/index.md#defined-in_13)
</div>

## `flash.js`
Expand Down Expand Up @@ -112,7 +98,6 @@ def create
end
```

[ApplicationBase]: reference/index.md#abstract-applicationbase
[buildStore]: reference/index.md#buildstore
[visitAndRemote]: requests.md
[mapping]: reference/index.md#mapping
Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ nav:
- Rails Utilities: rails-utils.md
- Page utilities: functions-passed.md
- Hooks: reference/hooks.md
- Nav: reference/components.Nav.md
- Navigation: reference/components.Navigation.md
- Superglue: reference/index.md
- Types: reference/types.md
- Requests: reference/types.requests.md
Expand Down
4 changes: 3 additions & 1 deletion superglue/.prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 80
"printWidth": 80,
"useTabs": false,
"tabWidth": 2
}
7 changes: 7 additions & 0 deletions superglue/lib/action_creators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ function getChangedFragments(page: Page) {
return changedFragments
}

/**
* Save and process a rendered view from PropsTemplate. This is the primitive
* function that `visit` and `remote` calls when it receives a page.
*
* If you render a page outside the normal request response cycle, e.g,
* websocket, you can use this function to save the payload.
*/
export function saveAndProcessPage(
pageKey: string,
page: VisitResponse | GraftResponse
Expand Down
65 changes: 65 additions & 0 deletions superglue/lib/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,88 @@ export const updateFragments = createAction<{
changedFragments: Record<string, JSONValue>
}>('@@superglue/UPDATE_FRAGMENTS')

/**
* A redux action you can dispatch to copy a page from one pageKey to another. Its
* a very useful way to create optimistic updates with a URL change. For example:
*
* ```
* import { copyPage, remote } from '@thoughtbot/superglue'
*
* dispatch(copyPage({ from: originalKey, to: targetKey}))
*
* ... make edits to target page and finally
*
* navigateTo(targetKey)
* ```
*/
export const copyPage = createAction<{ from: PageKey; to: PageKey }>(
'@@superglue/COPY_PAGE'
)

/**
* A redux action you can dispatch to remove a page from your store.
*
* ```
* import { removePage } from '@thoughtbot/superglue'
*
* dispatch(removePage({ pageKey: '/delete_me_please"}))
* ```
*/
export const removePage = createAction<{ pageKey: PageKey }>(
'@@superglue/REMOVE_PAGE'
)

/**
* A redux action called before a `fetch` takes place. It will fire in `remote`
* and `visit`. You can hook into this event in your redux slices like this:
*
* ```
* import { beforeFetch } from '@thoughtbot/superglue'
*
* export const exampleSlice = createSlice({
* name: 'Example',
* initialState: {},
* extraReducers: (builder) => {
* builder.addCase(beforeFetch, (state, action) => {
* ```
*/
export const beforeFetch = createAction<{ fetchArgs: FetchArgs }>(
'@@superglue/BEFORE_FETCH'
)

/**
* A redux action called before a `visit` takes place. You can hook into this event
* in your redux slices like this:
*
* ```
* import { beforeVisit } from '@thoughtbot/superglue'
*
* export const exampleSlice = createSlice({
* name: 'Example',
* initialState: {},
* extraReducers: (builder) => {
* builder.addCase(beforeVisit, (state, action) => {
* ```
*/
export const beforeVisit = createAction<{
currentPageKey: PageKey
fetchArgs: FetchArgs
}>('@@superglue/BEFORE_VISIT')

/**
* A redux action called before `remote` takes place. You can hook into this event
* in your redux slices like this:
*
* ```
* import { beforeRemote } from '@thoughtbot/superglue'
*
* export const exampleSlice = createSlice({
* name: 'Example',
* initialState: {},
* extraReducers: (builder) => {
* builder.addCase(beforeRemote, (state, action) => {
* ```
*/
export const beforeRemote = createAction<{
currentPageKey: PageKey
fetchArgs: FetchArgs
Expand Down
Loading

0 comments on commit 85e50f9

Please sign in to comment.