@ohhwells/bridge 0.1.16-next.8 → 0.1.17-next.15
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 +81 -46
- package/dist/index.cjs +2224 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -2
- package/dist/index.d.ts +68 -2
- package/dist/index.js +2208 -129
- package/dist/index.js.map +1 -1
- package/dist/styles.css +753 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ npm install @ohhwells/bridge
|
|
|
30
30
|
In your root layout file, import the bridge stylesheet **once**:
|
|
31
31
|
|
|
32
32
|
```ts
|
|
33
|
-
import
|
|
33
|
+
import "@ohhwells/bridge/styles";
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
### 2. Add the loader surface
|
|
@@ -38,18 +38,20 @@ import '@ohhwells/bridge/styles'
|
|
|
38
38
|
The loader is a full-screen spinner shown while the bridge fetches personalised content. It hides itself once content is ready. Add this **before** your main content in the `<body>`:
|
|
39
39
|
|
|
40
40
|
```tsx
|
|
41
|
-
import { OHW_LOADER_STYLE, OhwLoaderSpinner } from
|
|
41
|
+
import { OHW_LOADER_STYLE, OhwLoaderSpinner } from "@ohhwells/bridge";
|
|
42
42
|
|
|
43
43
|
// Inside <body>:
|
|
44
44
|
<div
|
|
45
45
|
id="ohw-loader"
|
|
46
46
|
suppressHydrationWarning
|
|
47
|
-
style={{ ...OHW_LOADER_STYLE, display:
|
|
47
|
+
style={{ ...OHW_LOADER_STYLE, display: "none" }}
|
|
48
48
|
>
|
|
49
49
|
<OhwLoaderSpinner />
|
|
50
|
-
</div
|
|
50
|
+
</div>;
|
|
51
51
|
|
|
52
|
-
{
|
|
52
|
+
{
|
|
53
|
+
/* Inline script — shows the loader immediately on the client before React hydrates */
|
|
54
|
+
}
|
|
53
55
|
<script
|
|
54
56
|
dangerouslySetInnerHTML={{
|
|
55
57
|
__html: `(function(){try{
|
|
@@ -61,7 +63,7 @@ import { OHW_LOADER_STYLE, OhwLoaderSpinner } from '@ohhwells/bridge'
|
|
|
61
63
|
if(e)e.style.display="flex"
|
|
62
64
|
}catch(e){}})();`,
|
|
63
65
|
}}
|
|
64
|
-
|
|
66
|
+
/>;
|
|
65
67
|
```
|
|
66
68
|
|
|
67
69
|
The inline script detects whether the page is being loaded under a subdomain (personalised content mode) and shows the loader before React has a chance to hydrate, preventing a flash of the default content.
|
|
@@ -71,8 +73,8 @@ The inline script detects whether the page is being loaded under a subdomain (pe
|
|
|
71
73
|
Add `<OhhwellsBridge />` inside a `<Suspense>` boundary in your root layout. It must be in `<Suspense>` because it calls `useSearchParams()` internally.
|
|
72
74
|
|
|
73
75
|
```tsx
|
|
74
|
-
import { Suspense } from
|
|
75
|
-
import { OhhwellsBridge } from
|
|
76
|
+
import { Suspense } from "react";
|
|
77
|
+
import { OhhwellsBridge } from "@ohhwells/bridge";
|
|
76
78
|
|
|
77
79
|
export default function RootLayout({ children }) {
|
|
78
80
|
return (
|
|
@@ -88,7 +90,7 @@ export default function RootLayout({ children }) {
|
|
|
88
90
|
{children}
|
|
89
91
|
</body>
|
|
90
92
|
</html>
|
|
91
|
-
)
|
|
93
|
+
);
|
|
92
94
|
}
|
|
93
95
|
```
|
|
94
96
|
|
|
@@ -97,6 +99,7 @@ The bridge activates automatically when the page is loaded inside the OhhWells c
|
|
|
97
99
|
### 4. Mark sections
|
|
98
100
|
|
|
99
101
|
Every top-level section on each page must have a unique `data-ohw-section` attribute. This is what the canvas editor uses to:
|
|
102
|
+
|
|
100
103
|
- Show the "Add Section" insert line between sections
|
|
101
104
|
- Persist widget insertions (saving which section a widget was inserted after)
|
|
102
105
|
|
|
@@ -113,6 +116,7 @@ Every top-level section on each page must have a unique `data-ohw-section` attri
|
|
|
113
116
|
```
|
|
114
117
|
|
|
115
118
|
**Naming rules:**
|
|
119
|
+
|
|
116
120
|
- Use `kebab-case`
|
|
117
121
|
- Must be unique across the entire page
|
|
118
122
|
- Must be stable — if a section is renamed, any saved widget insertions referencing that name will break
|
|
@@ -129,7 +133,7 @@ export default function HomePage() {
|
|
|
129
133
|
<section data-ohw-section="testimonials">...</section>
|
|
130
134
|
<section data-ohw-section="plan-form">...</section>
|
|
131
135
|
</>
|
|
132
|
-
)
|
|
136
|
+
);
|
|
133
137
|
}
|
|
134
138
|
```
|
|
135
139
|
|
|
@@ -138,39 +142,42 @@ export default function HomePage() {
|
|
|
138
142
|
Add `data-ohw-editable` and `data-ohw-key` to any element the studio owner should be able to edit:
|
|
139
143
|
|
|
140
144
|
```tsx
|
|
141
|
-
{
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
>
|
|
145
|
+
{
|
|
146
|
+
/* Editable rich text (bold, italic, etc.) */
|
|
147
|
+
}
|
|
148
|
+
<h1 data-ohw-editable="text" data-ohw-key="hero-heading">
|
|
146
149
|
Welcome to the studio
|
|
147
|
-
</h1
|
|
150
|
+
</h1>;
|
|
148
151
|
|
|
149
|
-
{
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
>
|
|
152
|
+
{
|
|
153
|
+
/* Editable plain text (no formatting) */
|
|
154
|
+
}
|
|
155
|
+
<p data-ohw-editable="plain" data-ohw-key="hero-subtitle">
|
|
154
156
|
Book your first class
|
|
155
|
-
</p
|
|
157
|
+
</p>;
|
|
156
158
|
|
|
157
|
-
{
|
|
159
|
+
{
|
|
160
|
+
/* Editable image */
|
|
161
|
+
}
|
|
158
162
|
<img
|
|
159
163
|
data-ohw-editable="image"
|
|
160
164
|
data-ohw-key="hero-image"
|
|
161
165
|
src="/hero.jpg"
|
|
162
166
|
alt="Hero"
|
|
163
|
-
|
|
167
|
+
/>;
|
|
164
168
|
|
|
165
|
-
{
|
|
169
|
+
{
|
|
170
|
+
/* Editable background image */
|
|
171
|
+
}
|
|
166
172
|
<div
|
|
167
173
|
data-ohw-editable="bg-image"
|
|
168
174
|
data-ohw-key="hero-bg"
|
|
169
|
-
style={{ backgroundImage:
|
|
170
|
-
|
|
175
|
+
style={{ backgroundImage: "url(/bg.jpg)" }}
|
|
176
|
+
/>;
|
|
171
177
|
```
|
|
172
178
|
|
|
173
179
|
**Key naming rules:**
|
|
180
|
+
|
|
174
181
|
- Must be globally unique across all pages
|
|
175
182
|
- Use `kebab-case`
|
|
176
183
|
- Must be stable — changing a key orphans any saved content for that element
|
|
@@ -186,15 +193,9 @@ For elements with multiple display states (e.g. a contact form with default/succ
|
|
|
186
193
|
data-ohw-editable-state="default,success,error"
|
|
187
194
|
data-ohw-key="contact-form"
|
|
188
195
|
>
|
|
189
|
-
<div data-ohw-state-view="default">
|
|
190
|
-
|
|
191
|
-
</div>
|
|
192
|
-
<div data-ohw-state-view="success">
|
|
193
|
-
{/* success message */}
|
|
194
|
-
</div>
|
|
195
|
-
<div data-ohw-state-view="error">
|
|
196
|
-
{/* error message */}
|
|
197
|
-
</div>
|
|
196
|
+
<div data-ohw-state-view="default">{/* default form UI */}</div>
|
|
197
|
+
<div data-ohw-state-view="success">{/* success message */}</div>
|
|
198
|
+
<div data-ohw-state-view="error">{/* error message */}</div>
|
|
198
199
|
</div>
|
|
199
200
|
```
|
|
200
201
|
|
|
@@ -240,23 +241,57 @@ npm publish --access public
|
|
|
240
241
|
|
|
241
242
|
---
|
|
242
243
|
|
|
244
|
+
## Link popover (Canvas Editor)
|
|
245
|
+
|
|
246
|
+
`LinkPopover` is rendered inside `OhhwellsBridge` (iframe portal) when editing link destinations. It implements the Figma shadcn kit panel (nodes 8365-7616 / 8382-4161) — anchored popover, not a centered dialog.
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
// Used internally by OhhwellsBridge — external consumers rarely mount this directly.
|
|
250
|
+
import { LinkPopover } from "@ohhwells/bridge";
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The iframe bridge reports page sections on `ow:ready`:
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
{ "type": "ow:ready", "version": "1", "nodes": [...], "sections": [{ "id": "hero", "label": "Hero" }] }
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Templates must mark sections with `data-ohw-section` (and optional `data-ohw-section-label`).
|
|
260
|
+
|
|
261
|
+
### Local link-editor testing (dev fixtures)
|
|
262
|
+
|
|
263
|
+
Without the canvas editor parent, add `ohw-fixtures=1` to the edit URL. This preloads Re:Bound pages and sections into the link popover:
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
http://localhost:3000 /?mode=edit&ohw-fixtures=1
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
1. Click a nav link label (e.g. **Pricing**) → toolbar → chain icon
|
|
270
|
+
2. Pick **About** in Destination → **Choose a section** → **Personal training**
|
|
271
|
+
3. **Save** — href becomes `/about#personal-training`
|
|
272
|
+
4. Open `http://localhost:3001/about#personal-training` (without `mode=edit`) to verify scroll
|
|
273
|
+
|
|
274
|
+
In edit mode link clicks are blocked; check `href` in DevTools or test on a normal page load.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
243
278
|
## Design tokens
|
|
244
279
|
|
|
245
280
|
The package ships the full OhhWells design token set, scoped to `[data-ohw-bridge-root]` so styles never leak into the host template.
|
|
246
281
|
|
|
247
282
|
### Semantic colors (CSS variables on `[data-ohw-bridge-root]`)
|
|
248
283
|
|
|
249
|
-
| Token
|
|
250
|
-
|
|
251
|
-
| `primary`
|
|
284
|
+
| Token | Light | Dark |
|
|
285
|
+
| -------------------- | --------- | --------- |
|
|
286
|
+
| `primary` | `#0f172a` | `#f8fafc` |
|
|
252
287
|
| `primary-foreground` | `#f8fafc` | `#0f172a` |
|
|
253
|
-
| `background`
|
|
254
|
-
| `foreground`
|
|
255
|
-
| `muted`
|
|
256
|
-
| `muted-foreground`
|
|
257
|
-
| `border`
|
|
258
|
-
| `destructive`
|
|
259
|
-
| `success`
|
|
288
|
+
| `background` | `#ffffff` | `#020617` |
|
|
289
|
+
| `foreground` | `#020617` | `#f8fafc` |
|
|
290
|
+
| `muted` | `#f1f5f9` | `#1e293b` |
|
|
291
|
+
| `muted-foreground` | `#64748b` | `#94a3b8` |
|
|
292
|
+
| `border` | `#e2e8f0` | `#334155` |
|
|
293
|
+
| `destructive` | `#dc2626` | `#7f1d1d` |
|
|
294
|
+
| `success` | `#16a34a` | `#22c55e` |
|
|
260
295
|
|
|
261
296
|
### Brand palette
|
|
262
297
|
|