@riebeckite/plugin-share 0.0.21 → 0.0.23

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 CHANGED
@@ -1,19 +1,23 @@
1
1
  # @riebeckite/plugin-share
2
2
 
3
+ <!-- Generated from docs/docs/plugins/share.md. Edit the canonical documentation in docs/docs/plugins and run `pnpm docs:sync`. -->
4
+
3
5
  Per-article share controls built at build time. For every published entry the
4
- plugin builds share URLs for the configured services and injects the controls
5
- into the rendered HTML. The links are ordinary anchors and work without
6
- JavaScript; only the copy-link action is a progressive enhancement.
6
+ plugin builds share URLs for the configured services and provides the control
7
+ data. The Site renders `<ShareControls />` itself, determining position in the
8
+ layout. The links are ordinary anchors and work without JavaScript; only the
9
+ copy-link action is a progressive enhancement.
7
10
 
8
11
  [日本語](./README_ja.md)
9
12
 
10
13
  ## Overview
11
14
 
12
15
  `share()` resolves each note's `permalink` to an absolute URL, composes the
13
- service URLs from the note title and URL, and inserts the controls near the
14
- article. The controls are inserted into the manifest entry's HTML, which Core
15
- synchronizes with the content the route renders, so they appear on generated
16
- pages and in feeds.
16
+ service URLs from the note title and URL, and builds share link data. The data
17
+ is available via `getShareLinks({ entry, site, options? })` and rendered by the
18
+ Site using `<ShareControls links={...} />`. The controls are ordinary anchors
19
+ and work without JavaScript; only the copy-link action is a progressive
20
+ enhancement.
17
21
 
18
22
  Supported services:
19
23
 
@@ -27,7 +31,7 @@ Supported services:
27
31
  | `hatena` | `https://b.hatena.ne.jp/add?mode=confirm&url=…&title=…` |
28
32
  | `copy` | Copies the note URL (button, no JavaScript required for the links) |
29
33
 
30
- `mastodon` is opt-in: add `"mastodon"` to `services` and set
34
+ Mastodon is opt-in: add `"mastodon"` to `services` and set
31
35
  `mastodonInstance`.
32
36
 
33
37
  ## Usage
@@ -42,22 +46,11 @@ export default defineConfig({
42
46
  });
