@archipelago-js/react 0.1.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +251 -7
- package/dist/IslandForm.d.ts +16 -0
- package/dist/IslandForm.js +51 -0
- package/dist/IslandForm.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/useIslandForm.d.ts +27 -7
- package/dist/useIslandForm.js +162 -15
- package/dist/useIslandForm.js.map +1 -1
- package/package.json +5 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @archipelago-js/react
|
|
2
2
|
|
|
3
|
-
React bindings for Archipelago islands.
|
|
3
|
+
React bindings for [Archipelago](https://github.com/Catchhook/archipelago-rails) islands — server-rendered micro-frontends powered by Rails and React.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -8,10 +8,254 @@ React bindings for Archipelago islands.
|
|
|
8
8
|
yarn add @archipelago-js/react @archipelago-js/client react react-dom
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## 60-Second Quick Start
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
### 1. Rails View Helper
|
|
14
|
+
|
|
15
|
+
Render an island from any ERB template:
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<%= archipelago_island("TeamMembers", props: { team_id: @team.id }, stream: "team:#{@team.id}") %>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 2. React Island Component
|
|
22
|
+
|
|
23
|
+
Create `app/javascript/islands/TeamMembers.tsx`:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { useIslandProps, useIslandForm } from "@archipelago-js/react"
|
|
27
|
+
|
|
28
|
+
export default function TeamMembers() {
|
|
29
|
+
const { props } = useIslandProps()
|
|
30
|
+
const form = useIslandForm({ initialData: { name: "" } })
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div>
|
|
34
|
+
<h2>Team #{props.team_id}</h2>
|
|
35
|
+
<input
|
|
36
|
+
value={form.data.name}
|
|
37
|
+
onChange={(e) => form.setData("name", e.target.value)}
|
|
38
|
+
/>
|
|
39
|
+
<button onClick={() => form.post("add_member")} disabled={form.processing}>
|
|
40
|
+
{form.recentlySuccessful ? "Added!" : "Add Member"}
|
|
41
|
+
</button>
|
|
42
|
+
{form.errors.name?.map((e) => <p key={e}>{e}</p>)}
|
|
43
|
+
</div>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. Boot Islands
|
|
49
|
+
|
|
50
|
+
In your JS entry file:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { bootArchipelagoIslands } from "@archipelago-js/react"
|
|
54
|
+
import TeamMembers from "../islands/TeamMembers"
|
|
55
|
+
|
|
56
|
+
void bootArchipelagoIslands({
|
|
57
|
+
TeamMembers
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Context
|
|
62
|
+
|
|
63
|
+
Every island is wrapped in an `IslandProvider` that provides context via `useIslandContext()`:
|
|
64
|
+
|
|
65
|
+
| Field | Type | Description |
|
|
66
|
+
|-------------|--------------------------------|---------------------------------------------|
|
|
67
|
+
| `component` | `string` | Island component name |
|
|
68
|
+
| `params` | `Record<string, unknown>` | Server-side params embedded in the HTML |
|
|
69
|
+
| `instance` | `string \| undefined` | Optional instance identifier |
|
|
70
|
+
| `stream` | `string \| undefined` | ActionCable stream name for live updates |
|
|
71
|
+
| `state` | `{ props, version }` | Current props and version |
|
|
72
|
+
| `setState` | `Dispatch<SetStateAction<…>>` | Update island state |
|
|
73
|
+
|
|
74
|
+
`useIslandProps()` is the primary way to read props:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
const { props, setProps, version } = useIslandProps()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Forms
|
|
81
|
+
|
|
82
|
+
### `useIslandForm` (Controlled)
|
|
83
|
+
|
|
84
|
+
The form hook manages data, errors, processing state, and submission:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
const form = useIslandForm({
|
|
88
|
+
initialData: { email: "", role: "member" },
|
|
89
|
+
clearFieldErrorsOnChange: true,
|
|
90
|
+
recentlySuccessfulDuration: 2000,
|
|
91
|
+
transform: (data) => ({ ...data, email: data.email.toLowerCase() }),
|
|
92
|
+
onSuccess: (response) => console.log("Saved!", response),
|
|
93
|
+
onError: (response) => console.log("Validation failed", response),
|
|
94
|
+
onFinish: () => console.log("Request complete")
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Returned values:**
|
|
99
|
+
|
|
100
|
+
| Property | Type | Description |
|
|
101
|
+
|------------------------|-----------------------------------------|--------------------------------------------------|
|
|
102
|
+
| `data` | `TData` | Current form data |
|
|
103
|
+
| `setData(field, val)` | `(field, value) => void` | Set a field value |
|
|
104
|
+
| `errors` | `Record<string, string[]>` | Field-keyed validation errors |
|
|
105
|
+
| `setError(field, msg)` | `(field, message) => void` | Manually set a field error |
|
|
106
|
+
| `clearErrors(...f?)` | `(...fields?) => void` | Clear all or specific errors |
|
|
107
|
+
| `processing` | `boolean` | True while request is in flight |
|
|
108
|
+
| `wasSuccessful` | `boolean` | True after an ok/redirect response |
|
|
109
|
+
| `recentlySuccessful` | `boolean` | True for `recentlySuccessfulDuration` ms after success |
|
|
110
|
+
| `progress` | `{ percentage } \| null` | Upload progress (future XHR support) |
|
|
111
|
+
| `transportError` | `Error \| null` | Network/parse error (not a validation error) |
|
|
112
|
+
| `defaults(...)` | Getter/setter for default values | `defaults()` returns defaults; `defaults(next)` updates them |
|
|
113
|
+
| `reset(...fields?)` | `(...fields?) => void` | Reset all or specific fields to defaults |
|
|
114
|
+
| `resetAndClearErrors` | `(...fields?) => void` | Reset data + clear errors |
|
|
115
|
+
| `post(op, overrides?)` | `(operation, overrides?) => Promise` | Submit with POST |
|
|
116
|
+
| `put` / `patch` / `delete` | Same as `post` | Submit with PUT / PATCH / DELETE |
|
|
117
|
+
|
|
118
|
+
### `<IslandForm>` (Declarative / Uncontrolled)
|
|
119
|
+
|
|
120
|
+
For simple forms that don't need keystroke-level control:
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { IslandForm } from "@archipelago-js/react"
|
|
124
|
+
|
|
125
|
+
<IslandForm operation="update_settings" method="patch" resetOnSuccess>
|
|
126
|
+
<input name="display_name" defaultValue={props.display_name} />
|
|
127
|
+
<button type="submit">Save</button>
|
|
128
|
+
</IslandForm>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Render-prop children get access to the full form object:
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
<IslandForm operation="create_post" method="post">
|
|
135
|
+
{(form) => (
|
|
136
|
+
<>
|
|
137
|
+
<input name="title" />
|
|
138
|
+
{form.errors.title?.map((e) => <span key={e}>{e}</span>)}
|
|
139
|
+
<button type="submit" disabled={form.processing}>
|
|
140
|
+
{form.recentlySuccessful ? "Created!" : "Create"}
|
|
141
|
+
</button>
|
|
142
|
+
</>
|
|
143
|
+
)}
|
|
144
|
+
</IslandForm>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Props:**
|
|
148
|
+
|
|
149
|
+
| Prop | Type | Default |
|
|
150
|
+
|------------------------|--------------------------|-----------|
|
|
151
|
+
| `operation` | `string` | required |
|
|
152
|
+
| `method` | `FormMethod` | `"post"` |
|
|
153
|
+
| `transform` | `(data) => data` | — |
|
|
154
|
+
| `resetOnSuccess` | `boolean` | `false` |
|
|
155
|
+
| `clearErrorsOnSuccess` | `boolean` | `false` |
|
|
156
|
+
| `fixedParams` | `Record<string, unknown>`| — |
|
|
157
|
+
| `onSuccess` | `(response) => void` | — |
|
|
158
|
+
| `onError` | `(response) => void` | — |
|
|
159
|
+
| `onForbidden` | `(response) => void` | — |
|
|
160
|
+
| `onFinish` | `(response?) => void` | — |
|
|
161
|
+
|
|
162
|
+
## Streams (Live Updates via ActionCable)
|
|
163
|
+
|
|
164
|
+
Islands with a `stream` attribute automatically subscribe to an ActionCable channel. When a broadcast arrives, `useIslandProps()` updates the props in real time.
|
|
165
|
+
|
|
166
|
+
### Setup
|
|
167
|
+
|
|
168
|
+
Assign an ActionCable consumer globally:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
import { createConsumer } from "@rails/actioncable"
|
|
172
|
+
window.Archipelago = { cable: createConsumer() }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Server Broadcast
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
Archipelago.broadcast("team:#{team.id}", props: { members: team.members.as_json })
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Custom Merge Logic
|
|
182
|
+
|
|
183
|
+
Use `onLiveProps` to merge incoming props with the current state:
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
const { props } = useIslandProps({
|
|
187
|
+
onLiveProps: (next, previous) => ({
|
|
188
|
+
...previous,
|
|
189
|
+
members: next.members
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Lazy Islands (`defineIslandLoader`)
|
|
195
|
+
|
|
196
|
+
Code-split islands so their JavaScript is only fetched when the island appears in the DOM:
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { defineIslandLoader, bootArchipelagoIslands } from "@archipelago-js/react"
|
|
200
|
+
|
|
201
|
+
void bootArchipelagoIslands({
|
|
202
|
+
TeamMembers: defineIslandLoader(
|
|
203
|
+
() => import("../islands/TeamMembers"),
|
|
204
|
+
<div>Loading team...</div> // optional fallback
|
|
205
|
+
)
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The Rails generator supports `--lazy_registry` to scaffold a lazy registry automatically:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
bin/rails generate archipelago:install:react --lazy_registry
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Turbo Lifecycle
|
|
216
|
+
|
|
217
|
+
Archipelago integrates seamlessly with Turbo Drive and Turbo Frames:
|
|
218
|
+
|
|
219
|
+
- **`turbo:load`** / **`turbo:render`** / **`turbo:frame-load`** — Automatically boots any new `[data-island]` elements added to the page.
|
|
220
|
+
- **`turbo:before-cache`** — All mounted islands are unmounted before Turbo caches the page, preventing stale React trees from persisting in the snapshot.
|
|
221
|
+
- **MutationObserver** — A DOM observer detects dynamically inserted islands (e.g. from Turbo Streams or manual DOM manipulation) and boots them automatically.
|
|
222
|
+
|
|
223
|
+
No extra configuration is needed. Just call `bootArchipelagoIslands(registry)` once in your entry file.
|
|
224
|
+
|
|
225
|
+
## Error Handling
|
|
226
|
+
|
|
227
|
+
### `FORM_ERROR`
|
|
228
|
+
|
|
229
|
+
The `@archipelago-js/client` package exports a `FORM_ERROR` constant (`"_base"`) for base-level form errors:
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
import { FORM_ERROR } from "@archipelago-js/client"
|
|
233
|
+
|
|
234
|
+
{form.errors[FORM_ERROR]?.map((e) => <p key={e}>{e}</p>)}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### `ArchipelagoTransportError`
|
|
238
|
+
|
|
239
|
+
Network failures, HTML responses, and JSON parse errors are wrapped in `ArchipelagoTransportError` (also exported from `@archipelago-js/client`). The form hook captures these into `form.transportError`.
|
|
240
|
+
|
|
241
|
+
### `ErrorBoundary`
|
|
242
|
+
|
|
243
|
+
Each island is wrapped in an `ErrorBoundary`. If an island crashes, the error is contained and other islands continue to function.
|
|
244
|
+
|
|
245
|
+
## API Reference
|
|
246
|
+
|
|
247
|
+
| Export | Package | Description |
|
|
248
|
+
|-------------------------------|----------|------------------------------------------|
|
|
249
|
+
| `bootArchipelagoIslands` | react | Mount all `[data-island]` elements |
|
|
250
|
+
| `unmountArchipelagoIslands` | react | Tear down all mounted islands |
|
|
251
|
+
| `defineIslandLoader` | react | Create a lazy-loaded registry entry |
|
|
252
|
+
| `useIslandProps` | react | Read/subscribe to island props |
|
|
253
|
+
| `useIslandForm` | react | Controlled form state and submission |
|
|
254
|
+
| `IslandForm` | react | Declarative form component |
|
|
255
|
+
| `IslandProvider` | react | Context provider (used internally) |
|
|
256
|
+
| `useIslandContext` | react | Access raw island context |
|
|
257
|
+
| `ErrorBoundary` | react | Per-island error boundary |
|
|
258
|
+
| `islandFetch` | client | Low-level island RPC call |
|
|
259
|
+
| `FORM_ERROR` | client | `"_base"` constant for base errors |
|
|
260
|
+
| `ArchipelagoTransportError` | client | Typed transport error class |
|
|
261
|
+
| `parseIslandResponse` | client | Parse raw JSON into typed response |
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useIslandForm, type UseIslandFormCallbacks } from "./useIslandForm";
|
|
3
|
+
type FormMethod = "post" | "put" | "patch" | "delete";
|
|
4
|
+
type IslandFormRenderProps = ReturnType<typeof useIslandForm>;
|
|
5
|
+
export interface IslandFormProps extends UseIslandFormCallbacks<Record<string, unknown>> {
|
|
6
|
+
operation: string;
|
|
7
|
+
method?: FormMethod;
|
|
8
|
+
transform?: (payload: Record<string, unknown>) => Record<string, unknown>;
|
|
9
|
+
resetOnSuccess?: boolean;
|
|
10
|
+
clearErrorsOnSuccess?: boolean;
|
|
11
|
+
fixedParams?: Record<string, unknown>;
|
|
12
|
+
className?: string;
|
|
13
|
+
children: React.ReactNode | ((form: IslandFormRenderProps) => React.ReactNode);
|
|
14
|
+
}
|
|
15
|
+
export declare function IslandForm({ operation, method, transform, resetOnSuccess, clearErrorsOnSuccess, fixedParams, className, children, onSuccess, onError, onForbidden, onFinish }: IslandFormProps): React.ReactElement;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useRef } from "react";
|
|
3
|
+
import { useIslandForm } from "./useIslandForm";
|
|
4
|
+
function formDataToObject(formData) {
|
|
5
|
+
const result = {};
|
|
6
|
+
formData.forEach((value, key) => {
|
|
7
|
+
const existing = result[key];
|
|
8
|
+
if (existing !== undefined) {
|
|
9
|
+
if (Array.isArray(existing)) {
|
|
10
|
+
existing.push(value);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
result[key] = [existing, value];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
export function IslandForm({ operation, method = "post", transform, resetOnSuccess = false, clearErrorsOnSuccess = false, fixedParams, className, children, onSuccess, onError, onForbidden, onFinish }) {
|
|
23
|
+
const formRef = useRef(null);
|
|
24
|
+
const form = useIslandForm({
|
|
25
|
+
initialData: {},
|
|
26
|
+
fixedParams,
|
|
27
|
+
transform,
|
|
28
|
+
onSuccess: (response) => {
|
|
29
|
+
if (resetOnSuccess) {
|
|
30
|
+
form.reset();
|
|
31
|
+
formRef.current?.reset();
|
|
32
|
+
}
|
|
33
|
+
if (clearErrorsOnSuccess) {
|
|
34
|
+
form.clearErrors();
|
|
35
|
+
}
|
|
36
|
+
onSuccess?.(response);
|
|
37
|
+
},
|
|
38
|
+
onError,
|
|
39
|
+
onForbidden,
|
|
40
|
+
onFinish
|
|
41
|
+
});
|
|
42
|
+
const handleSubmit = useCallback((event) => {
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
const formData = new FormData(event.currentTarget);
|
|
45
|
+
const payload = formDataToObject(formData);
|
|
46
|
+
const submitFn = form[method];
|
|
47
|
+
submitFn(operation, { payload });
|
|
48
|
+
}, [form, method, operation]);
|
|
49
|
+
return (_jsx("form", { ref: formRef, onSubmit: handleSubmit, className: className, children: typeof children === "function" ? children(form) : children }));
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=IslandForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IslandForm.js","sourceRoot":"","sources":["../src/IslandForm.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAElD,OAAO,EAAE,aAAa,EAA+B,MAAM,iBAAiB,CAAA;AAiB5E,SAAS,gBAAgB,CAAC,QAAkB;IAC1C,MAAM,MAAM,GAA4B,EAAE,CAAA;IAE1C,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACrB,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EACzB,SAAS,EACT,MAAM,GAAG,MAAM,EACf,SAAS,EACT,cAAc,GAAG,KAAK,EACtB,oBAAoB,GAAG,KAAK,EAC5B,WAAW,EACX,SAAS,EACT,QAAQ,EACR,SAAS,EACT,OAAO,EACP,WAAW,EACX,QAAQ,EACQ;IAChB,MAAM,OAAO,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAA;IAE7C,MAAM,IAAI,GAAG,aAAa,CAA0B;QAClD,WAAW,EAAE,EAAE;QACf,WAAW;QACX,SAAS;QACT,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE;YACtB,IAAI,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,KAAK,EAAE,CAAA;gBACZ,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;YAC1B,CAAC;YACD,IAAI,oBAAoB,EAAE,CAAC;gBACzB,IAAI,CAAC,WAAW,EAAE,CAAA;YACpB,CAAC;YACD,SAAS,EAAE,CAAC,QAAQ,CAAC,CAAA;QACvB,CAAC;QACD,OAAO;QACP,WAAW;QACX,QAAQ;KACT,CAAC,CAAA;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,KAAuC,EAAE,EAAE;QAC1C,KAAK,CAAC,cAAc,EAAE,CAAA;QAEtB,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;QAClD,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAE1C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;QAC7B,QAAQ,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAClC,CAAC,EACD,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAC1B,CAAA;IAED,OAAO,CACL,eAAM,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,YAC7D,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,GACtD,CACR,CAAA;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA"}
|
package/dist/useIslandForm.d.ts
CHANGED
|
@@ -1,21 +1,41 @@
|
|
|
1
|
+
import { type IslandResponse } from "@archipelago-js/client";
|
|
1
2
|
type SubmitOverrides = {
|
|
2
3
|
payload?: Record<string, unknown>;
|
|
3
4
|
navigate?: (location: string) => void;
|
|
4
5
|
};
|
|
5
|
-
export interface
|
|
6
|
+
export interface UseIslandFormCallbacks<TData extends Record<string, unknown>> {
|
|
7
|
+
onSuccess?: (response: IslandResponse) => void;
|
|
8
|
+
onError?: (response: IslandResponse) => void;
|
|
9
|
+
onForbidden?: (response: IslandResponse) => void;
|
|
10
|
+
onFinish?: (response: IslandResponse | undefined) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface UseIslandFormOptions<TData extends Record<string, unknown>> extends UseIslandFormCallbacks<TData> {
|
|
6
13
|
initialData: TData;
|
|
7
14
|
clearFieldErrorsOnChange?: boolean;
|
|
8
15
|
fixedParams?: Record<string, unknown>;
|
|
16
|
+
recentlySuccessfulDuration?: number;
|
|
17
|
+
transform?: (payload: TData) => Record<string, unknown>;
|
|
9
18
|
}
|
|
10
|
-
export
|
|
19
|
+
export type UploadProgress = {
|
|
20
|
+
percentage: number;
|
|
21
|
+
};
|
|
22
|
+
export declare function useIslandForm<TData extends Record<string, unknown>>({ initialData, clearFieldErrorsOnChange, fixedParams, recentlySuccessfulDuration, transform, onSuccess, onError, onForbidden, onFinish }: UseIslandFormOptions<TData>): {
|
|
11
23
|
data: TData;
|
|
12
24
|
setData: <K extends keyof TData>(field: K, value: TData[K]) => void;
|
|
13
25
|
errors: Record<string, string[]>;
|
|
26
|
+
setError: (field: keyof TData | string, message: string | string[]) => void;
|
|
27
|
+
clearErrors: (...fields: (keyof TData)[]) => void;
|
|
14
28
|
processing: boolean;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
wasSuccessful: boolean;
|
|
30
|
+
recentlySuccessful: boolean;
|
|
31
|
+
progress: UploadProgress | null;
|
|
32
|
+
transportError: Error | null;
|
|
33
|
+
defaults: (...args: [] | [Partial<TData>] | [keyof TData, TData[keyof TData]]) => TData;
|
|
34
|
+
reset: (...fields: (keyof TData)[]) => void;
|
|
35
|
+
resetAndClearErrors: (...fields: (keyof TData)[]) => void;
|
|
36
|
+
post: (operation: string, overrides?: SubmitOverrides) => Promise<IslandResponse | undefined>;
|
|
37
|
+
put: (operation: string, overrides?: SubmitOverrides) => Promise<IslandResponse | undefined>;
|
|
38
|
+
patch: (operation: string, overrides?: SubmitOverrides) => Promise<IslandResponse | undefined>;
|
|
39
|
+
delete: (operation: string, overrides?: SubmitOverrides) => Promise<IslandResponse | undefined>;
|
|
20
40
|
};
|
|
21
41
|
export {};
|
package/dist/useIslandForm.js
CHANGED
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
import { islandFetch } from "@archipelago-js/client";
|
|
2
|
-
import { useCallback, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { useIslandContext } from "./context";
|
|
4
|
-
|
|
4
|
+
function deepClone(value) {
|
|
5
|
+
if (typeof structuredClone === "function") {
|
|
6
|
+
return structuredClone(value);
|
|
7
|
+
}
|
|
8
|
+
return JSON.parse(JSON.stringify(value));
|
|
9
|
+
}
|
|
10
|
+
function isFormDataLike(value) {
|
|
11
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
12
|
+
}
|
|
13
|
+
export function useIslandForm({ initialData, clearFieldErrorsOnChange = true, fixedParams = {}, recentlySuccessfulDuration = 2000, transform, onSuccess, onError, onForbidden, onFinish }) {
|
|
5
14
|
const { component, params, stream, setState } = useIslandContext();
|
|
6
15
|
const [data, setDataState] = useState(initialData);
|
|
7
16
|
const [errors, setErrors] = useState({});
|
|
8
17
|
const [processing, setProcessing] = useState(false);
|
|
18
|
+
const [wasSuccessful, setWasSuccessful] = useState(false);
|
|
19
|
+
const [recentlySuccessful, setRecentlySuccessful] = useState(false);
|
|
20
|
+
const [progress, setProgress] = useState(null);
|
|
21
|
+
const [transportError, setTransportError] = useState(null);
|
|
9
22
|
const requestRef = useRef(null);
|
|
23
|
+
const defaultsRef = useRef(deepClone(initialData));
|
|
24
|
+
const recentlySuccessfulTimerRef = useRef(null);
|
|
25
|
+
const mountedRef = useRef(true);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
mountedRef.current = true;
|
|
28
|
+
return () => {
|
|
29
|
+
mountedRef.current = false;
|
|
30
|
+
if (recentlySuccessfulTimerRef.current) {
|
|
31
|
+
clearTimeout(recentlySuccessfulTimerRef.current);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}, []);
|
|
10
35
|
const setData = useCallback((field, value) => {
|
|
11
36
|
setDataState((previous) => ({
|
|
12
37
|
...previous,
|
|
@@ -23,72 +48,194 @@ export function useIslandForm({ initialData, clearFieldErrorsOnChange = true, fi
|
|
|
23
48
|
});
|
|
24
49
|
}
|
|
25
50
|
}, [clearFieldErrorsOnChange]);
|
|
51
|
+
const clearErrors = useCallback((...fields) => {
|
|
52
|
+
if (fields.length === 0) {
|
|
53
|
+
setErrors({});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
setErrors((previous) => {
|
|
57
|
+
const next = { ...previous };
|
|
58
|
+
for (const field of fields) {
|
|
59
|
+
delete next[field];
|
|
60
|
+
}
|
|
61
|
+
return next;
|
|
62
|
+
});
|
|
63
|
+
}, []);
|
|
64
|
+
const setError = useCallback((field, message) => {
|
|
65
|
+
const messages = Array.isArray(message) ? message : [message];
|
|
66
|
+
setErrors((previous) => ({
|
|
67
|
+
...previous,
|
|
68
|
+
[field]: messages
|
|
69
|
+
}));
|
|
70
|
+
}, []);
|
|
71
|
+
const defaults = useCallback((...args) => {
|
|
72
|
+
if (args.length === 0) {
|
|
73
|
+
return deepClone(defaultsRef.current);
|
|
74
|
+
}
|
|
75
|
+
if (args.length === 1 && typeof args[0] === "object") {
|
|
76
|
+
defaultsRef.current = deepClone({ ...defaultsRef.current, ...args[0] });
|
|
77
|
+
return defaultsRef.current;
|
|
78
|
+
}
|
|
79
|
+
if (args.length === 2) {
|
|
80
|
+
const [field, value] = args;
|
|
81
|
+
defaultsRef.current = deepClone({ ...defaultsRef.current, [field]: value });
|
|
82
|
+
return defaultsRef.current;
|
|
83
|
+
}
|
|
84
|
+
return deepClone(defaultsRef.current);
|
|
85
|
+
}, []);
|
|
86
|
+
const reset = useCallback((...fields) => {
|
|
87
|
+
if (fields.length === 0) {
|
|
88
|
+
setDataState(deepClone(defaultsRef.current));
|
|
89
|
+
setErrors({});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
setDataState((previous) => {
|
|
93
|
+
const next = { ...previous };
|
|
94
|
+
for (const field of fields) {
|
|
95
|
+
if (field in defaultsRef.current) {
|
|
96
|
+
next[field] = deepClone(defaultsRef.current[field]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return next;
|
|
100
|
+
});
|
|
101
|
+
}, []);
|
|
102
|
+
const resetAndClearErrors = useCallback((...fields) => {
|
|
103
|
+
reset(...fields);
|
|
104
|
+
clearErrors(...fields);
|
|
105
|
+
}, [reset, clearErrors]);
|
|
26
106
|
const submit = useCallback(async (method, operation, overrides = {}) => {
|
|
27
107
|
requestRef.current?.controller.abort();
|
|
28
108
|
const controller = new AbortController();
|
|
29
109
|
const requestId = (requestRef.current?.id ?? 0) + 1;
|
|
30
110
|
requestRef.current = { id: requestId, controller };
|
|
31
111
|
setProcessing(true);
|
|
32
|
-
|
|
112
|
+
setWasSuccessful(false);
|
|
113
|
+
setRecentlySuccessful(false);
|
|
114
|
+
setTransportError(null);
|
|
115
|
+
setProgress(null);
|
|
116
|
+
if (recentlySuccessfulTimerRef.current) {
|
|
117
|
+
clearTimeout(recentlySuccessfulTimerRef.current);
|
|
118
|
+
recentlySuccessfulTimerRef.current = null;
|
|
119
|
+
}
|
|
120
|
+
const rawPayload = method === "post" ? data : { ...data, _method: method };
|
|
121
|
+
const payload = transform ? transform(rawPayload) : rawPayload;
|
|
33
122
|
try {
|
|
34
123
|
const response = await islandFetch(component, operation, payload, {
|
|
35
124
|
signal: controller.signal,
|
|
36
125
|
fixedParams: {
|
|
37
126
|
...params,
|
|
38
|
-
...fixedParams
|
|
39
|
-
...(stream ? { __stream: stream } : {})
|
|
127
|
+
...fixedParams
|
|
40
128
|
},
|
|
41
129
|
overridePayload: overrides.payload,
|
|
42
|
-
navigate: overrides.navigate
|
|
130
|
+
navigate: overrides.navigate,
|
|
131
|
+
stream: stream ?? undefined
|
|
43
132
|
});
|
|
44
133
|
if (requestRef.current?.id !== requestId) {
|
|
45
134
|
return response;
|
|
46
135
|
}
|
|
47
136
|
if (response.status === "ok") {
|
|
48
137
|
setErrors({});
|
|
138
|
+
setWasSuccessful(true);
|
|
139
|
+
setRecentlySuccessful(true);
|
|
140
|
+
recentlySuccessfulTimerRef.current = setTimeout(() => {
|
|
141
|
+
if (mountedRef.current) {
|
|
142
|
+
setRecentlySuccessful(false);
|
|
143
|
+
}
|
|
144
|
+
}, recentlySuccessfulDuration);
|
|
49
145
|
setState((previous) => ({
|
|
50
146
|
props: response.props,
|
|
51
147
|
version: typeof response.version === "number" && response.version > previous.version
|
|
52
148
|
? response.version
|
|
53
149
|
: previous.version
|
|
54
150
|
}));
|
|
151
|
+
onSuccess?.(response);
|
|
152
|
+
}
|
|
153
|
+
if (response.status === "redirect") {
|
|
154
|
+
setWasSuccessful(true);
|
|
155
|
+
setRecentlySuccessful(true);
|
|
156
|
+
recentlySuccessfulTimerRef.current = setTimeout(() => {
|
|
157
|
+
if (mountedRef.current) {
|
|
158
|
+
setRecentlySuccessful(false);
|
|
159
|
+
}
|
|
160
|
+
}, recentlySuccessfulDuration);
|
|
161
|
+
onSuccess?.(response);
|
|
55
162
|
}
|
|
56
163
|
if (response.status === "error") {
|
|
57
164
|
setErrors(response.errors);
|
|
165
|
+
onError?.(response);
|
|
58
166
|
}
|
|
59
167
|
if (response.status === "forbidden") {
|
|
60
168
|
setErrors({ _base: ["forbidden"] });
|
|
169
|
+
onForbidden?.(response);
|
|
61
170
|
}
|
|
171
|
+
onFinish?.(response);
|
|
62
172
|
return response;
|
|
63
173
|
}
|
|
64
174
|
catch (error) {
|
|
65
175
|
if (error.name === "AbortError") {
|
|
66
176
|
return undefined;
|
|
67
177
|
}
|
|
68
|
-
|
|
178
|
+
if (requestRef.current?.id === requestId) {
|
|
179
|
+
setTransportError(error instanceof Error ? error : new Error(String(error)));
|
|
180
|
+
}
|
|
181
|
+
onFinish?.(undefined);
|
|
182
|
+
return undefined;
|
|
69
183
|
}
|
|
70
184
|
finally {
|
|
71
185
|
if (requestRef.current?.id === requestId) {
|
|
72
186
|
setProcessing(false);
|
|
187
|
+
setProgress(null);
|
|
73
188
|
}
|
|
74
189
|
}
|
|
75
|
-
}, [
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
190
|
+
}, [
|
|
191
|
+
component,
|
|
192
|
+
data,
|
|
193
|
+
fixedParams,
|
|
194
|
+
onError,
|
|
195
|
+
onFinish,
|
|
196
|
+
onForbidden,
|
|
197
|
+
onSuccess,
|
|
198
|
+
params,
|
|
199
|
+
recentlySuccessfulDuration,
|
|
200
|
+
setState,
|
|
201
|
+
stream,
|
|
202
|
+
transform
|
|
203
|
+
]);
|
|
80
204
|
return useMemo(() => {
|
|
81
205
|
return {
|
|
82
206
|
data,
|
|
83
207
|
setData,
|
|
84
208
|
errors,
|
|
209
|
+
setError,
|
|
210
|
+
clearErrors,
|
|
85
211
|
processing,
|
|
212
|
+
wasSuccessful,
|
|
213
|
+
recentlySuccessful,
|
|
214
|
+
progress,
|
|
215
|
+
transportError,
|
|
216
|
+
defaults,
|
|
217
|
+
reset,
|
|
218
|
+
resetAndClearErrors,
|
|
86
219
|
post: (operation, overrides) => submit("post", operation, overrides),
|
|
87
220
|
put: (operation, overrides) => submit("put", operation, overrides),
|
|
88
221
|
patch: (operation, overrides) => submit("patch", operation, overrides),
|
|
89
|
-
delete: (operation, overrides) => submit("delete", operation, overrides)
|
|
90
|
-
reset
|
|
222
|
+
delete: (operation, overrides) => submit("delete", operation, overrides)
|
|
91
223
|
};
|
|
92
|
-
}, [
|
|
224
|
+
}, [
|
|
225
|
+
clearErrors,
|
|
226
|
+
data,
|
|
227
|
+
defaults,
|
|
228
|
+
errors,
|
|
229
|
+
processing,
|
|
230
|
+
progress,
|
|
231
|
+
recentlySuccessful,
|
|
232
|
+
reset,
|
|
233
|
+
resetAndClearErrors,
|
|
234
|
+
setData,
|
|
235
|
+
setError,
|
|
236
|
+
submit,
|
|
237
|
+
transportError,
|
|
238
|
+
wasSuccessful
|
|
239
|
+
]);
|
|
93
240
|
}
|
|
94
241
|
//# sourceMappingURL=useIslandForm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useIslandForm.js","sourceRoot":"","sources":["../src/useIslandForm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"useIslandForm.js","sourceRoot":"","sources":["../src/useIslandForm.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archipelago-js/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "React bindings for Archipelago islands",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@archipelago-js/client": "^0.
|
|
27
|
+
"@archipelago-js/client": "^0.9.0",
|
|
28
28
|
"react": "^19.0.0",
|
|
29
29
|
"react-dom": "^19.0.0"
|
|
30
30
|
},
|
|
@@ -33,11 +33,10 @@
|
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|
|
36
|
-
"url": "git+https://github.com/
|
|
37
|
-
"directory": "packages/react"
|
|
36
|
+
"url": "git+https://github.com/Catchhook/archipelago-js-react.git"
|
|
38
37
|
},
|
|
39
38
|
"bugs": {
|
|
40
|
-
"url": "https://github.com/
|
|
39
|
+
"url": "https://github.com/Catchhook/archipelago-js-react/issues"
|
|
41
40
|
},
|
|
42
|
-
"homepage": "https://github.com/
|
|
41
|
+
"homepage": "https://github.com/Catchhook/archipelago-js-react"
|
|
43
42
|
}
|