wiki-formant 0.78.0 → 0.80.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 +13 -3
- package/dist/base.css +11 -2
- package/dist/dom.d.ts +8 -6
- package/dist/dom.js +10 -7
- package/dist/react.d.ts +1 -1
- package/dist/react.js +3 -3
- package/dist/social.d.ts +34 -0
- package/dist/social.js +41 -0
- package/dist/tiptap.d.ts +8 -0
- package/dist/tiptap.js +18 -4
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -675,6 +675,16 @@ const block = licenseBlock({ license, scope: 'The protocol compilation and prose
|
|
|
675
675
|
|
|
676
676
|
The same `License` goes to `agentCard({ license, licenseScope })` and to `openApiLicense(license)` for a spec's `info.license`. The three cards and three specs here had each projected it differently, one from a hand-typed name.
|
|
677
677
|
|
|
678
|
+
## The X account
|
|
679
|
+
|
|
680
|
+
A site names its X account in five places: the footer link, the JSON-LD `sameAs`, llms.txt, AGENTS.md and the MCP `initialize` instructions. Written by hand, one repo's `sameAs` still pointed at twitter.com, and only one site told an agent the account existed. `wiki-formant/social` builds all five from the handle and a fragment saying what the account posts.
|
|
681
|
+
|
|
682
|
+
```ts
|
|
683
|
+
export const X = xAccount({ siteName: 'AcuiQ', handle: '@acu_iq', posts: "a named trial's prescription with its citation" });
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
`X.url` goes to `sameAs`, `X.handle` to `sitePageMetadata`, `followLines(X)` into llms.txt and AGENTS.md, and `followNote(X)` into the MCP instructions. The note tells an agent to give the link to the person it is helping, since an agent cannot follow an account. The footer is `<a {...followLinkProps(X)}>{X.label}</a>`, whose `rel="me"` confirms the `sameAs` claim from the page the account points back at.
|
|
687
|
+
|
|
678
688
|
## Rendered-article passes
|
|
679
689
|
|
|
680
690
|
`wiki-formant/dom` holds what runs against an article element after it is in the document. Not React, so not in `react.tsx`.
|
|
@@ -683,7 +693,7 @@ The same `License` goes to `agentCard({ license, licenseScope })` and to `openAp
|
|
|
683
693
|
addCopyButtons(el); // every <pre> gets one, once
|
|
684
694
|
sortTables(el); // every column-headed table sorts by its headers
|
|
685
695
|
hydrateTweetEmbeds(el); // placeholders get a live src
|
|
686
|
-
const off = onTweetResize(h =>
|
|
696
|
+
const off = onTweetResize((h, source) => sizeTweetEmbed(el, h, source));
|
|
687
697
|
```
|
|
688
698
|
|
|
689
699
|
`addCopyButton` was **byte-identical** in two BlockRenderers, down to the SVG path data. Its idempotence guard now lives inside the function rather than in a `pre:not(:has(…))` at the call site, where it can be — and was — retyped.
|
|
@@ -696,7 +706,7 @@ In React, `useArticlePasses(ref, [blocks])` runs the three passes and `useTweetE
|
|
|
696
706
|
|
|
697
707
|
`scrollTables(html)` is the one table pass that runs on the string, before render: it wraps each stored table in a `.table-scroll` box, and `base.css` lets that box scroll sideways. A table box ignores `overflow`, so a table with an address or a URL in a cell is as wide as that token whatever its column, and a scroll box added by an effect would arrive after the table had already been laid out too wide. Call it on the render path beside `injectHeadingIds`. A table already in a box keeps it, so it is safe on HTML that has been through it once. `articleHtml(html, { used, slug, anchor, links })` (`wiki-formant/headings`) is that chain: heading ids, the scroll boxes, and, given `links`, `normaliseLinks`.
|
|
698
708
|
|
|
699
|
-
The embed's origin is written down once. It is both the embed host and the allow-list `onTweetResize` checks before believing a posted height, and it had been spelled out at four call sites across two repos. Any page can `postMessage`; only the embed host may size the embed.
|
|
709
|
+
The embed's origin is written down once. It is both the embed host and the allow-list `onTweetResize` checks before believing a posted height, and it had been spelled out at four call sites across two repos. Any page can `postMessage`; only the embed host may size the embed. Every embed on a page posts to the same listener, so `onTweetResize` hands over the window that posted, and `sizeTweetEmbed` sizes only that one's iframe: two posts on a page had both been drawn at whichever height arrived last.
|
|
700
710
|
|
|
701
711
|
## Search
|
|
702
712
|
|
|
@@ -789,7 +799,7 @@ The bytes say what the file is, never the name or type, and SVG is refused. Ever
|
|
|
789
799
|
|
|
790
800
|
## Editor nodes
|
|
791
801
|
|
|
792
|
-
`wiki-formant/tiptap` carries the custom nodes both wiki editors had written twice: `Iframe`, `YouTube` (the stock extension plus the paste rule it does not ship with), `TwitterEmbed`, `createMapEmbed`, `createCodeBlock` and `createTabs`. `Iframe` and `createMapEmbed` draw a frame only for an https src on `DEFAULT_IFRAME_HOSTS` (`embedSrc`), since an editor draws stored HTML where its author is signed in, and a `javascript:` src runs there under any CSP that allows inline script.
|
|
802
|
+
`wiki-formant/tiptap` carries the custom nodes both wiki editors had written twice: `Iframe`, `YouTube` (the stock extension plus the paste rule it does not ship with), `TwitterEmbed`, `createMapEmbed`, `createCodeBlock` and `createTabs`. `embedNodes({ resolveMapUrl })` is the first four as one list, which an editor puts in its `nodes`: a pasted YouTube, X or map link becomes its player as it lands, and the toolbar's embed prompt has a node for every link it recognises. `resolveMapUrl` defaults to `wiki-formant/maps`', through `/api/resolve-map`. `Iframe` and `createMapEmbed` draw a frame only for an https src on `DEFAULT_IFRAME_HOSTS` (`embedSrc`), since an editor draws stored HTML where its author is signed in, and a `javascript:` src runs there under any CSP that allows inline script.
|
|
793
803
|
|
|
794
804
|
```ts
|
|
795
805
|
const CodeBlock = createCodeBlock({
|
package/dist/base.css
CHANGED
|
@@ -432,8 +432,8 @@ pre:hover > .code-copy-btn,
|
|
|
432
432
|
.stats-count { font-variant-numeric: tabular-nums; }
|
|
433
433
|
|
|
434
434
|
/* ---- embeds ------------------------------------------------------------------
|
|
435
|
-
The players the `wiki-formant/tiptap` nodes store,
|
|
436
|
-
screen's proportions. The node writes a width and height onto the iframe,
|
|
435
|
+
The players the `wiki-formant/tiptap` nodes store, a video or map filling its
|
|
436
|
+
column at a screen's proportions. The node writes a width and height onto the iframe,
|
|
437
437
|
which `aspect-ratio` with `height: auto` overrides. Spacing, corners,
|
|
438
438
|
borders and the editor's selection ring are the site's. */
|
|
439
439
|
:is(div[data-youtube-video], .map-embed) iframe {
|
|
@@ -442,3 +442,12 @@ pre:hover > .code-copy-btn,
|
|
|
442
442
|
height: auto;
|
|
443
443
|
aspect-ratio: 16 / 9;
|
|
444
444
|
}
|
|
445
|
+
|
|
446
|
+
/* A post on X at the width X lays it out for, as tall as it says it is
|
|
447
|
+
(`onTweetResize`), and a little before it has said. */
|
|
448
|
+
.twitter-embed iframe {
|
|
449
|
+
display: block;
|
|
450
|
+
width: 550px;
|
|
451
|
+
max-width: 100%;
|
|
452
|
+
min-height: 200px;
|
|
453
|
+
}
|
package/dist/dom.d.ts
CHANGED
|
@@ -20,13 +20,15 @@ export declare function addCopyButtons(root: ParentNode, options?: CopyButtonOpt
|
|
|
20
20
|
/** The embed iframe's src. `dnt=true` opts the embed out of Twitter's tracking. */
|
|
21
21
|
export declare const tweetEmbedSrc: (tweetId: string | number) => string;
|
|
22
22
|
/**
|
|
23
|
-
* Subscribe to the height
|
|
23
|
+
* Subscribe to the height an embed posts back once it has laid itself out,
|
|
24
|
+
* with the window that posted it.
|
|
24
25
|
*
|
|
25
26
|
* The iframe renders at an unknown height and there is no other way to learn
|
|
26
|
-
* it.
|
|
27
|
-
* the origin check and the
|
|
27
|
+
* it. Every embed on the page posts to the same listener, so the source is how
|
|
28
|
+
* a height finds its own iframe. This only owns the origin check and the
|
|
29
|
+
* message shape. Returns a disposer.
|
|
28
30
|
*/
|
|
29
|
-
export declare function onTweetResize(resize: (height: number) => void): () => void;
|
|
31
|
+
export declare function onTweetResize(resize: (height: number, source: MessageEventSource | null) => void): () => void;
|
|
30
32
|
/**
|
|
31
33
|
* Point every un-hydrated `[data-twitter-embed]` placeholder under `root` at
|
|
32
34
|
* the real embed URL.
|
|
@@ -36,8 +38,8 @@ export declare function onTweetResize(resize: (height: number) => void): () => v
|
|
|
36
38
|
* of the same content does not reload every embed on the page.
|
|
37
39
|
*/
|
|
38
40
|
export declare function hydrateTweetEmbeds(root: ParentNode): void;
|
|
39
|
-
/** Apply a
|
|
40
|
-
export declare function
|
|
41
|
+
/** Apply a posted height to the embed iframe under `root` that posted it, and to no other. */
|
|
42
|
+
export declare function sizeTweetEmbed(root: ParentNode, height: number, source: MessageEventSource | null): void;
|
|
41
43
|
export interface TabGroupClassNames {
|
|
42
44
|
list?: string;
|
|
43
45
|
panels?: string;
|
package/dist/dom.js
CHANGED
|
@@ -63,11 +63,13 @@ export const TWITTER_ORIGIN = 'https://platform.twitter.com';
|
|
|
63
63
|
/** The embed iframe's src. `dnt=true` opts the embed out of Twitter's tracking. */
|
|
64
64
|
export const tweetEmbedSrc = (tweetId) => `${TWITTER_ORIGIN}/embed/Tweet.html?id=${tweetId}&dnt=true`;
|
|
65
65
|
/**
|
|
66
|
-
* Subscribe to the height
|
|
66
|
+
* Subscribe to the height an embed posts back once it has laid itself out,
|
|
67
|
+
* with the window that posted it.
|
|
67
68
|
*
|
|
68
69
|
* The iframe renders at an unknown height and there is no other way to learn
|
|
69
|
-
* it.
|
|
70
|
-
* the origin check and the
|
|
70
|
+
* it. Every embed on the page posts to the same listener, so the source is how
|
|
71
|
+
* a height finds its own iframe. This only owns the origin check and the
|
|
72
|
+
* message shape. Returns a disposer.
|
|
71
73
|
*/
|
|
72
74
|
export function onTweetResize(resize) {
|
|
73
75
|
const handleMessage = (e) => {
|
|
@@ -78,7 +80,7 @@ export function onTweetResize(resize) {
|
|
|
78
80
|
return;
|
|
79
81
|
const height = data.params?.[0]?.height;
|
|
80
82
|
if (height)
|
|
81
|
-
resize(height);
|
|
83
|
+
resize(height, e.source);
|
|
82
84
|
};
|
|
83
85
|
window.addEventListener('message', handleMessage);
|
|
84
86
|
return () => window.removeEventListener('message', handleMessage);
|
|
@@ -104,10 +106,11 @@ export function hydrateTweetEmbeds(root) {
|
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
|
-
/** Apply a
|
|
108
|
-
export function
|
|
109
|
+
/** Apply a posted height to the embed iframe under `root` that posted it, and to no other. */
|
|
110
|
+
export function sizeTweetEmbed(root, height, source) {
|
|
109
111
|
for (const iframe of Array.from(root.querySelectorAll('[data-twitter-embed] iframe'))) {
|
|
110
|
-
iframe.
|
|
112
|
+
if (iframe.contentWindow === source)
|
|
113
|
+
iframe.style.height = `${height}px`;
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
116
|
/**
|
package/dist/react.d.ts
CHANGED
|
@@ -485,7 +485,7 @@ export type { WikiLinkComponent, WikiLinkProps } from './react-server.js';
|
|
|
485
485
|
* idempotent, so running on every `deps` change is safe.
|
|
486
486
|
*/
|
|
487
487
|
export declare function useArticlePasses(ref: RefObject<HTMLElement | null>, deps: DependencyList): void;
|
|
488
|
-
/** Tweet placeholders hydrated, and
|
|
488
|
+
/** Tweet placeholders hydrated, and each iframe kept at the height it posts. */
|
|
489
489
|
export declare function useTweetEmbeds(ref: RefObject<HTMLElement | null>, deps: DependencyList): void;
|
|
490
490
|
/**
|
|
491
491
|
* Counts the page views of the app it is mounted in: place it once, in the root
|
package/dist/react.js
CHANGED
|
@@ -26,7 +26,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
26
26
|
// state on <html> before first paint. The hook keeps that attribute in
|
|
27
27
|
// sync afterwards, so CSS has one source of truth either side of hydration.
|
|
28
28
|
import { railBreakpointMismatch, readRailFloating, resolveSidebarOpen, SIDEBAR_ATTRIBUTE, } from './sidebar.js';
|
|
29
|
-
import { activateTabGroups, addCopyButtons, hydrateTweetEmbeds, onTweetResize,
|
|
29
|
+
import { activateTabGroups, addCopyButtons, hydrateTweetEmbeds, onTweetResize, sizeTweetEmbed, sortTables, startBeacon } from './dom.js';
|
|
30
30
|
import { comboboxAria } from './combobox.js';
|
|
31
31
|
import { Component, createContext, createElement, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
|
|
32
32
|
const readStored = (key) => {
|
|
@@ -899,14 +899,14 @@ export function useArticlePasses(ref, deps) {
|
|
|
899
899
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
900
900
|
}, deps);
|
|
901
901
|
}
|
|
902
|
-
/** Tweet placeholders hydrated, and
|
|
902
|
+
/** Tweet placeholders hydrated, and each iframe kept at the height it posts. */
|
|
903
903
|
export function useTweetEmbeds(ref, deps) {
|
|
904
904
|
useEffect(() => {
|
|
905
905
|
const root = ref.current;
|
|
906
906
|
if (!root)
|
|
907
907
|
return;
|
|
908
908
|
hydrateTweetEmbeds(root);
|
|
909
|
-
return onTweetResize(height =>
|
|
909
|
+
return onTweetResize((height, source) => sizeTweetEmbed(root, height, source));
|
|
910
910
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
911
911
|
}, deps);
|
|
912
912
|
}
|
package/dist/social.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface XAccount {
|
|
2
|
+
/** `@handle`, as the social cards credit it. */
|
|
3
|
+
handle: string;
|
|
4
|
+
/** `https://x.com/<handle>`, for `sameAs` and every link. */
|
|
5
|
+
url: string;
|
|
6
|
+
/** "<Site> posts on X as @handle: <posts>." */
|
|
7
|
+
about: string;
|
|
8
|
+
/** The footer link's text: "Follow @handle on X". */
|
|
9
|
+
label: string;
|
|
10
|
+
siteName: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function xAccount(o: {
|
|
13
|
+
siteName: string;
|
|
14
|
+
handle: string;
|
|
15
|
+
posts: string;
|
|
16
|
+
}): XAccount;
|
|
17
|
+
/**
|
|
18
|
+
* The sentence an agent reads: what the account posts, and when to pass the
|
|
19
|
+
* link on. An agent cannot follow an account; the person it is helping can.
|
|
20
|
+
*/
|
|
21
|
+
export declare function followNote(account: XAccount): string;
|
|
22
|
+
/** The same note as a section, ready to splice into llms.txt or AGENTS.md. */
|
|
23
|
+
export declare function followLines(account: XAccount, heading?: string): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Attributes for the footer link. `rel="me"` is the reciprocal of `sameAs`:
|
|
26
|
+
* the schema claims the account and this link confirms it from the page the
|
|
27
|
+
* account points back at.
|
|
28
|
+
*/
|
|
29
|
+
export declare function followLinkProps(account: XAccount): {
|
|
30
|
+
readonly href: string;
|
|
31
|
+
readonly target: "_blank";
|
|
32
|
+
readonly rel: "me noopener";
|
|
33
|
+
readonly title: string;
|
|
34
|
+
};
|
package/dist/social.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// social.ts – the site's X account, as every surface states it.
|
|
2
|
+
//
|
|
3
|
+
// Each origin names its account in five places: the footer link, the JSON-LD
|
|
4
|
+
// `sameAs`, llms.txt, AGENTS.md and the MCP `initialize` instructions. Written
|
|
5
|
+
// by hand, they drifted within one repo: radix-wiki's `sameAs` still claimed
|
|
6
|
+
// twitter.com while its cards credited the handle, and only acuiq.com told an
|
|
7
|
+
// agent the account existed at all.
|
|
8
|
+
//
|
|
9
|
+
// What is per-site is the handle and what the account posts. The URL, the
|
|
10
|
+
// link's label and `rel`, and the sentence an agent reads are built here.
|
|
11
|
+
export function xAccount(o) {
|
|
12
|
+
if (!/^@\w{1,15}$/.test(o.handle))
|
|
13
|
+
throw new Error(`xAccount: "${o.handle}" is not an @handle`);
|
|
14
|
+
const posts = o.posts.trim().replace(/\.$/, '');
|
|
15
|
+
return {
|
|
16
|
+
handle: o.handle,
|
|
17
|
+
url: `https://x.com/${o.handle.slice(1)}`,
|
|
18
|
+
about: `${o.siteName} posts on X as ${o.handle}: ${posts}.`,
|
|
19
|
+
label: `Follow ${o.handle} on X`,
|
|
20
|
+
siteName: o.siteName,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The sentence an agent reads: what the account posts, and when to pass the
|
|
25
|
+
* link on. An agent cannot follow an account; the person it is helping can.
|
|
26
|
+
*/
|
|
27
|
+
export function followNote(account) {
|
|
28
|
+
return `${account.about} If the person you are helping wants to follow ${account.siteName}, give them ${account.url}.`;
|
|
29
|
+
}
|
|
30
|
+
/** The same note as a section, ready to splice into llms.txt or AGENTS.md. */
|
|
31
|
+
export function followLines(account, heading = `Follow ${account.siteName} on X`) {
|
|
32
|
+
return [`## ${heading}`, '', followNote(account)];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Attributes for the footer link. `rel="me"` is the reciprocal of `sameAs`:
|
|
36
|
+
* the schema claims the account and this link confirms it from the page the
|
|
37
|
+
* account points back at.
|
|
38
|
+
*/
|
|
39
|
+
export function followLinkProps(account) {
|
|
40
|
+
return { href: account.url, target: '_blank', rel: 'me noopener', title: account.about };
|
|
41
|
+
}
|
package/dist/tiptap.d.ts
CHANGED
|
@@ -29,6 +29,14 @@ export interface MapEmbedOptions {
|
|
|
29
29
|
* node has to already exist for the reader to see anything happen.
|
|
30
30
|
*/
|
|
31
31
|
export declare function createMapEmbed({ resolveMapUrl }: MapEmbedOptions): TiptapNode<any, any>;
|
|
32
|
+
/**
|
|
33
|
+
* Every player a pasted link becomes – a YouTube video, a post on X, a Google
|
|
34
|
+
* or Apple map – and any other allowed iframe, as one list. Each app had
|
|
35
|
+
* picked its embeds by hand, and one that left `TwitterEmbed` out kept a
|
|
36
|
+
* pasted post as a bare link. `resolveMapUrl` follows a shortened map link,
|
|
37
|
+
* through `/api/resolve-map` unless an app routes it another way.
|
|
38
|
+
*/
|
|
39
|
+
export declare const embedNodes: ({ resolveMapUrl }?: Partial<MapEmbedOptions>) => TiptapNode<any, any>[];
|
|
32
40
|
export interface CodeBlockClassNames {
|
|
33
41
|
wrapper?: string;
|
|
34
42
|
/** The control cluster, positioned over the block. */
|
package/dist/tiptap.js
CHANGED
|
@@ -18,7 +18,7 @@ import TiptapYoutube from '@tiptap/extension-youtube';
|
|
|
18
18
|
import TiptapCodeBlock from '@tiptap/extension-code-block';
|
|
19
19
|
import { onTweetResize, tweetEmbedSrc } from './dom.js';
|
|
20
20
|
import { DEFAULT_IFRAME_HOSTS } from './headers.js';
|
|
21
|
-
import { toMapEmbedUrl } from './maps.js';
|
|
21
|
+
import { resolveMapUrl as resolveMapRoute, toMapEmbedUrl } from './maps.js';
|
|
22
22
|
import { useClickOutside } from './react.js';
|
|
23
23
|
import { cx } from './html.js';
|
|
24
24
|
import { slugifyHeading, uniqueHeadingId } from './headings.js';
|
|
@@ -78,10 +78,10 @@ export const YouTube = TiptapYoutube.extend({
|
|
|
78
78
|
function TwitterEmbedView({ node }) {
|
|
79
79
|
const containerRef = useRef(null);
|
|
80
80
|
// The embed posts its measured height back; `onTweetResize` owns the origin
|
|
81
|
-
// check.
|
|
82
|
-
useEffect(() => onTweetResize(height => {
|
|
81
|
+
// check, and the source keeps one tweet's height off every other.
|
|
82
|
+
useEffect(() => onTweetResize((height, source) => {
|
|
83
83
|
const iframe = containerRef.current?.querySelector('iframe');
|
|
84
|
-
if (iframe)
|
|
84
|
+
if (iframe && iframe.contentWindow === source)
|
|
85
85
|
iframe.style.height = `${height}px`;
|
|
86
86
|
}), []);
|
|
87
87
|
return (_jsx(NodeViewWrapper, { children: _jsx("div", { ref: containerRef, className: "twitter-embed", children: _jsx("iframe", { src: tweetEmbedSrc(node.attrs.tweetId), scrolling: "no", allowFullScreen: true }) }) }));
|
|
@@ -231,6 +231,20 @@ export function createMapEmbed({ resolveMapUrl }) {
|
|
|
231
231
|
},
|
|
232
232
|
});
|
|
233
233
|
}
|
|
234
|
+
// ---- every embed ------------------------------------------------------------
|
|
235
|
+
/**
|
|
236
|
+
* Every player a pasted link becomes – a YouTube video, a post on X, a Google
|
|
237
|
+
* or Apple map – and any other allowed iframe, as one list. Each app had
|
|
238
|
+
* picked its embeds by hand, and one that left `TwitterEmbed` out kept a
|
|
239
|
+
* pasted post as a bare link. `resolveMapUrl` follows a shortened map link,
|
|
240
|
+
* through `/api/resolve-map` unless an app routes it another way.
|
|
241
|
+
*/
|
|
242
|
+
export const embedNodes = ({ resolveMapUrl = resolveMapRoute } = {}) => [
|
|
243
|
+
YouTube,
|
|
244
|
+
Iframe,
|
|
245
|
+
TwitterEmbed,
|
|
246
|
+
createMapEmbed({ resolveMapUrl }),
|
|
247
|
+
];
|
|
234
248
|
/** A code block whose language is pickable from a dropdown. */
|
|
235
249
|
export function createCodeBlock({ langs = CODE_LANGS, defaultLang = DEFAULT_LANG, classNames = {}, icons = {}, } = {}) {
|
|
236
250
|
function CodeBlockView({ node, updateAttributes, }) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wiki-formant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.80.0",
|
|
4
4
|
"description": "The portable half of a wiki: derived taxonomy and facet controls, a version-negotiating MCP transport, markdown twins, block rendering, a rich-text editor engine, conditional-GET plumbing, and the headers and CSP every origin sends.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -147,6 +147,11 @@
|
|
|
147
147
|
"import": "./dist/license.js",
|
|
148
148
|
"default": "./dist/license.js"
|
|
149
149
|
},
|
|
150
|
+
"./social": {
|
|
151
|
+
"types": "./dist/social.d.ts",
|
|
152
|
+
"import": "./dist/social.js",
|
|
153
|
+
"default": "./dist/social.js"
|
|
154
|
+
},
|
|
150
155
|
"./links": {
|
|
151
156
|
"types": "./dist/links.d.ts",
|
|
152
157
|
"import": "./dist/links.js",
|