43
47
  ```
44
48
 
45
- Enable Mastodon and change placement:
46
-
47
- ```ts
48
- share({
49
- services: ["x", "bluesky", "mastodon", "copy"],
50
- mastodonInstance: "mastodon.social",
51
- placement: "top",
52
- });
53
- ```
54
-
55
49
  ## Options
56
50
 
57
51
  | Option | Type | Default | Description |
58
52
  | ------ | ---- | ------- | ----------- |
59
53
  | `services` | `ShareService[]` | every service except `mastodon` | Services to render, in order |
60
- | `placement` | `"top" \| "bottom"` | `"bottom"` | Where the controls appear |
61
54
  | `mastodonInstance` | `string` | none | Mastodon host; required when `services` includes `"mastodon"` |
62
55
  | `className` | `string` | none | Extra root class alongside the stable `rr-share` hook |
63
56
  | `ariaLabel` | `string` | `"Share"` | Accessible name for the control group |
@@ -68,35 +61,22 @@ share({
68
61
  `share` throws a configuration error at `riebeckite check` time when
69
62
  `services` includes `"mastodon"` but `mastodonInstance` is missing.
70
63
 
71
- ## Output
72
-
73
- ```html
74
- <div class="rr-share" data-rr-share data-rr-share-placement="bottom"
75
- role="group" aria-label="Share">
76
- <ul class="rr-share__list">
77
- <li class="rr-share__item">
78
- <a class="rr-share__link rr-share__link--x"
79
- href="https://twitter.com/intent/tweet?url=…&amp;text=…"
80
- target="_blank" rel="noopener noreferrer" data-share-service="x">X</a>
81
- </li>
82
- <li class="rr-share__item">
83
- <button type="button" class="rr-share__button rr-share__copy"
84
- data-rr-share-copy data-share-url="https://example.com/posts/hello"
85
- data-rr-share-copied="Copied" hidden>Copy link</button>
86
- </li>
87
- </ul>
88
- <p class="rr-share__status" role="status" aria-live="polite"></p>
89
- </div>
90
- ```
64
+ ## Display
65
+
66
+ Share controls are rendered at the position determined by the Site, where
67
+ `<ShareControls links={...} />` is placed in the layout. On this site they
68
+ appear as live controls on the page, including the progressively enhanced
69
+ copy-link action. The Site decides whether to render controls at the top or
70
+ bottom of the article, or at some other position.
91
71
 
92
- ## Progressive enhancement
72
+ Progressive enhancement:
93
73
 
94
74
  The share links are plain anchors, so they work with JavaScript disabled. The
95
75
  copy-link button starts `hidden` and is revealed by `initShare()`, which the
96
76
  app calls during page initialization; a no-JS reader never sees a control that
97
77
  cannot work. Copying uses `navigator.clipboard.writeText` and falls back to a
98
- hidden textarea with `document.execCommand("copy")`. The result is announced in
99
- the `aria-live="polite"` status region.
78
+ hidden textarea with `document.execCommand("copy")`. The result is announced
79
+ in the `aria-live="polite"` status region.
100
80
 
101
81
  ## Style
102
82
 
@@ -108,8 +88,8 @@ import "@riebeckite/plugin-share/style.css";
108
88
 
109
89
  The stable classes are `rr-share` (root), `rr-share__list`, `rr-share__item`,
110
90
  `rr-share__link`, `rr-share__link--{service}`, `rr-share__button`,
111
- `rr-share__copy`, and `rr-share__status`. A theme can target these hooks; the
112
- optional `className` is added to the root without replacing them.
91
+ `rr-share__copy`, and `rr-share__status`. A theme can target these hooks;
92
+ the optional `className` is added to the root without replacing them.
113
93
 
114
94
  ## Exports
115
95
 
@@ -127,15 +107,13 @@ optional `className` is added to the root without replacing them.
127
107
  - Constants: `SHARE_SERVICES`, `SHARE_ATTRIBUTE`, `SHARE_ROOT_CLASS`,
128
108
  `DEFAULT_SHARE_SERVICES`, `DEFAULT_SHARE_LABELS`, `DEFAULT_SHARE_PLACEMENT`
129
109
  - Types: `ShareOptions`, `ResolvedShareOptions`, `ShareService`,
130
- `SharePlacement`, `ShareLink`, `ShareTarget`
110
+ `ShareLink`, `ShareTarget`
131
111
 
132
112
  ## Limitations
133
113
 
134
114
  - Share URLs are fixed at build time. A full rebuild always recomputes them.
135
115
  - Mastodon cannot be enabled without a concrete instance.
136
- - The plugin contributes controls to `article.before-content` for `top` and
137
- `article.footer` for `bottom`; a Site places those semantic slots in its layout.
138
116
 
139
117
  ## See also
140
118
 
141
- - [Plugin guide](../../../docs/docs/reference/plugin-api.md)
119
+ - [Plugin guide](https://github.com/Rerurate514/riebeckite/blob/main/docs/docs/reference/plugin-api.md)
package/README_ja.md CHANGED
@@ -1,8 +1,11 @@
1
1
  # @riebeckite/plugin-share
2
2
 
3
+ <!-- Generated from docs/docs/plugins/share.ja.md. Edit the canonical documentation in docs/docs/plugins and run `pnpm docs:sync`. -->
4
+
3
5
  記事ごとの共有ボタンをビルド時に生成するプラグインです。公開対象の各エントリ
4
- について、設定したサービス向けの共有 URL を組み立て、本文の近くにコントロール
5
- を挿入します。共有リンクは通常の `<a>` なので JavaScript なしでも動作し、コピー
6
+ について、設定したサービス向けの共有 URL を組み立て、Share controls のデータ
7
+ を提供します。Site が `<ShareControls links={...} />` を描画する位置をlayout で
8
+ 決定します。共有リンクは通常の `<a>` なので JavaScript なしでも動作し、コピー
6
9
  操作だけをプログレッシブ・エンハンスメントとして追加します。
7
10
 
8
11
  [English](./README.md)
@@ -10,9 +13,11 @@
10
13
  ## 仕組み
11
14
 
12
15
  `share()` は各ノートの `permalink` を絶対 URL に解決し、ノートのタイトルと URL
13
- からサービスごとの共有 URL を組み立て、記事の近くにコントロールを挿入します。
14
- 挿入先はマニフェストエントリの HTML で、Core がそれをコンテンツルートの描画
15
- HTML と同期するため、生成ページとフィードの両方に反映されます。
16
+ からサービスごとの共有 URL を組み立て、Share control data を組み立てます。
17
+ データは `getShareLinks({ entry, site, options? })` で利用可能で、Site が
18
+ `<ShareControls links={...} />` で描画します。共有リンクは通常の `<a>` なので
19
+ JavaScript なしでも動作し、コピー操作だけをプログレッシブ・エンハンスメント
20
+ として追加します。
16
21
 
17
22
  対応サービスは次のとおりです。
18
23
 
@@ -26,7 +31,7 @@ HTML と同期するため、生成ページとフィードの両方に反映さ
26
31
  | `hatena` | `https://b.hatena.ne.jp/add?mode=confirm&url=…&title=…` |
