@connextar/house 0.1.1 → 0.3.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 +286 -28
- package/dist/changelog/changelog.d.ts +60 -0
- package/dist/changelog/changelog.d.ts.map +1 -0
- package/dist/changelog/changelog.js +61 -0
- package/dist/changelog/changelog.js.map +1 -0
- package/dist/changelog/index.d.ts +2 -0
- package/dist/changelog/index.d.ts.map +1 -0
- package/dist/changelog/index.js +2 -0
- package/dist/changelog/index.js.map +1 -0
- package/dist/editor/block-handle.d.ts +15 -0
- package/dist/editor/block-handle.d.ts.map +1 -0
- package/dist/editor/block-handle.js +106 -0
- package/dist/editor/block-handle.js.map +1 -0
- package/dist/editor/blocks.d.ts +35 -0
- package/dist/editor/blocks.d.ts.map +1 -0
- package/dist/editor/blocks.js +114 -0
- package/dist/editor/blocks.js.map +1 -0
- package/dist/editor/bubble-toolbar.d.ts +11 -0
- package/dist/editor/bubble-toolbar.d.ts.map +1 -0
- package/dist/editor/bubble-toolbar.js +87 -0
- package/dist/editor/bubble-toolbar.js.map +1 -0
- package/dist/editor/content-index.d.ts +2 -0
- package/dist/editor/content-index.d.ts.map +1 -0
- package/dist/editor/content-index.js +2 -0
- package/dist/editor/content-index.js.map +1 -0
- package/dist/editor/content.d.ts +30 -0
- package/dist/editor/content.d.ts.map +1 -0
- package/dist/editor/content.js +256 -0
- package/dist/editor/content.js.map +1 -0
- package/dist/editor/editor.d.ts +52 -0
- package/dist/editor/editor.d.ts.map +1 -0
- package/dist/editor/editor.js +160 -0
- package/dist/editor/editor.js.map +1 -0
- package/dist/editor/emoji-index.d.ts +2 -0
- package/dist/editor/emoji-index.d.ts.map +1 -0
- package/dist/editor/emoji-index.js +2 -0
- package/dist/editor/emoji-index.js.map +1 -0
- package/dist/editor/emoji-picker.d.ts +16 -0
- package/dist/editor/emoji-picker.d.ts.map +1 -0
- package/dist/editor/emoji-picker.js +37 -0
- package/dist/editor/emoji-picker.js.map +1 -0
- package/dist/editor/emoji.d.ts +18 -0
- package/dist/editor/emoji.d.ts.map +1 -0
- package/dist/editor/emoji.js +418 -0
- package/dist/editor/emoji.js.map +1 -0
- package/dist/editor/index.d.ts +5 -0
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/index.js +6 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/editor/suggestion-popup.d.ts +17 -0
- package/dist/editor/suggestion-popup.d.ts.map +1 -0
- package/dist/editor/suggestion-popup.js +57 -0
- package/dist/editor/suggestion-popup.js.map +1 -0
- package/dist/editor/suggestions.d.ts +93 -0
- package/dist/editor/suggestions.d.ts.map +1 -0
- package/dist/editor/suggestions.js +179 -0
- package/dist/editor/suggestions.js.map +1 -0
- package/dist/editor/ui.d.ts +54 -0
- package/dist/editor/ui.d.ts.map +1 -0
- package/dist/editor/ui.js +58 -0
- package/dist/editor/ui.js.map +1 -0
- package/dist/house.css +333 -0
- package/dist/internal/cx.d.ts +3 -0
- package/dist/internal/cx.d.ts.map +1 -0
- package/dist/internal/cx.js +5 -0
- package/dist/internal/cx.js.map +1 -0
- package/dist/internal/next-link.d.ts +23 -0
- package/dist/internal/next-link.d.ts.map +1 -0
- package/dist/internal/next-link.js +3 -0
- package/dist/internal/next-link.js.map +1 -0
- package/dist/markdown/guide.d.ts +98 -0
- package/dist/markdown/guide.d.ts.map +1 -0
- package/dist/markdown/guide.js +328 -0
- package/dist/markdown/guide.js.map +1 -0
- package/dist/markdown/index.d.ts +4 -0
- package/dist/markdown/index.d.ts.map +1 -0
- package/dist/markdown/index.js +4 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/markdown/table-view.d.ts +28 -0
- package/dist/markdown/table-view.d.ts.map +1 -0
- package/dist/markdown/table-view.js +25 -0
- package/dist/markdown/table-view.js.map +1 -0
- package/dist/markdown/table.d.ts +35 -0
- package/dist/markdown/table.d.ts.map +1 -0
- package/dist/markdown/table.js +79 -0
- package/dist/markdown/table.js.map +1 -0
- package/dist/release/changelog.d.ts +72 -0
- package/dist/release/changelog.d.ts.map +1 -0
- package/dist/release/changelog.js +92 -0
- package/dist/release/changelog.js.map +1 -0
- package/dist/release/index.d.ts +3 -0
- package/dist/release/index.d.ts.map +1 -0
- package/dist/release/index.js +3 -0
- package/dist/release/index.js.map +1 -0
- package/dist/release/version.d.ts +33 -0
- package/dist/release/version.d.ts.map +1 -0
- package/dist/release/version.js +57 -0
- package/dist/release/version.js.map +1 -0
- package/dist/trail/index.d.ts +3 -0
- package/dist/trail/index.d.ts.map +1 -0
- package/dist/trail/index.js +3 -0
- package/dist/trail/index.js.map +1 -0
- package/dist/trail/rules.d.ts +44 -0
- package/dist/trail/rules.d.ts.map +1 -0
- package/dist/trail/rules.js +74 -0
- package/dist/trail/rules.js.map +1 -0
- package/dist/trail/trail.d.ts +49 -0
- package/dist/trail/trail.d.ts.map +1 -0
- package/dist/trail/trail.js +188 -0
- package/dist/trail/trail.js.map +1 -0
- package/dist/ux/errors.d.ts +26 -0
- package/dist/ux/errors.d.ts.map +1 -0
- package/dist/ux/errors.js +33 -0
- package/dist/ux/errors.js.map +1 -0
- package/dist/ux/feedback.d.ts +23 -0
- package/dist/ux/feedback.d.ts.map +1 -0
- package/dist/ux/feedback.js +22 -0
- package/dist/ux/feedback.js.map +1 -0
- package/dist/ux/index.d.ts +20 -0
- package/dist/ux/index.d.ts.map +1 -0
- package/dist/ux/index.js +20 -0
- package/dist/ux/index.js.map +1 -0
- package/dist/ux/navigation-index.d.ts +10 -0
- package/dist/ux/navigation-index.d.ts.map +1 -0
- package/dist/ux/navigation-index.js +10 -0
- package/dist/ux/navigation-index.js.map +1 -0
- package/dist/ux/navigation-progress.d.ts +53 -0
- package/dist/ux/navigation-progress.d.ts.map +1 -0
- package/dist/ux/navigation-progress.js +245 -0
- package/dist/ux/navigation-progress.js.map +1 -0
- package/dist/ux/optimistic.d.ts +139 -0
- package/dist/ux/optimistic.d.ts.map +1 -0
- package/dist/ux/optimistic.js +242 -0
- package/dist/ux/optimistic.js.map +1 -0
- package/dist/ux/use-action.d.ts +60 -0
- package/dist/ux/use-action.d.ts.map +1 -0
- package/dist/ux/use-action.js +100 -0
- package/dist/ux/use-action.js.map +1 -0
- package/dist/ux/use-optimistic-list.d.ts +69 -0
- package/dist/ux/use-optimistic-list.d.ts.map +1 -0
- package/dist/ux/use-optimistic-list.js +115 -0
- package/dist/ux/use-optimistic-list.js.map +1 -0
- package/dist/ux/use-optimistic-value.d.ts +40 -0
- package/dist/ux/use-optimistic-value.d.ts.map +1 -0
- package/dist/ux/use-optimistic-value.js +68 -0
- package/dist/ux/use-optimistic-value.js.map +1 -0
- package/docs/ReleaseProcess.md +315 -0
- package/package.json +83 -11
package/README.md
CHANGED
|
@@ -12,16 +12,16 @@ small, and the reason it is small is worth reading before adding to it.
|
|
|
12
12
|
The portfolio was measured before anything was extracted. Divergence, against
|
|
13
13
|
Quickie, of files that exist in six or more apps:
|
|
14
14
|
|
|
15
|
-
| File
|
|
16
|
-
|
|
|
17
|
-
| `error-shell.tsx`
|
|
18
|
-
| `check-motion.mjs` | 3/6
|
|
19
|
-
| `e2e-local.sh`
|
|
20
|
-
| `button.tsx`
|
|
21
|
-
| `dialog.tsx`
|
|
22
|
-
| `card.tsx`
|
|
23
|
-
| `lib/api.ts`
|
|
24
|
-
| `auth.ts`
|
|
15
|
+
| File | copies | divergence |
|
|
16
|
+
| ------------------ | ------ | ---------- |
|
|
17
|
+
| `error-shell.tsx` | 6/6 | **0%** |
|
|
18
|
+
| `check-motion.mjs` | 3/6 | 11% |
|
|
19
|
+
| `e2e-local.sh` | 6/6 | 30% |
|
|
20
|
+
| `button.tsx` | 6/6 | 42% |
|
|
21
|
+
| `dialog.tsx` | 5/6 | 62% |
|
|
22
|
+
| `card.tsx` | 5/6 | 106% |
|
|
23
|
+
| `lib/api.ts` | 6/6 | 152% |
|
|
24
|
+
| `auth.ts` | 4/6 | 42–103% |
|
|
25
25
|
|
|
26
26
|
Everything below about 15% is an extraction. Everything above it is a rewrite
|
|
27
27
|
wearing an extraction's clothes, and pulling it in here would mean thirteen apps
|
|
@@ -35,6 +35,18 @@ That is why there is no `Button` here, and why the error shell takes its actions
|
|
|
35
35
|
as props instead of rendering its own. Bringing a second design system into an
|
|
36
36
|
app that already has one is a cost with no matching benefit.
|
|
37
37
|
|
|
38
|
+
The 0.2.0 modules are the second half of that rule. AltEd built a versioned
|
|
39
|
+
changelog, a navigation trail, a block editor and guide tables; every other app
|
|
40
|
+
was about to write each of them for the second time.
|
|
41
|
+
|
|
42
|
+
`ux`, in 0.3.0, is the clearest case of that clause yet. Every app in the
|
|
43
|
+
portfolio writes over `fetch` and refreshes afterwards, so every one of them has
|
|
44
|
+
the same dead-click problem — a tick that goes nowhere for half a second, a
|
|
45
|
+
button that looks broken while working perfectly — and none of them had solved
|
|
46
|
+
it. It is also the kind of code nobody should write twice: the rules about when
|
|
47
|
+
to let go of an optimistic change are small, subtle and easy to get quietly
|
|
48
|
+
wrong.
|
|
49
|
+
|
|
38
50
|
## Modules
|
|
39
51
|
|
|
40
52
|
### `@connextar/house/errors`
|
|
@@ -79,7 +91,7 @@ decorative: a stolen mailbox is still enough.
|
|
|
79
91
|
|
|
80
92
|
This module decides which routes to refuse, and why. It is here rather than in
|
|
81
93
|
each app because it has to be the same everywhere and because getting it wrong is
|
|
82
|
-
silent — two-factor keeps
|
|
94
|
+
silent — two-factor keeps _looking_ enabled while doing nothing.
|
|
83
95
|
|
|
84
96
|
The lookup is injected, because only the app knows its own user table:
|
|
85
97
|
|
|
@@ -100,7 +112,7 @@ TOTP. A link in an inbox is.
|
|
|
100
112
|
### `@connextar/house/account`
|
|
101
113
|
|
|
102
114
|
The contract for "your data" and "delete my account" — types, the export notice,
|
|
103
|
-
and the sole-owner refusal message. The
|
|
115
|
+
and the sole-owner refusal message. The _implementation_ stays per-app, because
|
|
104
116
|
an export is a walk over that app's Prisma schema. What must not be per-app is
|
|
105
117
|
the shape of the answer, since that is what a person receives and a regulator
|
|
106
118
|
reads.
|
|
@@ -119,9 +131,234 @@ Two decisions are encoded here rather than left to be rediscovered:
|
|
|
119
131
|
App-specific sections go in `extras`, so one app's furniture does not become
|
|
120
132
|
everyone's obligation.
|
|
121
133
|
|
|
134
|
+
### `@connextar/house/release`
|
|
135
|
+
|
|
136
|
+
Version arithmetic and the release-history guard behind every app's changelog.
|
|
137
|
+
`releaseHistoryProblems(changelog, { pkg, lock })` returns, as sentences, every
|
|
138
|
+
way the changelog, `package.json` and the lockfile disagree — a version that
|
|
139
|
+
skips a step, dates out of order, a release with no title. An app's
|
|
140
|
+
`lib/release.test.ts` asserts it is empty. `nextVersion(current, kind)` applies
|
|
141
|
+
the 0.x rule (a MAJOR-class change bumps the minor before 1.0.0).
|
|
142
|
+
|
|
143
|
+
The process itself — how to classify a change, how to write the notes, the
|
|
144
|
+
runbook — is [`docs/ReleaseProcess.md`](docs/ReleaseProcess.md), shipped in the
|
|
145
|
+
package. Each app's own `docs/operations/ReleaseProcess.md` links to it and adds
|
|
146
|
+
only what is its own: its public API, its trigger documents, its history note.
|
|
147
|
+
|
|
148
|
+
### `@connextar/house/changelog`
|
|
149
|
+
|
|
150
|
+
`<Changelog releases={CHANGELOG} />` — the body of a `/changelog` page. Each
|
|
151
|
+
release shows its version, whether it was a major, minor or patch release, its
|
|
152
|
+
date and a one-line summary; changes are grouped under headings, each with a bold
|
|
153
|
+
headline and a tag. A list of releases sits beside the content on wide screens
|
|
154
|
+
and becomes a scrolling strip on a phone. The app keeps its hero and calls to
|
|
155
|
+
action around it, and maps the four change types onto its palette with
|
|
156
|
+
`tagClassNames`.
|
|
157
|
+
|
|
158
|
+
### `@connextar/house/markdown`
|
|
159
|
+
|
|
160
|
+
The help-centre guide renderer, and the GitHub-flavoured table parser under it.
|
|
161
|
+
Five apps carried a copy that had drifted: some rendered tables as a paragraph of
|
|
162
|
+
pipes, some broke a wrapped list line into a stray paragraph, some passed
|
|
163
|
+
`javascript:` links through, and three let an `####` heading shift the numbering
|
|
164
|
+
of the `##` anchors after it. `GuideMarkdown` is the union of the fixes;
|
|
165
|
+
`extractHeadings` gives exactly the ids it renders.
|
|
166
|
+
|
|
167
|
+
An app's `lib/markdown.tsx` becomes a thin binding that keeps its own export names,
|
|
168
|
+
so no page changes:
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
import { GuideMarkdown } from "@connextar/house/markdown";
|
|
172
|
+
|
|
173
|
+
import { constants } from "@lib/constants";
|
|
174
|
+
|
|
175
|
+
export {
|
|
176
|
+
extractHeadings as extractGuideHeadings,
|
|
177
|
+
extractHowToSteps,
|
|
178
|
+
parseGuideFrontmatter,
|
|
179
|
+
stripInline,
|
|
180
|
+
} from "@connextar/house/markdown";
|
|
181
|
+
|
|
182
|
+
export function Markdown({ content }: { content: string }) {
|
|
183
|
+
return <GuideMarkdown content={content} guidesPath={constants.routes.guides} />;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`classNames` replaces the look of any element for an app without theme tokens.
|
|
188
|
+
|
|
189
|
+
### `@connextar/house/trail`
|
|
190
|
+
|
|
191
|
+
Where you came from, rather than where the URL says you are. A breadcrumb built
|
|
192
|
+
from the path can only show the hierarchy the routes happen to have; a trail
|
|
193
|
+
shows the chain the person actually walked — a learner, then their plan, then a
|
|
194
|
+
lesson — and keeps it when they follow a reference to somewhere else.
|
|
195
|
+
|
|
196
|
+
Pages declare their chain (`useTrail(chain)` or `<TrailHere chain={…} />`); the
|
|
197
|
+
trail lives per tab in session storage under a `scope`; a link marked
|
|
198
|
+
`data-trail-carry` (every internal link in `RichTextContent`) carries it across.
|
|
199
|
+
`<TrailRail />` draws it as pills down the left on wide screens, `<TrailBar />` as
|
|
200
|
+
a pinned bar with Back on phones.
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
// components/navigation/dashboard-shell.tsx
|
|
204
|
+
"use client";
|
|
205
|
+
import { ScrollToHash, TrailBar, TrailProvider, TrailRail } from "@connextar/house/trail";
|
|
206
|
+
|
|
207
|
+
// `scope` keeps one signed-in person's trail from surfacing for the next on a shared browser.
|
|
208
|
+
export function DashboardShell({ userId, children }: { userId: string; children: React.ReactNode }) {
|
|
209
|
+
return (
|
|
210
|
+
<TrailProvider scope={userId}>
|
|
211
|
+
<ScrollToHash />
|
|
212
|
+
<div className="flex">
|
|
213
|
+
<TrailRail top="4rem" />
|
|
214
|
+
<main className="min-w-0 flex-1">
|
|
215
|
+
<TrailBar top="4rem" />
|
|
216
|
+
{children}
|
|
217
|
+
</main>
|
|
218
|
+
</div>
|
|
219
|
+
</TrailProvider>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### `@connextar/house/editor`, `/editor/content`, `/editor/emoji`
|
|
225
|
+
|
|
226
|
+
`RichTextEditor` — Notion-style writing for any prose field. Formatting appears
|
|
227
|
+
as a bubble over a selection (with Turn into); new blocks come from typing `/` or
|
|
228
|
+
the `+` beside a block; every block has a grip to drag or open its menu (turn
|
|
229
|
+
into, duplicate, move up, move down, delete); `:` completes an emoji shortcode.
|
|
230
|
+
`@` references and `#` tags work when the app passes `sources`, because only the
|
|
231
|
+
app knows what its people, records and tags are. **Storage is plain Markdown with
|
|
232
|
+
no new node types** — a reference is `[@Ann Lee](/people/1)` — so every existing
|
|
233
|
+
text column keeps working and a server can read mentions with a regex.
|
|
234
|
+
|
|
235
|
+
`RichTextContent` (from `/editor/content`) is the read-only side: Markdown to
|
|
236
|
+
React with no HTML, an allow-list of link schemes, and bounded patterns, safe for
|
|
237
|
+
text a stranger wrote. `EmojiPicker` and the curated set of ~360 emoji are in
|
|
238
|
+
`/editor` and `/editor/emoji`.
|
|
239
|
+
|
|
240
|
+
The editor draws its own menus and popovers on Radix with the house token
|
|
241
|
+
classes. They are internal and not exported: the apps' primitive sets differ too
|
|
242
|
+
much for the editor to ask for theirs, and this is not a second design system.
|
|
243
|
+
|
|
244
|
+
If an app also depends on `@tiptap/*` directly, keep it in the same range as this
|
|
245
|
+
package so npm installs one copy. Two copies of `@tiptap/pm` break the editor.
|
|
246
|
+
|
|
247
|
+
### `@connextar/house/ux`
|
|
248
|
+
|
|
249
|
+
The interface answers the click: optimistic updates, pending state, and
|
|
250
|
+
navigation feedback. Headless — no components, no design system, no toast
|
|
251
|
+
library, no HTTP client.
|
|
252
|
+
|
|
253
|
+
`useOptimisticList(rows, { key })` holds the server's rows as a _base_ and every
|
|
254
|
+
change as a _patch_ beside them, folded in on render. `insert`, `update`,
|
|
255
|
+
`remove`, `move` and `bulk` each take a commit function; `isPending(key)` marks
|
|
256
|
+
one row without disabling the table. `useOptimisticValue` is the same for a
|
|
257
|
+
switch, a status or a settings record; `useAction` and `useKeyedAction` are for
|
|
258
|
+
work that should not be guessed at — a payment, a model call, a sign-in — and
|
|
259
|
+
give a control the `pending` flag it needs and nothing more.
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
const tasks = useOptimisticList(rows, { key: (t) => t.id, onSettled: router.refresh });
|
|
263
|
+
|
|
264
|
+
tasks.update(task.id, { done: true }, () => save(task.id, { done: true }));
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Why not `useOptimistic`.** React 19's hook is right when the write _is_ the
|
|
268
|
+
transition — a server action. It is wrong for an app that writes over `fetch` and
|
|
269
|
+
then calls `router.refresh()`, because `router.refresh()` is not awaitable: the
|
|
270
|
+
transition ends before the new rows arrive and the optimistic value snaps back to
|
|
271
|
+
the stale one, flashing the old answer on every single write.
|
|
272
|
+
|
|
273
|
+
**When a change is let go of.** A patch is `pending` while its write is in
|
|
274
|
+
flight, then dropped (it failed — the base alone is the truth again) or `settled`
|
|
275
|
+
(it landed, and keeps being applied, because the base is still the _old_ rows
|
|
276
|
+
until a refresh arrives). A settled patch goes when fresh rows account for it:
|
|
277
|
+
either they agree, or they disagree with what they said when the write landed, in
|
|
278
|
+
which case they win and the screen corrects itself. Evidence, never a timer — a
|
|
279
|
+
screen that does not refetch has no truth to fall back to, and snapping to stale
|
|
280
|
+
rows after N seconds is a bug that only appears on a slow connection.
|
|
281
|
+
|
|
282
|
+
**The three seams that keep it portable.** A commit is
|
|
283
|
+
`() => Promise<Row | void>` that **throws** on failure, which is the one failure
|
|
284
|
+
contract every client already has; an app whose client returns a result object
|
|
285
|
+
wraps it once. Failures are reported to an `ActionFeedbackProvider` as
|
|
286
|
+
`{ tone, title, description }`, so the app decides what a message looks like.
|
|
287
|
+
And `NavigationProgress` takes a `className` for its bar, so it never needs a
|
|
288
|
+
token.
|
|
289
|
+
|
|
290
|
+
`NavigationProgress` (from `@connextar/house/ux/navigation` — its own entry
|
|
291
|
+
point, so `next` stays an optional peer) also marks the link that was clicked
|
|
292
|
+
with `data-busy`, which `house.css` turns into a spinner. Two notes on it, both
|
|
293
|
+
learned the hard way:
|
|
294
|
+
|
|
295
|
+
- Its click listener is in the **capture** phase, and deliberately does not check
|
|
296
|
+
`defaultPrevented`. Next's `Link` cancels the click on its way to a
|
|
297
|
+
client-side navigation, so a bubble-phase listener guarding on
|
|
298
|
+
`defaultPrevented` fires for every link _except_ the app's own — which is
|
|
299
|
+
precisely backwards, and is what AltEd shipped unnoticed until it was measured
|
|
300
|
+
in a browser.
|
|
301
|
+
- `useAppRouter()` is `useRouter()` with the same feedback on `push` and
|
|
302
|
+
`replace`. Swapping the import is the whole change; no call site moves.
|
|
303
|
+
|
|
304
|
+
**Not everything should be optimistic.** Money, model calls, sign-in, imports and
|
|
305
|
+
exports: anything whose result the person cannot predict, or would be alarmed to
|
|
306
|
+
see undone. Guessing is only honest when the guess is nearly always right.
|
|
307
|
+
|
|
308
|
+
### Styles — `@connextar/house/house.css`
|
|
309
|
+
|
|
310
|
+
What the components need that utility classes cannot say: rich text, the editor's
|
|
311
|
+
block gutter and suggestion highlight, the trail's tinted pills, and the busy
|
|
312
|
+
spinner `ux` puts on whatever was clicked.
|
|
313
|
+
|
|
314
|
+
The spinner is `[data-busy="true"]::after`, drawn in `currentColor` with no theme
|
|
315
|
+
token. A control that renders its own spinner marks it `.house-spinner` so it
|
|
316
|
+
does not end up with two. For `prefers-reduced-motion` the ring stays and stops
|
|
317
|
+
turning, rather than disappearing — it is the only thing on screen saying the
|
|
318
|
+
click was heard.
|
|
319
|
+
|
|
320
|
+
## Tailwind setup (required for every component)
|
|
321
|
+
|
|
322
|
+
Tailwind does not scan `node_modules`. Every utility class that appears only
|
|
323
|
+
inside this package is silently missing from an app's build unless the app
|
|
324
|
+
points Tailwind at it. This was measured, not assumed: a probe compile of an
|
|
325
|
+
app's stylesheet emitted none of the package's classes until the line below was
|
|
326
|
+
added.
|
|
327
|
+
|
|
328
|
+
**Tailwind v4** — in the global stylesheet:
|
|
329
|
+
|
|
330
|
+
```css
|
|
331
|
+
@import "tailwindcss";
|
|
332
|
+
@import "@connextar/house/house.css";
|
|
333
|
+
@source "../node_modules/@connextar/house/dist";
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
(The `@source` path is relative to the stylesheet.)
|
|
337
|
+
|
|
338
|
+
**Tailwind v3** — add `"./node_modules/@connextar/house/dist/**/*.js"` to
|
|
339
|
+
`content` in `tailwind.config`, and import `@connextar/house/house.css` at the top
|
|
340
|
+
of the global stylesheet, before the `@tailwind` directives.
|
|
341
|
+
|
|
342
|
+
`house.css` reads the app's theme tokens (`--foreground`, `--muted-foreground`,
|
|
343
|
+
`--primary`, `--muted`, `--border`, `--card`, `--accent`) through a `--house-*`
|
|
344
|
+
variable at each use. An app that stores tokens as HSL triplets
|
|
345
|
+
(`--primary: 222 47% 11%`) maps them once:
|
|
346
|
+
|
|
347
|
+
```css
|
|
348
|
+
:root {
|
|
349
|
+
--house-foreground: hsl(var(--foreground));
|
|
350
|
+
--house-muted-foreground: hsl(var(--muted-foreground));
|
|
351
|
+
--house-primary: hsl(var(--primary));
|
|
352
|
+
--house-muted: hsl(var(--muted));
|
|
353
|
+
--house-border: hsl(var(--border));
|
|
354
|
+
--house-card: hsl(var(--card));
|
|
355
|
+
--house-accent: hsl(var(--accent));
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
122
359
|
## Publishing
|
|
123
360
|
|
|
124
|
-
The scope is public and the contents are
|
|
361
|
+
The scope is public and the contents are shared components and policy modules —
|
|
125
362
|
nothing here is a secret. Public publishing is what keeps thirteen repositories
|
|
126
363
|
across two GitHub owners able to install it with no token in any Vercel project,
|
|
127
364
|
which is the failure mode that would otherwise take every deploy down at once.
|
|
@@ -136,24 +373,45 @@ npm publish # publishConfig.access is already "public"
|
|
|
136
373
|
|
|
137
374
|
## Adopting it in an app
|
|
138
375
|
|
|
139
|
-
Once published:
|
|
140
|
-
|
|
141
376
|
```bash
|
|
142
377
|
npm install @connextar/house
|
|
143
378
|
```
|
|
144
379
|
|
|
145
|
-
Then
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
380
|
+
Then, per module the app takes up:
|
|
381
|
+
|
|
382
|
+
1. **Tailwind first.** Add the `@source` line (or the v3 `content` glob) from
|
|
383
|
+
[Tailwind setup](#tailwind-setup-required-for-every-component). Without it the
|
|
384
|
+
components render unstyled and nothing errors.
|
|
385
|
+
2. **Replace the local copy with a binding, not a rewrite of its callers.** The
|
|
386
|
+
app's `lib/markdown.tsx`, `components/editor/rich-text-editor.tsx` or
|
|
387
|
+
`lib/changelog.ts` stays where its importers expect it and shrinks to the
|
|
388
|
+
app's own part: its routes, its type scale, its `@` and `#` lookups, its data.
|
|
389
|
+
A binding that grows past a screen is the package being re-implemented.
|
|
390
|
+
3. **Move the tests with the code.** A local test of behaviour the package now
|
|
391
|
+
owns is deleted; a test of the app's binding stays.
|
|
392
|
+
4. **Changelog and releases** follow [`docs/ReleaseProcess.md`](docs/ReleaseProcess.md)
|
|
393
|
+
§7: the old entries become numbered releases once, `lib/release.test.ts` guards
|
|
394
|
+
them from then on, and the app's own `docs/operations/ReleaseProcess.md` says
|
|
395
|
+
only what is its own.
|
|
396
|
+
5. **Gates, then the pages.** `npm run check`, `npm test`, `npm run build`, and
|
|
397
|
+
grep the built CSS for a class that only the package uses — the one check that
|
|
398
|
+
proves step 1.
|
|
399
|
+
|
|
400
|
+
Traps found adopting it the first time:
|
|
401
|
+
|
|
402
|
+
- A **server component** receives a client module as a reference that throws on
|
|
403
|
+
any property access. Never dot into an import from a client module in shared
|
|
404
|
+
code; the package's own `next/link` helper is a type-only cast for this reason.
|
|
405
|
+
- Next writes route types under `.next/dev/types` during `next dev`. After routes
|
|
406
|
+
are deleted, a stale copy fails `next build`'s type check with "Cannot find
|
|
407
|
+
module"; delete `.next/dev` when no dev server is running.
|
|
408
|
+
- If the app also depends on `@tiptap/*` directly, keep the range aligned or drop
|
|
409
|
+
the direct dependency — two copies of `@tiptap/pm` break the editor.
|
|
410
|
+
- **Jest** (with `next/jest`) does not transform `node_modules`, and this package is
|
|
411
|
+
ESM, so the first import fails with `Unexpected token 'export'`. `next/jest` only
|
|
412
|
+
appends to `transformIgnorePatterns`, so export an async config that rewrites each
|
|
413
|
+
`/node_modules/(?!` rule to `/node_modules/(?!@connextar/house/)(?!`. Vitest needs
|
|
414
|
+
nothing.
|
|
157
415
|
|
|
158
416
|
**A note on local development.** Installing this with `npm install ../path` makes
|
|
159
417
|
a symlink, and Next's Turbopack will not resolve a package whose real path is
|
|
@@ -163,7 +421,7 @@ behaves exactly like a registry install:
|
|
|
163
421
|
|
|
164
422
|
```bash
|
|
165
423
|
npm pack --pack-destination /tmp # in this repo
|
|
166
|
-
npm install /tmp/connextar-house-0.
|
|
424
|
+
npm install /tmp/connextar-house-0.2.0.tgz # in the app
|
|
167
425
|
```
|
|
168
426
|
|
|
169
427
|
## Adding to it
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type ChangeType, type ChangelogRelease } from "../release/changelog.js";
|
|
3
|
+
import { type ReleaseKind } from "../release/version.js";
|
|
4
|
+
/**
|
|
5
|
+
* The body of a /changelog page: an index of releases beside the releases
|
|
6
|
+
* themselves.
|
|
7
|
+
*
|
|
8
|
+
* Each release shows its version, whether it is a major, minor or patch
|
|
9
|
+
* release, and its date, then a headline and a one-sentence summary. Changes
|
|
10
|
+
* sit under the product-area headings they were grouped by, each with a tag
|
|
11
|
+
* and a bold headline. The index is a sticky rail on wide screens and a
|
|
12
|
+
* scrolling strip of versions on a phone.
|
|
13
|
+
*
|
|
14
|
+
* Only the body: the page's header, hero, footer and metadata are the app's,
|
|
15
|
+
* because that is where every product already differs. Server-safe, no hooks.
|
|
16
|
+
*
|
|
17
|
+
* Tag colours default to tokens every house app has (`primary`, `accent`,
|
|
18
|
+
* `muted`, `border`). An app with `success` and `warning` tokens can pass
|
|
19
|
+
* `tagClassNames` for the fuller palette.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_TAG_CLASS_NAMES: Record<ChangeType, string>;
|
|
22
|
+
export declare const TAG_LABELS: Record<ChangeType, string>;
|
|
23
|
+
export declare const KIND_LABELS: Record<ReleaseKind, string>;
|
|
24
|
+
export interface ChangelogProps {
|
|
25
|
+
releases: readonly ChangelogRelease[];
|
|
26
|
+
/** Tag classes per change type; merged over the defaults. */
|
|
27
|
+
tagClassNames?: Partial<Record<ChangeType, string>>;
|
|
28
|
+
/** The release headline. Defaults to a plain 2xl semibold heading. */
|
|
29
|
+
releaseTitleClassName?: string;
|
|
30
|
+
/** The small uppercase label above the index. */
|
|
31
|
+
eyebrowClassName?: string;
|
|
32
|
+
/** The one-sentence summary under a release headline. */
|
|
33
|
+
summaryClassName?: string;
|
|
34
|
+
/** The "Latest" pill's colours. */
|
|
35
|
+
latestClassName?: string;
|
|
36
|
+
/** A section heading ("Notes", "Fixes"). */
|
|
37
|
+
sectionHeadingClassName?: string;
|
|
38
|
+
/** The "3 changes" count beside a section heading. */
|
|
39
|
+
sectionCountClassName?: string;
|
|
40
|
+
/**
|
|
41
|
+
* How a change's text is drawn. Defaults to rendering `**bold**` as strong —
|
|
42
|
+
* release notes name UI labels that way — and everything else as text.
|
|
43
|
+
*/
|
|
44
|
+
renderText?: (text: string) => ReactNode;
|
|
45
|
+
/** Locale for release dates. */
|
|
46
|
+
locale?: string;
|
|
47
|
+
/** How far below the top a sticky index sits, and where an anchor lands. */
|
|
48
|
+
stickyTop?: string;
|
|
49
|
+
className?: string;
|
|
50
|
+
}
|
|
51
|
+
/** `**label**` → <strong>label</strong>; nothing else is interpreted. */
|
|
52
|
+
export declare function renderReleaseText(text: string): ReactNode;
|
|
53
|
+
export declare function Changelog({ releases, tagClassNames, releaseTitleClassName, eyebrowClassName, summaryClassName, latestClassName, sectionHeadingClassName, sectionCountClassName, renderText, locale, stickyTop, className, }: ChangelogProps): import("react").JSX.Element;
|
|
54
|
+
/** Figures for a page hero: the latest version, how many releases, how many changes. */
|
|
55
|
+
export declare function changelogStats(releases: readonly ChangelogRelease[]): {
|
|
56
|
+
latest: string | null;
|
|
57
|
+
releases: number;
|
|
58
|
+
changes: number;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=changelog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/changelog/changelog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEtE;;;;;;;;;;;;;;;;GAgBG;AAEH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAK9D,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAKjD,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAInD,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACtC,6DAA6D;IAC7D,aAAa,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,sEAAsE;IACtE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mCAAmC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,sDAAsD;IACtD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC;IACzC,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAWzD;AAED,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,aAAa,EACb,qBAAwF,EACxF,gBAA4F,EAC5F,gBAAgF,EAChF,eAAqE,EACrE,uBAAyF,EACzF,qBAAmG,EACnG,UAA8B,EAC9B,MAAgB,EAChB,SAAkB,EAClB,SAAS,GACV,EAAE,cAAc,+BA0GhB;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GAAG;IACrE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAMA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "../internal/cx.js";
|
|
3
|
+
import { countChanges, formatReleaseDate, releaseAnchor, } from "../release/changelog.js";
|
|
4
|
+
import { releaseKind } from "../release/version.js";
|
|
5
|
+
/**
|
|
6
|
+
* The body of a /changelog page: an index of releases beside the releases
|
|
7
|
+
* themselves.
|
|
8
|
+
*
|
|
9
|
+
* Each release shows its version, whether it is a major, minor or patch
|
|
10
|
+
* release, and its date, then a headline and a one-sentence summary. Changes
|
|
11
|
+
* sit under the product-area headings they were grouped by, each with a tag
|
|
12
|
+
* and a bold headline. The index is a sticky rail on wide screens and a
|
|
13
|
+
* scrolling strip of versions on a phone.
|
|
14
|
+
*
|
|
15
|
+
* Only the body: the page's header, hero, footer and metadata are the app's,
|
|
16
|
+
* because that is where every product already differs. Server-safe, no hooks.
|
|
17
|
+
*
|
|
18
|
+
* Tag colours default to tokens every house app has (`primary`, `accent`,
|
|
19
|
+
* `muted`, `border`). An app with `success` and `warning` tokens can pass
|
|
20
|
+
* `tagClassNames` for the fuller palette.
|
|
21
|
+
*/
|
|
22
|
+
export const DEFAULT_TAG_CLASS_NAMES = {
|
|
23
|
+
new: "border-primary/40 bg-primary/10 text-primary",
|
|
24
|
+
improved: "border-border bg-accent text-accent-foreground",
|
|
25
|
+
changed: "border-foreground/30 bg-background text-foreground",
|
|
26
|
+
fixed: "border-border bg-muted text-muted-foreground",
|
|
27
|
+
};
|
|
28
|
+
export const TAG_LABELS = {
|
|
29
|
+
new: "New",
|
|
30
|
+
improved: "Improved",
|
|
31
|
+
changed: "Changed",
|
|
32
|
+
fixed: "Fixed",
|
|
33
|
+
};
|
|
34
|
+
export const KIND_LABELS = {
|
|
35
|
+
major: "Major release",
|
|
36
|
+
minor: "Minor release",
|
|
37
|
+
patch: "Patch release",
|
|
38
|
+
};
|
|
39
|
+
/** `**label**` → <strong>label</strong>; nothing else is interpreted. */
|
|
40
|
+
export function renderReleaseText(text) {
|
|
41
|
+
const parts = text.split(/(\*\*[^*\n]+\*\*)/g);
|
|
42
|
+
return parts.map((part, i) => part.startsWith("**") && part.endsWith("**") && part.length > 4 ? (_jsx("strong", { className: "font-semibold text-foreground", children: part.slice(2, -2) }, i)) : (part));
|
|
43
|
+
}
|
|
44
|
+
export function Changelog({ releases, tagClassNames, releaseTitleClassName = "text-2xl font-semibold tracking-tight text-balance sm:text-3xl", eyebrowClassName = "text-xs font-semibold tracking-[0.14em] text-muted-foreground uppercase", summaryClassName = "max-w-prose text-base leading-relaxed text-muted-foreground", latestClassName = "border-primary bg-primary text-primary-foreground", sectionHeadingClassName = "text-xs font-bold tracking-[0.14em] text-foreground uppercase", sectionCountClassName = "text-[11px] font-medium tracking-normal text-muted-foreground normal-case", renderText = renderReleaseText, locale = "en-GB", stickyTop = "7rem", className, }) {
|
|
45
|
+
const tags = { ...DEFAULT_TAG_CLASS_NAMES, ...tagClassNames };
|
|
46
|
+
return (_jsxs("div", { className: cx("mx-auto grid max-w-6xl gap-10 px-4 py-12 lg:grid-cols-[14rem_minmax(0,1fr)] lg:gap-16", className), children: [_jsx("nav", { "aria-label": "Releases", className: "min-w-0", children: _jsxs("div", { className: "lg:sticky", style: { top: stickyTop }, children: [_jsx("p", { className: eyebrowClassName, children: "Releases" }), _jsx("ol", { className: "-mx-4 mt-4 flex gap-2 overflow-x-auto px-4 pb-2 lg:mx-0 lg:block lg:max-h-[calc(100vh-10rem)] lg:space-y-0.5 lg:overflow-y-auto lg:border-l lg:border-border lg:px-0 lg:pb-0", children: releases.map((release) => (_jsx("li", { className: "shrink-0", children: _jsxs("a", { href: `#${releaseAnchor(release.version)}`, className: "block rounded-full border border-border px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:border-primary hover:text-foreground lg:-ml-px lg:rounded-none lg:border-0 lg:border-l-2 lg:border-transparent lg:py-1.5 lg:pr-2 lg:pl-4", children: [_jsxs("span", { className: "font-mono text-xs font-semibold text-foreground", children: ["v", release.version] }), _jsx("span", { className: "hidden truncate lg:block", children: release.title })] }) }, release.version))) })] }) }), _jsx("div", { className: "min-w-0 space-y-20", children: releases.map((release, i) => {
|
|
47
|
+
const anchor = releaseAnchor(release.version);
|
|
48
|
+
const previous = releases[i + 1];
|
|
49
|
+
const kind = previous ? releaseKind(previous.version, release.version) : null;
|
|
50
|
+
return (_jsxs("article", { id: anchor, "aria-labelledby": `${anchor}-title`, style: { scrollMarginTop: stickyTop }, children: [_jsxs("header", { className: "border-b border-border pb-7", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [_jsxs("span", { className: "rounded-full border border-primary/40 bg-primary/10 px-2.5 py-0.5 font-mono text-xs font-semibold text-primary", children: ["v", release.version] }), i === 0 ? (_jsx("span", { className: cx("rounded-full border px-2.5 py-0.5 text-[11px] font-semibold", latestClassName), children: "Latest" })) : null, kind ? _jsx("span", { className: "text-xs text-muted-foreground", children: KIND_LABELS[kind] }) : null, _jsx("span", { className: "text-xs text-muted-foreground", "aria-hidden": "true", children: "\u00B7" }), _jsx("time", { dateTime: release.date, className: "text-xs text-muted-foreground", children: formatReleaseDate(release.date, locale) })] }), _jsx("h2", { id: `${anchor}-title`, className: cx("mt-4", releaseTitleClassName), children: release.title }), _jsx("p", { className: cx("mt-3", summaryClassName), children: release.summary })] }), _jsx("div", { className: "mt-9 space-y-10", children: release.sections.map((section) => (_jsxs("section", { "aria-label": `${section.heading} — v${release.version}`, children: [_jsxs("h3", { className: cx("flex items-baseline gap-2", sectionHeadingClassName), children: [section.heading, _jsxs("span", { className: sectionCountClassName, children: [section.changes.length, " ", section.changes.length === 1 ? "change" : "changes"] })] }), _jsx("ul", { className: "mt-4 divide-y divide-border overflow-hidden rounded-2xl border border-border bg-card", children: section.changes.map((change) => (_jsxs("li", { className: "grid gap-2.5 p-5 sm:grid-cols-[5.5rem_minmax(0,1fr)] sm:gap-5", children: [_jsx("span", { className: cx("inline-flex h-fit w-fit items-center rounded-full border px-2 py-0.5 text-[11px] font-semibold", tags[change.type]), children: TAG_LABELS[change.type] }), _jsxs("div", { children: [_jsx("p", { className: "leading-snug font-semibold text-card-foreground", children: change.title }), _jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: renderText(change.text) })] })] }, change.title))) })] }, section.heading))) })] }, release.version));
|
|
51
|
+
}) })] }));
|
|
52
|
+
}
|
|
53
|
+
/** Figures for a page hero: the latest version, how many releases, how many changes. */
|
|
54
|
+
export function changelogStats(releases) {
|
|
55
|
+
return {
|
|
56
|
+
latest: releases[0]?.version ?? null,
|
|
57
|
+
releases: releases.length,
|
|
58
|
+
changes: releases.reduce((n, release) => n + countChanges(release), 0),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=changelog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changelog.js","sourceRoot":"","sources":["../../src/changelog/changelog.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/changelog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,cAAc,EACd,uBAAuB,EACvB,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/changelog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,cAAc,EACd,uBAAuB,EACvB,WAAW,EACX,iBAAiB,EACjB,UAAU,GAEX,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/react";
|
|
2
|
+
/**
|
|
3
|
+
* The gutter beside whichever block the pointer is over: a `+` that starts a new
|
|
4
|
+
* block underneath (with the `/` menu already open, as Notion does) and a grip
|
|
5
|
+
* that drags the block to reorder it or, clicked, opens the block menu — turn
|
|
6
|
+
* into, duplicate, move up, move down, delete.
|
|
7
|
+
*
|
|
8
|
+
* Everything works on the block's document position rather than the caret, so a
|
|
9
|
+
* block can be acted on without ever being clicked into. The drag itself is the
|
|
10
|
+
* extension's: it understands nested lists and shows the drop cursor.
|
|
11
|
+
*/
|
|
12
|
+
export declare function BlockHandle({ editor }: {
|
|
13
|
+
editor: Editor;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=block-handle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-handle.d.ts","sourceRoot":"","sources":["../../src/editor/block-handle.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AA+B5C;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,+BAuJzD"}
|