Skip to content

Commit

Permalink
refactor: Renaming route registrations options (#206)
Browse files Browse the repository at this point in the history
* Some stuff

* Added changeset files
  • Loading branch information
patricklafrance authored Sep 23, 2024
1 parent bdc2564 commit 8ee26fd
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 95 deletions.
9 changes: 9 additions & 0 deletions .changeset/friendly-toes-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@squide/react-router": minor
"@squide/core": minor
---

- Renamed a route definition `$name` option to `$id`.
- Renamed the `registerRoute` `$parentName` option to `$parentId`.

These changes should have been a major version but since Squide firefly v9 has been released a few days ago and no applications already migrated, it's include as part of v9 breaking changes.
4 changes: 2 additions & 2 deletions docs/getting-started/create-host.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export function RootLayout() {
}
```

The `RootLayout` component created in the previous sample will serves as the default layout for the homepage as well as for every page (route) registered by a module that are not nested under a parent route with either the [parentPath](../reference/runtime/runtime-class.md#register-nested-routes) or the [parentName](../reference/runtime/runtime-class.md#register-a-named-route) option.
The `RootLayout` component created in the previous sample will serves as the default layout for the homepage as well as for every page (route) registered by a module that are not nested under a parent route with either the [parentPath](../reference/runtime/runtime-class.md#register-nested-routes) or the [parentId](../reference/runtime/runtime-class.md#register-a-route-with-an-id) option.

### Homepage

Expand Down Expand Up @@ -260,7 +260,7 @@ export const registerHost: ModuleRegisterFunction<FireflyRuntime> = runtime => {
```

!!!info
The [PublicRoutes](../reference/routing/publicRoutes.md) and [ProtectedRoutes](../reference/routing/protectedRoutes.md) placeholders indicates where routes that are neither hoisted or nested with a [parentPath](../reference/runtime/runtime-class.md#register-nested-navigation-items) or [parentName](../reference/runtime/runtime-class.md#register-a-named-route) option will be rendered. In this example, the homepage route is considered as a protected route and will be rendered under the `ProtectedRoutes` placeholder.
The [PublicRoutes](../reference/routing/publicRoutes.md) and [ProtectedRoutes](../reference/routing/protectedRoutes.md) placeholders indicates where routes that are neither hoisted or nested with a [parentPath](../reference/runtime/runtime-class.md#register-nested-navigation-items) or [parentId](../reference/runtime/runtime-class.md#register-a-route-with-an-id) option will be rendered. In this example, the homepage route is considered as a protected route and will be rendered under the `ProtectedRoutes` placeholder.
!!!

Finally, update the bootstrapping code to [register](../reference/registration/registerLocalModules.md) the newly created local module:
Expand Down
4 changes: 3 additions & 1 deletion docs/guides/migrate-to-firefly-v9.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Finally, with `v9`, Squide's philosophy has evolved. We used to describe Squide
### Renamed

- The `setMswAsStarted` function has been renamed to [setMswIsReady](../reference/msw/setMswAsReady.md).
- A route definition `$name` option has been renamed to [$id](../reference/runtime/runtime-class.md#register-a-route-with-an-id).
- The [registerRoute](../reference/runtime/runtime-class.md#register-routes) `parentName` option has been renamed to [parentId](../reference/runtime/runtime-class.md#register-nested-routes).

### Others

Expand Down Expand Up @@ -331,7 +333,7 @@ export const registerHost: ModuleRegisterFunction<FireflyRuntime> = runtime => {
element: <RootLayout />,
children: [
{
$name: "root-error-boundary",
$id: "root-error-boundary",
errorElement: <RootErrorBoundary />,
children: [
ManagedRoutes
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/routing/protectedRoutes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ toc:

A placeholder indicating where in the routing tree should the protected routes be rendered. The `ProtectedRoutes` placeholder concept is similar to React Router's [outlet](https://reactrouter.com/en/main/components/outlet), it's a pipeline to inject routes at a predetermined location.

> A protected route is a route with a `"protected"` visibility that is not [hoisted](../runtime/runtime-class.md#register-an-hoisted-route) or nested with either a [parentPath](../runtime/runtime-class.md#register-nested-routes) or [parentName](../runtime/runtime-class.md#register-a-named-route) option.
> A protected route is a route with a `"protected"` visibility that is not [hoisted](../runtime/runtime-class.md#register-an-hoisted-route) or nested with either a [parentPath](../runtime/runtime-class.md#register-nested-routes) or [parentId](../runtime/runtime-class.md#register-a-route-with-an-id) option.
## Reference

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/routing/publicRoutes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ toc:

A placeholder indicating where in the routing tree should the public routes be rendered. The `PublicRoutes` placeholder concept is similar to React Router's [outlet](https://reactrouter.com/en/main/components/outlet), it's a pipeline to inject routes at a predetermined location.

> A public route is a route with a `"public"` visibility that is not [hoisted](../runtime/runtime-class.md#register-an-hoisted-route) or nested with either a [parentPath](../runtime/runtime-class.md#register-nested-routes) or [parentName](../runtime/runtime-class.md#register-a-named-route) option.
> A public route is a route with a `"public"` visibility that is not [hoisted](../runtime/runtime-class.md#register-an-hoisted-route) or nested with either a [parentPath](../runtime/runtime-class.md#register-nested-routes) or [parentId](../runtime/runtime-class.md#register-a-route-with-an-id) option.
## Reference

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/routing/useRenderedNavigationItems.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Accept any properties of a React Router [Link](https://reactrouter.com/en/main/c

#### `NavigationSection`

- `$id`: An optional key identifying the section. Usually used to nest navigation items undern a specific section and as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$id`: An optional identifier the section. Usually used to nest navigation items undern a specific section and as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$label`: The section label. Could either by a `string` or a `ReactNode`.
- `$canRender`: An optional function accepting an object and returning a `boolean` indicating whether or not the section should be rendered.
- `$additionalProps`: An optional object literal of additional props to apply to the section component.
Expand Down
39 changes: 27 additions & 12 deletions docs/reference/runtime/runtime-class.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,16 @@ if (runtime.isMswEnabled) {
### Register routes

```ts
runtime.registerRoute(route, options?: { hoist?, parentPath?, parentName? })
runtime.registerRoute(route, options?: { hoist?, parentPath?, parentId? })
```

- `route`: accept any properties of a React Router [Route](https://reactrouter.com/en/main/components/route) component with the addition of:
- `$name`: An optional name for the route.
- `$id`: An optional identifier for the route. Usually used to nest routes under a specific route.
- `$visibility`: An optional visibility indicator for the route. Accepted values are `"public"` or `"protected"`.
- `options`: An optional object literal of options:
- `hoist`: An optional `boolean` value to register the route at the root of the router. The default value is `false`.
- `parentPath`: An optional path of a parent route to register this new route under.
- `parentName`: An optional name of a parent route to register this new route under.
- `parentId`: An optional id of a parent route to register this new route under.

```tsx
import { Page } from "./Page.tsx"
Expand Down Expand Up @@ -159,17 +159,17 @@ runtime.registerPublicRoute({
When no `$visibility` indicator is provided, a route is considered `protected`.
!!!

### Register a named route
### Register a route with an id

The `registerRoute` function accepts a `parentName` option, allowing a route to be [nested under an existing parent route](#register-nested-routes). When searching for the parent route matching the `parentName` option, the `parentName` will be matched against the `$name` option of every route.
The `registerRoute` function accepts a `parentId` option, allowing a route to be [nested under an existing parent route](#register-nested-routes). When searching for the parent route matching the `parentId` option, the `parentId` will be matched against the `$id` option of every route.

> A `$name` option should only be defined for routes that doesn't have a path like an error boundary or an authentication boundary.
> A `$id` option should only be defined for routes that doesn't have a path like an error boundary or an authentication boundary.
```tsx !#4
import { RootErrorBoundary } from "./RootErrorBoundary.tsx";

runtime.registerRoute({
$name: "error-boundary",
$id: "error-boundary",
element: <RootErrorBoundary />
});
```
Expand All @@ -193,7 +193,7 @@ runtime.registerRoute({
});
```

Or a `parentName` option that matches the parent route's `name` option:
Or a `parentId` option that matches the parent route's `$id` option:

```tsx !#7
import { Page } from "./Page.tsx";
Expand All @@ -202,7 +202,7 @@ runtime.registerRoute({
path: "/page-1",
element: <Page />
}, {
parentName: "error-boundary" // Register the route under an existing route having "error-boundary" as its "name".
parentId: "error-boundary" // Register the route under an existing route having "error-boundary" as its "$id".
});
```

Expand All @@ -223,27 +223,28 @@ const routes = runtime.routes;
### Register navigation items

```ts
runtime.registerNavigationItem(item, options?: { menuId? })
runtime.registerNavigationItem(item, options?: { menuId?, sectionId? })
```

- `item`: `NavigationSection | NavigationLink`.
- `options`: An optional object literal of options:
- `menuId`: An optional menu id to associate the item with.
- `sectionId`: An optional section id of a parent navigation section to register this new item under.

A Squide navigation item can either be a `NavigationLink` or a `NavigationSection`. Both types can be intertwined to create a multi-level menu hierarchy. A `NavigationSection` item is used to setup a new level while a `NavigationLink` define a link.

#### `NavigationLink`

Accept any properties of a React Router [Link](https://reactrouter.com/en/main/components/link) component with the addition of:
- `$id`: An optional key identifying the link. Usually used as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$id`: An optional identifier for the link. Usually used as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$label`: The link text.
- `$canRender`: An optional function accepting an object and returning a `boolean` indicating whether or not the link should be rendered.
- `$priority`: An order priority affecting the position of the item in the menu (higher first)
- `$additionalProps`: Additional properties to be forwarded to the link renderer.

#### `NavigationSection`

- `$id`: An optional key identifying the section. Usually used to nest navigation items under a specific section and as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$id`: An optional identifier for the section. Usually used to nest navigation items under a specific section and as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$label`: The section text.
- `$canRender`: An optional function accepting an object and returning a `boolean` indicating whether or not the section should be rendered.
- `$priority`: An order priority affecting the position of the item in the menu (higher first)
Expand All @@ -265,6 +266,20 @@ runtime.registerNavigationItem({

[!ref text="Setup the host application to render navigation items"](../routing/useRenderedNavigationItems.md)

### Register a navigation item with an id

The `registerNavigationItem` function accepts a `sectionId` option, allowing a navigation item to be nested under an existing navigation section. When searching the parent navigation section matching the `sectionId` option, the `sectionId` will be match against the `$id` option of every navigation item.

```ts
runtime.registerNavigationItem({
$id: "page-1",
$label: "Page 1",
to: "/page-1"
});
```

Additionally, when combined with the [useRenderedNavigationItems]() function, the `$id` option will be used as the React element `key` property.

### Register nested navigation items

Similarly to [nested routes](#register-nested-navigation-items), a navigation item can be nested under an existing section be specifying a `sectionId` option that matches the section's `$id` option:
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/runtime/useNavigationItems.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ An array of `NavigationLink | NavigationSection`.
#### `NavigationLink`

Accept any properties of a React Router [Link](https://reactrouter.com/en/main/components/link) component with the addition of:
- `$id`: An optional key identifying the link. Usually used as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$id`: An optional identifier for the link. Usually used as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$label`: The link label. Could either by a `string` or a `ReactNode`.
- `$canRender`: An optional function accepting an object and returning a `boolean` indicating whether or not the link should be rendered.
- `$additionalProps`: An optional object literal of additional props to apply to the link component.

#### `NavigationSection`

- `$id`: An optional key identifying the section. Usually used to nest navigation items under a specific section and as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$id`: An optional identifier for the section. Usually used to nest navigation items under a specific section and as the React element [key](https://legacy.reactjs.org/docs/lists-and-keys.html#keys) property.
- `$label`: The section label. Could either by a `string` or a `ReactNode`.
- `$canRender`: An optional function accepting an object and returning a `boolean` indicating whether or not the section should be rendered.
- `$additionalProps`: An optional object literal of additional props to apply to the section component.
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/runtime/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface RuntimeOptions {
export interface RegisterRouteOptions {
hoist?: true;
parentPath?: string;
parentName?: string;
parentId?: string;
}

export interface RegisterNavigationItemOptions {
Expand Down
12 changes: 6 additions & 6 deletions packages/react-router/src/outlets.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import type { NonIndexRoute, Route } from "./routeRegistry.ts";

export const PublicRoutesOutletName = "__squide-public-routes-outlet__";
export const PublicRoutesOutletId = "__squide-public-routes-outlet__";

export const PublicRoutes: NonIndexRoute = {
$visibility: "public",
$name: PublicRoutesOutletName
$id: PublicRoutesOutletId
};

export function isPublicRoutesOutletRoute(route: Route) {
return route.$name === PublicRoutesOutletName;
return route.$id === PublicRoutesOutletId;
}

export const ProtectedRoutesOutletName = "__squide-protected-routes-outlet__";
export const ProtectedRoutesOutletId = "__squide-protected-routes-outlet__";

export const ProtectedRoutes: NonIndexRoute = {
$visibility: "protected",
$name: ProtectedRoutesOutletName
$id: ProtectedRoutesOutletId
};

export function isProtectedRoutesOutletRoute(route: Route) {
return route.$name === ProtectedRoutesOutletName;
return route.$id === ProtectedRoutesOutletId;
}
10 changes: 5 additions & 5 deletions packages/react-router/src/reactRouterRuntime.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { RootMenuId, Runtime, type RegisterNavigationItemOptions, type RegisterRouteOptions } from "@squide/core";
import { NavigationItemDeferredRegistrationScope, NavigationItemDeferredRegistrationTransactionalScope, NavigationItemRegistry, parseSectionIndexKey, type NavigationItemRegistrationResult, type RootNavigationItem } from "./navigationItemRegistry.ts";
import { ProtectedRoutesOutletName, PublicRoutesOutletName } from "./outlets.ts";
import { ProtectedRoutesOutletId, PublicRoutesOutletId } from "./outlets.ts";
import { RouteRegistry, type Route } from "./routeRegistry.ts";

function translateOutletsParentId(parentId?: string) {
if (parentId === PublicRoutesOutletName) {
if (parentId === PublicRoutesOutletId) {
return "PublicRoutes";
}

if (parentId === ProtectedRoutesOutletName) {
if (parentId === ProtectedRoutesOutletId) {
return "ProtectedRoutes";
}

Expand Down Expand Up @@ -167,14 +167,14 @@ export class ReactRouterRuntime extends Runtime<Route, RootNavigationItem> {
const pendingRegistrationsForRoute = pendingRegistrations.getPendingRegistrationsForRoute(x);

pendingRegistrationsForRoute.forEach(y => {
message += ` - "${y.path ?? y.$name ?? "(no identifier)"}"\r\n`;
message += ` - "${y.path ?? y.$id ?? "(no identifier)"}"\r\n`;
});

message += "\r\n";
});

message += `If you are certain that the route${pendingRoutes.length !== 1 ? "s" : ""} has been registered, make sure that the following conditions are met:\r\n`;
message += "- The missing routes \"path\" or \"name\" option perfectly match the provided \"parentPath\" or \"parentName\" (make sure that there's no leading or trailing \"/\" that differs).\r\n";
message += "- The missing routes \"path\" or \"$id\" option perfectly match the provided \"parentPath\" or \"parentId\" (make sure that there's no leading or trailing \"/\" that differs).\r\n";
message += "- The missing routes has been registered with the runtime.registerRoute function. A route cannot be registered under a parent route that has not be registered with the runtime.registerRoute function.\r\n";
message += "For more information about nested routes, refers to https://gsoft-inc.github.io/wl-squide/reference/runtime/runtime-class/#register-nested-routes-under-an-existing-route.\r\n";
message += "For more information about the PublicRoutes and ProtectedRoutes outlets, refers to https://gsoft-inc.github.io/wl-squide/reference/#routing.";
Expand Down
Loading

0 comments on commit 8ee26fd

Please sign in to comment.