27
32
  | `copy` | ノートの URL をコピーするボタン(リンクは JS 不要) |
28
33
 
29
- `mastodon` はオプトインです。`services` に `"mastodon"` を追加し、
34
+ Mastodon はオプトインです。`services` に `"mastodon"` を追加し、
30
35
  `mastodonInstance` を設定してください。
31
36
 
32
37
  ## 使い方
@@ -41,22 +46,11 @@ export default defineConfig({
41
46
  });
42
47
  ```
43
48
 
44
- Mastodon を有効にし、表示位置を変える例です。
45
-
46
- ```ts
47
- share({
48
- services: ["x", "bluesky", "mastodon", "copy"],
49
- mastodonInstance: "mastodon.social",
50
- placement: "top",
51
- });
52
- ```
53
-
54
49
  ## オプション
55
50
 
56
51
  | オプション | 型 | 既定値 | 説明 |
57
52
  | ---------- | -- | ------ | ---- |
58
53
  | `services` | `ShareService[]` | `mastodon` 以外のすべて | 表示するサービス(順序どおり) |
59
- | `placement` | `"top" \| "bottom"` | `"bottom"` | コントロールの表示位置 |
60
54
  | `mastodonInstance` | `string` | なし | Mastodon のホスト。`services` に `"mastodon"` を含めると必須 |
61
55
  | `className` | `string` | なし | 安定した `rr-share` フックに追加するルートクラス |
62
56
  | `ariaLabel` | `string` | `"Share"` | コントロールグループのアクセシブル名 |
@@ -67,26 +61,13 @@ share({
67
61
  `services` に `"mastodon"` を含めたのに `mastodonInstance` が未設定の場合、
68
62
  `riebeckite check` の時点で設定エラーになります。
69
63
 
70
- ## 出力
71
-
72
- ```html
73
- <div class="rr-share" data-rr-share data-rr-share-placement="bottom"
74
- role="group" aria-label="Share">
75
- <ul class="rr-share__list">
76
- <li class="rr-share__item">
77
- <a class="rr-share__link rr-share__link--x"
78
- href="https://twitter.com/intent/tweet?url=…&amp;text=…"
79
- target="_blank" rel="noopener noreferrer" data-share-service="x">X</a>
80
- </li>
81
- <li class="rr-share__item">
82
- <button type="button" class="rr-share__button rr-share__copy"
83
- data-rr-share-copy data-share-url="https://example.com/posts/hello"
84
- data-rr-share-copied="Copied" hidden>Copy link</button>
85
- </li>
86
- </ul>
87
- <p class="rr-share__status" role="status" aria-live="polite"></p>
88
- </div>
89
- ```
64
+ ## 表示
65
+
66
+ 共有コントロールは、Site が layout で `<ShareControls links={...} />` を
67
+ 描画する位置に実際に描画されます。このサイトでは、プログレッシブ・エンハンス
68
+ メントされたリンクコピー操作を含むコントロールとして表示します。Site は
69
+ コントロールを記事のトップやボトム、またはその他の位置に描画するかどうかを
70
+ 決定します。
90
71
 
91
72
  ## プログレッシブ・エンハンスメント
92
73
 
@@ -127,15 +108,13 @@ import "@riebeckite/plugin-share/style.css";
127
108
  - 定数: `SHARE_SERVICES`, `SHARE_ATTRIBUTE`, `SHARE_ROOT_CLASS`,
128
109
  `DEFAULT_SHARE_SERVICES`, `DEFAULT_SHARE_LABELS`, `DEFAULT_SHARE_PLACEMENT`
129
110
  - 型: `ShareOptions`, `ResolvedShareOptions`, `ShareService`,
130
- `SharePlacement`, `ShareLink`, `ShareTarget`
111
+ `ShareLink`, `ShareTarget`
131
112
 
132
113
  ## 制約
133
114
 
134
115
  - 共有 URL はビルド時に確定します。再ビルドすれば常に正しく再計算されます。
135
116
  - Mastodon は具体的なインスタンスなしには有効化できません。
136
- - `top` は `article.before-content`、`bottom` は `article.footer` にコントロールを
137
- 提供します。Site は layout でその semantic slot を配置します。
138
117
 
139
118
  ## 関連
140
119
 
141
- - [プラグインガイド](../../../docs/docs/reference/plugin-api.ja.md)
120
+ - [プラグインガイド](https://github.com/Rerurate514/riebeckite/blob/main/docs/docs/reference/plugin-api.ja.md)
@@ -0,0 +1,12 @@
1
+ import type { ShareLink } from "../src/types.js";
2
+ export type ShareControlsProps = {
3
+ readonly links: readonly ShareLink[];
4
+ readonly copyUrl?: string;
5
+ readonly ariaLabel?: string;
6
+ readonly className?: string;
7
+ readonly copyLabel?: string;
8
+ readonly copiedLabel?: string;
9
+ readonly copyFailedLabel?: string;
10
+ };
11
+ declare const ShareControls: ({ links, copyUrl, ariaLabel, className, copyLabel, copiedLabel, copyFailedLabel, }: Readonly<ShareControlsProps>) => import("hono/jsx/jsx-dev-runtime").JSX.Element;
12
+ export default ShareControls;
@@ -0,0 +1,47 @@
1
+ // components/share-controls.tsx
2
+ import { jsx, jsxs } from "hono/jsx/jsx-runtime";
3
+ var ShareControls = (({
4
+ links,
5
+ copyUrl,
6
+ ariaLabel = "Share",
7
+ className = "rr-share",
8
+ copyLabel = "Copy link",
9
+ copiedLabel = "Copied",
10
+ copyFailedLabel = "Copy failed"
11
+ }) => {
12
+ if (links.length === 0 && !copyUrl) return null;
13
+ const rootClass = className === "rr-share" ? className : `rr-share ${className}`;
14
+ return /* @__PURE__ */ jsxs("nav", { class: rootClass, "data-rr-share": true, "aria-label": ariaLabel, children: [
15
+ /* @__PURE__ */ jsxs("ul", { class: "rr-share__list", children: [
16
+ links.map((link) => /* @__PURE__ */ jsx("li", { class: "rr-share__item", children: /* @__PURE__ */ jsx(
17
+ "a",
18
+ {
19
+ class: `rr-share__link rr-share__link--${link.service}`,
20
+ href: link.url,
21
+ target: "_blank",
22
+ rel: "noopener noreferrer",
23
+ "data-share-service": link.service,
24
+ children: link.label
25
+ }
26
+ ) }, link.service)),
27
+ copyUrl ? /* @__PURE__ */ jsx("li", { class: "rr-share__item", children: /* @__PURE__ */ jsx(
28
+ "button",
29
+ {
30
+ type: "button",
31
+ class: "rr-share__button rr-share__copy",
32
+ "data-rr-share-copy": true,
33
+ "data-share-url": copyUrl,
34
+ "data-rr-share-copied": copiedLabel,
35
+ "data-rr-share-copy-failed": copyFailedLabel,
36
+ hidden: true,
37
+ children: copyLabel
38
+ }
39
+ ) }) : null
40
+ ] }),
41
+ /* @__PURE__ */ jsx("p", { class: "rr-share__status", role: "status", "aria-live": "polite" })
42
+ ] });
43
+ });
44
+ var share_controls_default = ShareControls;
45
+ export {
46
+ share_controls_default as default
47
+ };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,27 @@
1
+ import { type PluginDataHelper, type PublicContentEntry, type ResolvedRiebeckiteConfig } from "@riebeckite/core";
1
2
  import type { ShareOptions } from "./src/types.js";
3
+ export type { ShareControlsProps } from "./components/share-controls.js";
4
+ export { default as ShareControls } from "./components/share-controls.js";
2
5
  export { initShare } from "./src/client.js";
3
- export { DEFAULT_SHARE_ARIA_LABEL, DEFAULT_SHARE_COPIED_LABEL, DEFAULT_SHARE_COPY_FAILED_LABEL, DEFAULT_SHARE_LABELS, DEFAULT_SHARE_PLACEMENT, DEFAULT_SHARE_SERVICES, resolveShareOptions, validateShareOptions, } from "./src/options.js";
6
+ export { DEFAULT_SHARE_ARIA_LABEL, DEFAULT_SHARE_COPIED_LABEL, DEFAULT_SHARE_COPY_FAILED_LABEL, DEFAULT_SHARE_LABELS, DEFAULT_SHARE_SERVICES, resolveShareOptions, validateShareOptions, } from "./src/options.js";
4
7
  export { renderShareControls, SHARE_ATTRIBUTE, SHARE_ROOT_CLASS, } from "./src/render.js";
5
8
  export { buildAbsoluteUrl, buildShareLinks, buildShareUrl, normalizeMastodonInstance, type ShareTarget, } from "./src/services.js";
6
- export type { ResolvedShareOptions, ShareLink, ShareOptions, SharePlacement, ShareService, } from "./src/types.js";
9
+ export type { ResolvedShareOptions, ShareLink, ShareOptions, ShareService, } from "./src/types.js";
7
10
  export { SHARE_SERVICES } from "./src/types.js";
11
+ export type ShareLinksData = {
12
+ readonly links: readonly import("./src/types.js").ShareLink[];
13
+ readonly copyUrl?: string;
14
+ readonly ariaLabel: string;
15
+ readonly className: string;
16
+ readonly copyLabel: string;
17
+ readonly copiedLabel: string;
18
+ readonly copyFailedLabel: string;
19
+ };
20
+ export declare const getShareLinks: PluginDataHelper<{
21
+ entry: PublicContentEntry;
22
+ site: Pick<ResolvedRiebeckiteConfig, "site">;
23
+ options?: ShareOptions;
24
+ }, ShareLinksData>;
8
25
  export declare const SHARE_PLUGIN_NAME = "share";
9
26
  /**
10
27
  * Per-article share controls.
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // index.ts
2
2
  import {
3
- appendContentBodySlot,
4
3
  createClientEntry,
5
4
  createStyleAsset,
6
5
  definePlugin
@@ -89,14 +88,12 @@ var DEFAULT_SHARE_LABELS = {
89
88
  hatena: "Hatena Bookmark",
90
89
  copy: "Copy link"
91
90
  };
92
- var DEFAULT_SHARE_PLACEMENT = "bottom";
93
91
  var DEFAULT_SHARE_ARIA_LABEL = "Share";
94
92
  var DEFAULT_SHARE_COPIED_LABEL = "Copied";
95
93
  var DEFAULT_SHARE_COPY_FAILED_LABEL = "Copy failed";
96
94
  function resolveShareOptions(options = {}) {
97
95
  return {
98
96
  services: normalizeServices(options.services),
99
- placement: options.placement === "top" ? "top" : DEFAULT_SHARE_PLACEMENT,
100
97
  mastodonInstance: normalizeMastodonInstance(options.mastodonInstance),
101
98
  className: normalizeNonEmpty(options.className, ""),
102
99
  ariaLabel: normalizeNonEmpty(options.ariaLabel, DEFAULT_SHARE_ARIA_LABEL),
@@ -145,12 +142,6 @@ function validateShareOptions(options) {
145
142
  message: "Expected a non-empty string."
146
143
  });
147
144
  }
148
- if (options.placement !== void 0 && options.placement !== "top" && options.placement !== "bottom") {
149
- issues.push({
150
- path: "placement",
151
- message: 'Expected "top" or "bottom".'
152
- });
153
- }
154
145
  for (const key of [
155
146
  "className",
156
147
  "ariaLabel",
@@ -227,7 +218,7 @@ function renderShareControls(options, target) {
227
218
  const items = links.map(renderLinkItem).join("");
228
219
  const copyItem = wantsCopy ? renderCopyItem(options, target) : "";
229
220
  const ariaLabel = escapeHtmlAttribute(options.ariaLabel);
230
- return `<div class="${escapeHtmlAttribute(rootClass)}" ${SHARE_ATTRIBUTE} data-rr-share-placement="${escapeHtmlAttribute(options.placement)}" role="group" aria-label="${ariaLabel}"><ul class="${SHARE_ROOT_CLASS}__list">${items}${copyItem}</ul><p class="${SHARE_ROOT_CLASS}__status" role="status" aria-live="polite"></p></div>`;
221
+ return `<div class="${escapeHtmlAttribute(rootClass)}" ${SHARE_ATTRIBUTE} role="group" aria-label="${ariaLabel}"><ul class="${SHARE_ROOT_CLASS}__list">${items}${copyItem}</ul><p class="${SHARE_ROOT_CLASS}__status" role="status" aria-live="polite"></p></div>`;
231
222
  }
232
223
  function renderLinkItem(link) {
233
224
  const modifier = `${SHARE_ROOT_CLASS}__link--${link.service}`;
@@ -237,6 +228,51 @@ function renderCopyItem(options, target) {
237
228
  return `<li class="${SHARE_ROOT_CLASS}__item"><button type="button" class="${SHARE_ROOT_CLASS}__button ${SHARE_ROOT_CLASS}__copy" data-rr-share-copy data-share-url="${escapeHtmlAttribute(target.url)}" data-rr-share-copied="${escapeHtmlAttribute(options.copiedLabel)}" data-rr-share-copy-failed="${escapeHtmlAttribute(options.copyFailedLabel)}" hidden>${escapeHtml(options.labels.copy)}</button></li>`;
238
229
  }
239
230
 
231
+ // components/share-controls.tsx
232
+ import { jsx, jsxs } from "hono/jsx/jsx-runtime";
233
+ var ShareControls = (({
234
+ links,
235
+ copyUrl,
236
+ ariaLabel = "Share",
237
+ className = "rr-share",
238
+ copyLabel = "Copy link",
239
+ copiedLabel = "Copied",
240
+ copyFailedLabel = "Copy failed"
241
+ }) => {
242
+ if (links.length === 0 && !copyUrl) return null;
243
+ const rootClass = className === "rr-share" ? className : `rr-share ${className}`;
244
+ return /* @__PURE__ */ jsxs("nav", { class: rootClass, "data-rr-share": true, "aria-label": ariaLabel, children: [
245
+ /* @__PURE__ */ jsxs("ul", { class: "rr-share__list", children: [
246
+ links.map((link) => /* @__PURE__ */ jsx("li", { class: "rr-share__item", children: /* @__PURE__ */ jsx(
247
+ "a",
248
+ {
249
+ class: `rr-share__link rr-share__link--${link.service}`,
250
+ href: link.url,
251
+ target: "_blank",
252
+ rel: "noopener noreferrer",
253
+ "data-share-service": link.service,
254
+ children: link.label
255
+ }
256
+ ) }, link.service)),
257
+ copyUrl ? /* @__PURE__ */ jsx("li", { class: "rr-share__item", children: /* @__PURE__ */ jsx(
258
+ "button",
259
+ {
260
+ type: "button",
261
+ class: "rr-share__button rr-share__copy",
262
+ "data-rr-share-copy": true,
263
+ "data-share-url": copyUrl,
264
+ "data-rr-share-copied": copiedLabel,
265
+ "data-rr-share-copy-failed": copyFailedLabel,
266
+ hidden: true,
267
+ children: copyLabel
268
+ }
269
+ ) }) : null
270
+ ] }),
271
+ /* @__PURE__ */ jsx("p", { class: "rr-share__status", role: "status", "aria-live": "polite" })
272
+ ] });
273
+ });
274
+ var share_controls_default = ShareControls;
275
+
240
276
  // src/client.ts
241
277
  var COPY_SELECTOR = "[data-rr-share-copy]";
242
278
  var STATUS_SELECTOR = ".rr-share__status";
@@ -302,9 +338,22 @@ function copyWithExecCommand(value) {
302
338
  }
303
339
 
304
340
  // index.ts
341
+ var getShareLinks = ({ entry, site, options }) => {
342
+ const resolved = resolveShareOptions(options);
343
+ const url = buildAbsoluteUrl(site, entry.permalink);
344
+ return {
345
+ links: buildShareLinks(resolved, { url, title: entry.title }),
346
+ ...resolved.services.includes("copy") ? { copyUrl: url } : {},
347
+ ariaLabel: resolved.ariaLabel,
348
+ className: resolved.className || SHARE_ROOT_CLASS,
349
+ copyLabel: resolved.labels.copy,
350
+ copiedLabel: resolved.copiedLabel,
351
+ copyFailedLabel: resolved.copyFailedLabel
352
+ };
353
+ };
305
354
  var SHARE_PLUGIN_NAME = "share";
306
355
  function share(options = {}) {
307
- const resolved = resolveShareOptions(options);
356
+ const _resolved = resolveShareOptions(options);
308
357
  return definePlugin({
309
358
  name: SHARE_PLUGIN_NAME,
310
359
  processedContentCache: {
@@ -313,47 +362,34 @@ function share(options = {}) {
313
362
  },
314
363
  options,
315
364
  validateOptions: validateShareOptions,
316
- onManifestCreated: (context) => {
317
- const { manifest, config } = context;
318
- if (!config) return;
319
- for (const entry of manifest.entries) {
320
- const block = renderShareControls(resolved, {
321
- url: buildAbsoluteUrl(config, entry.permalink),
322
- title: entry.title
323
- });
324
- if (block === "") continue;
325
- const slot = resolved.placement === "top" ? "article.before-content" : "article.footer";
326
- if (!hasSlotFragment(entry.bodySlots?.[slot], block)) {
327
- appendContentBodySlot(entry, slot, block);
328
- }
329
- }
330
- },
331
- assets: [createStyleAsset(SHARE_PLUGIN_NAME)],
332
- clientEntries: [createClientEntry(SHARE_PLUGIN_NAME, "initShare")]
365
+ assets: [
366
+ createStyleAsset(SHARE_PLUGIN_NAME, "@riebeckite/plugin-share/style.css")
367
+ ],
368
+ clientEntries: [
369
+ createClientEntry(
370
+ SHARE_PLUGIN_NAME,
371
+ "@riebeckite/plugin-share/client",
372
+ "initShare"
373
+ )
374
+ ]
333
375
  });
334
376
  }
335
377
  var sharePlugin = share;
336
- function hasSlotFragment(slot, fragment) {
337
- return slot === fragment || slot?.startsWith(`${fragment}
338
- `) || slot?.endsWith(`
339
- ${fragment}`) || slot?.includes(`
340
- ${fragment}
341
- `) || false;
342
- }
343
378
  export {
344
379
  DEFAULT_SHARE_ARIA_LABEL,
345
380
  DEFAULT_SHARE_COPIED_LABEL,
346
381
  DEFAULT_SHARE_COPY_FAILED_LABEL,
347
382
  DEFAULT_SHARE_LABELS,
348
- DEFAULT_SHARE_PLACEMENT,
349
383
  DEFAULT_SHARE_SERVICES,
350
384
  SHARE_ATTRIBUTE,
351
385
  SHARE_PLUGIN_NAME,
352
386
  SHARE_ROOT_CLASS,
353
387
  SHARE_SERVICES,
388
+ share_controls_default as ShareControls,
354
389
  buildAbsoluteUrl,
355
390
  buildShareLinks,
356
391
  buildShareUrl,
392
+ getShareLinks,
357
393
  initShare,
358
394
  normalizeMastodonInstance,
359
395
  renderShareControls,
@@ -1,9 +1,8 @@
1
1
  import type { ConfigValidationIssue } from "@riebeckite/core";
2
- import { type ResolvedShareOptions, type ShareOptions, type SharePlacement, type ShareService } from "./types.js";
2
+ import { type ResolvedShareOptions, type ShareOptions, type ShareService } from "./types.js";
3
3
  /** Services rendered when `services` is omitted. Mastodon is opt-in. */
4
4
  export declare const DEFAULT_SHARE_SERVICES: readonly ShareService[];
5
5
  export declare const DEFAULT_SHARE_LABELS: Readonly<Record<ShareService, string>>;
6
- export declare const DEFAULT_SHARE_PLACEMENT: SharePlacement;
7
6
  export declare const DEFAULT_SHARE_ARIA_LABEL = "Share";
8
7
  export declare const DEFAULT_SHARE_COPIED_LABEL = "Copied";
9
8
  export declare const DEFAULT_SHARE_COPY_FAILED_LABEL = "Copy failed";
@@ -11,7 +11,7 @@ export type ShareTarget = {
11
11
  * Resolves a note's `permalink` to an absolute URL against the site base URL.
12
12
  * Already-absolute URLs are returned unchanged.
13
13
  */
14
- export declare function buildAbsoluteUrl(config: ResolvedRiebeckiteConfig, pathOrUrl: string): string;
14
+ export declare function buildAbsoluteUrl(config: Pick<ResolvedRiebeckiteConfig, "site">, pathOrUrl: string): string;
15
15
  /**
16
16
  * Normalizes a Mastodon instance to a bare host. Accepts `"mastodon.social"`,
17
17
  * `"https://mastodon.social/"`, and `"https://mastodon.social/@user"` (the
@@ -1,8 +1,6 @@
1
1
  /** Services a note can be shared to. `copy` is the copy-link action. */
2
2
  export declare const SHARE_SERVICES: readonly ["x", "bluesky", "mastodon", "facebook", "linkedin", "hatena", "copy"];
3
3
  export type ShareService = (typeof SHARE_SERVICES)[number];
4
- /** Where the controls sit relative to the note body. */
5
- export type SharePlacement = "top" | "bottom";
6
4
  /** Options accepted by `share()`. */
7
5
  export type ShareOptions = {
8
6
  /**
@@ -11,8 +9,6 @@ export type ShareOptions = {
11
9
  * to enable it.
12
10
  */
13
11
  services?: readonly ShareService[];
14
- /** Where the controls appear. Defaults to `"bottom"`. */
15
- placement?: SharePlacement;
16
12
  /**
17
13
  * Instance host used by the `mastodon` service, for example
18
14
  * `"mastodon.social"`. Accepts a bare host or a full URL; the scheme and
@@ -37,7 +33,6 @@ export type ShareOptions = {
37
33
  /** `ShareOptions` with every default applied. */
38
34
  export type ResolvedShareOptions = {
39
35
  services: readonly ShareService[];
40
- placement: SharePlacement;
41
36
  mastodonInstance: string;
42
37
  className: string;
43
38
  ariaLabel: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riebeckite/plugin-share",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,10 +18,17 @@
18
18
  "source": "./client.ts",
19
19
  "default": "./dist/client.js"
20
20
  },
21
+ "./components": {
22
+ "types": "./dist/components/share-controls.d.ts",
23
+ "import": "./dist/components/share-controls.js",
24
+ "source": "./components/share-controls.tsx",
25
+ "default": "./dist/components/share-controls.js"
26
+ },
21
27
  "./style.css": "./style.css"
22
28
  },
23
29
  "dependencies": {
24
- "@riebeckite/core": "0.0.21"
30
+ "hono": "^4.12.25",
31
+ "@riebeckite/core": "0.0.23"
25
32
  },
26
33
  "devDependencies": {
27
34
  "tsx": "^4.22.4"