@makershq/react 0.0.0-stage → 0.3.1

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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -2
  3. package/THIRD_PARTY_NOTICES.md +77 -0
  4. package/dist/api.d.ts +82 -0
  5. package/dist/api.js +183 -0
  6. package/dist/cache.d.ts +22 -0
  7. package/dist/cache.js +86 -0
  8. package/dist/components/icons/external-link/index.d.ts +52 -0
  9. package/dist/components/icons/external-link/index.js +60 -0
  10. package/dist/components/icons/index.d.ts +31 -0
  11. package/dist/components/icons/index.js +56 -0
  12. package/dist/components/icons/reduced-motion.d.ts +4 -0
  13. package/dist/components/icons/reduced-motion.js +24 -0
  14. package/dist/components/icons/x/index.d.ts +98 -0
  15. package/dist/components/icons/x/index.js +87 -0
  16. package/dist/components/release-markdown/index.d.ts +22 -0
  17. package/dist/components/release-markdown/index.js +101 -0
  18. package/dist/components/release-notes/index.d.ts +51 -0
  19. package/dist/components/release-notes/index.js +89 -0
  20. package/dist/connectors/use-release-note-list-connector.d.ts +24 -0
  21. package/dist/connectors/use-release-note-list-connector.js +219 -0
  22. package/dist/index.d.ts +20 -0
  23. package/dist/index.js +13 -0
  24. package/dist/styles.css +2 -0
  25. package/dist/styles.d.ts +8 -0
  26. package/dist/tauri/components/native-child/index.d.ts +19 -0
  27. package/dist/tauri/components/native-child/index.js +146 -0
  28. package/dist/tauri/components/native-child/theme.d.ts +12 -0
  29. package/dist/tauri/components/native-child/theme.js +45 -0
  30. package/dist/tauri/components/release-notes-host/index.d.ts +36 -0
  31. package/dist/tauri/components/release-notes-host/index.js +81 -0
  32. package/dist/tauri/components/release-notes-settings/index.d.ts +10 -0
  33. package/dist/tauri/components/release-notes-settings/index.js +23 -0
  34. package/dist/tauri/components/update-window/index.d.ts +20 -0
  35. package/dist/tauri/components/update-window/index.js +68 -0
  36. package/dist/tauri/context.d.ts +20 -0
  37. package/dist/tauri/context.js +22 -0
  38. package/dist/tauri/contracts.d.ts +84 -0
  39. package/dist/tauri/contracts.js +7 -0
  40. package/dist/tauri/hooks/use-release-notes.d.ts +92 -0
  41. package/dist/tauri/hooks/use-release-notes.js +101 -0
  42. package/dist/tauri/host-controller.d.ts +134 -0
  43. package/dist/tauri/host-controller.js +951 -0
  44. package/dist/tauri/index.d.ts +10 -0
  45. package/dist/tauri/index.js +9 -0
  46. package/dist/tauri/peer-protocol.d.ts +36 -0
  47. package/dist/tauri/peer-protocol.js +43 -0
  48. package/dist/tauri/preferences.d.ts +18 -0
  49. package/dist/tauri/preferences.js +39 -0
  50. package/dist/tauri/protocol.d.ts +71 -0
  51. package/dist/tauri/protocol.js +106 -0
  52. package/dist/tauri/remote-settings-client.d.ts +72 -0
  53. package/dist/tauri/remote-settings-client.js +265 -0
  54. package/dist/website/components/update-toast/index.d.ts +14 -0
  55. package/dist/website/components/update-toast/index.js +22 -0
  56. package/dist/website/components/website-updates/index.d.ts +24 -0
  57. package/dist/website/components/website-updates/index.js +35 -0
  58. package/dist/website/components/whats-new-panel/index.d.ts +23 -0
  59. package/dist/website/components/whats-new-panel/index.js +38 -0
  60. package/dist/website/preferences.d.ts +32 -0
  61. package/dist/website/preferences.js +85 -0
  62. package/dist/website/use-website-updates-connector.d.ts +34 -0
  63. package/dist/website/use-website-updates-connector.js +318 -0
  64. package/dist/website/version.d.ts +27 -0
  65. package/dist/website/version.js +73 -0
  66. package/package.json +71 -3
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Provides isolated private SDK icons using original Lucide geometry and Animate UI defaults.
3
+ *
4
+ * Owns reduced-motion gates and native control boundaries without consumer app imports.
5
+ *
6
+ * Retain third-party notices and upstream playback defaults when adding artwork.
7
+ */
8
+ import type { ReactElement } from 'react';
9
+ import { type IconProps } from '@animate-ui/react/icons';
10
+ export { X } from './x/index.js';
11
+ export { ExternalLink } from './external-link/index.js';
12
+ /** Renders the original Lucide Newspaper with Animate UI's built-in path variant.
13
+ * @param props - Private SVG and upstream playback controls.
14
+ * @returns The accessible-hidden icon artwork.
15
+ */
16
+ export declare function NewspaperIcon(props: IconProps<'path'>): import("react").JSX.Element;
17
+ /** Renders the original Lucide RefreshCw using the built-in path variant.
18
+ * @param props - Private SVG presentation controls.
19
+ * @returns The refresh icon artwork.
20
+ */
21
+ export declare function RefreshIcon(props: IconProps<'path'>): import("react").JSX.Element;
22
+ /** Attaches upstream hover/tap animation to the actual button or anchor.
23
+ * @param props - Native control child and its disabled state.
24
+ * @param props.children - The single native actionable element.
25
+ * @param props.disabled - Whether the control is temporarily unavailable.
26
+ * @returns The unchanged native control with reduced-motion-safe triggers.
27
+ */
28
+ export declare function IconAction({ children, disabled, }: {
29
+ children: ReactElement;
30
+ disabled?: boolean;
31
+ }): import("react").JSX.Element;
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { motion } from 'motion/react';
3
+ import { useIconReducedMotion } from './reduced-motion.js';
4
+ import { AnimateIcon, IconWrapper, staticAnimations, useAnimateIconContext, } from '@animate-ui/react/icons';
5
+ export { X } from './x/index.js';
6
+ export { ExternalLink } from './external-link/index.js';
7
+ function NewspaperDrawing({ size, ...props }) {
8
+ const { controls } = useAnimateIconContext();
9
+ const reduced = useIconReducedMotion();
10
+ const playback = {
11
+ variants: staticAnimations.path,
12
+ initial: 'initial',
13
+ animate: reduced === false ? controls : 'initial',
14
+ };
15
+ return (_jsxs(motion.svg, { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx(motion.path, { d: "M15 18h-5", ...playback }), _jsx(motion.path, { d: "M18 14h-8", ...playback }), _jsx(motion.path, { d: "M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2", ...playback }), _jsx(motion.rect, { width: "8", height: "4", x: "10", y: "6", rx: "1", ...playback })] }, reduced ? 'static' : 'animated'));
16
+ }
17
+ function RefreshDrawing({ size, ...props }) {
18
+ const { controls } = useAnimateIconContext();
19
+ const reduced = useIconReducedMotion();
20
+ const playback = {
21
+ variants: staticAnimations.path,
22
+ initial: 'initial',
23
+ animate: reduced === false ? controls : 'initial',
24
+ };
25
+ return (_jsxs(motion.svg, { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx(motion.path, { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", ...playback }), _jsx(motion.path, { d: "M21 3v5h-5", ...playback }), _jsx(motion.path, { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", ...playback }), _jsx(motion.path, { d: "M8 16H3v5", ...playback })] }, reduced ? 'static' : 'animated'));
26
+ }
27
+ /** Renders the original Lucide Newspaper with Animate UI's built-in path variant.
28
+ * @param props - Private SVG and upstream playback controls.
29
+ * @returns The accessible-hidden icon artwork.
30
+ */
31
+ export function NewspaperIcon(props) {
32
+ const reduced = useIconReducedMotion();
33
+ return (_jsx(IconWrapper, { icon: NewspaperDrawing, ...props, animateOnView: props.animateOnView === undefined
34
+ ? undefined
35
+ : reduced === false && props.animateOnView }));
36
+ }
37
+ /** Renders the original Lucide RefreshCw using the built-in path variant.
38
+ * @param props - Private SVG presentation controls.
39
+ * @returns The refresh icon artwork.
40
+ */
41
+ export function RefreshIcon(props) {
42
+ const reduced = useIconReducedMotion();
43
+ return (_jsx(IconWrapper, { icon: RefreshDrawing, ...props, animateOnView: props.animateOnView === undefined
44
+ ? undefined
45
+ : reduced === false && props.animateOnView }));
46
+ }
47
+ /** Attaches upstream hover/tap animation to the actual button or anchor.
48
+ * @param props - Native control child and its disabled state.
49
+ * @param props.children - The single native actionable element.
50
+ * @param props.disabled - Whether the control is temporarily unavailable.
51
+ * @returns The unchanged native control with reduced-motion-safe triggers.
52
+ */
53
+ export function IconAction({ children, disabled = false, }) {
54
+ const reduced = useIconReducedMotion();
55
+ return (_jsx(AnimateIcon, { asChild: true, animateOnHover: !disabled && reduced === false, animateOnTap: !disabled && reduced === false, children: children }));
56
+ }
@@ -0,0 +1,4 @@
1
+ /** Reads live reduced motion without accessing browser state during SSR.
2
+ * @returns True when motion must be disabled or browser preference is unavailable.
3
+ */
4
+ export declare function useIconReducedMotion(): boolean;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Tracks the browser's live reduced-motion preference for private SDK icons.
3
+ *
4
+ * Owns one native media subscription per mounted subscriber and an SSR-safe static snapshot.
5
+ *
6
+ * Keep this gate local to icons; do not replace Animate UI playback or timing.
7
+ */
8
+ import { useSyncExternalStore } from 'react';
9
+ const query = '(prefers-reduced-motion: reduce)';
10
+ const serverSnapshot = () => true;
11
+ const snapshot = () => typeof window.matchMedia !== 'function' || window.matchMedia(query).matches;
12
+ const subscribe = (listener) => {
13
+ if (typeof window.matchMedia !== 'function')
14
+ return () => { };
15
+ const media = window.matchMedia(query);
16
+ media.addEventListener('change', listener);
17
+ return () => media.removeEventListener('change', listener);
18
+ };
19
+ /** Reads live reduced motion without accessing browser state during SSR.
20
+ * @returns True when motion must be disabled or browser preference is unavailable.
21
+ */
22
+ export function useIconReducedMotion() {
23
+ return useSyncExternalStore(subscribe, snapshot, serverSnapshot);
24
+ }
@@ -0,0 +1,98 @@
1
+ import { type IconProps } from '@animate-ui/react/icons';
2
+ type XProps = IconProps<keyof typeof animations>;
3
+ declare const animations: {
4
+ readonly default: {
5
+ line1: {
6
+ initial: {
7
+ rotate: number;
8
+ transition: {
9
+ ease: "easeInOut";
10
+ duration: number;
11
+ };
12
+ };
13
+ animate: {
14
+ rotate: number;
15
+ transition: {
16
+ ease: "easeInOut";
17
+ duration: number;
18
+ };
19
+ };
20
+ };
21
+ line2: {
22
+ initial: {
23
+ rotate: number;
24
+ transition: {
25
+ ease: "easeInOut";
26
+ duration: number;
27
+ delay: number;
28
+ };
29
+ };
30
+ animate: {
31
+ rotate: number;
32
+ transition: {
33
+ ease: "easeInOut";
34
+ duration: number;
35
+ delay: number;
36
+ };
37
+ };
38
+ };
39
+ };
40
+ readonly plus: {
41
+ line1: {
42
+ initial: {
43
+ rotate: number;
44
+ x1: number;
45
+ y1: number;
46
+ x2: number;
47
+ y2: number;
48
+ transition: {
49
+ ease: "easeInOut";
50
+ duration: number;
51
+ delay: number;
52
+ };
53
+ };
54
+ animate: {
55
+ rotate: number;
56
+ x1: number;
57
+ y1: number;
58
+ x2: number;
59
+ y2: number;
60
+ transition: {
61
+ ease: "easeInOut";
62
+ duration: number;
63
+ delay: number;
64
+ };
65
+ };
66
+ };
67
+ line2: {
68
+ initial: {
69
+ rotate: number;
70
+ x1: number;
71
+ y1: number;
72
+ x2: number;
73
+ y2: number;
74
+ transition: {
75
+ ease: "easeInOut";
76
+ duration: number;
77
+ };
78
+ };
79
+ animate: {
80
+ rotate: number;
81
+ x1: number;
82
+ y1: number;
83
+ x2: number;
84
+ y2: number;
85
+ transition: {
86
+ ease: "easeInOut";
87
+ duration: number;
88
+ };
89
+ };
90
+ };
91
+ };
92
+ };
93
+ /** Renders Animate UI's original x icon.
94
+ * @param props - Upstream SVG presentation and playback controls.
95
+ * @returns The original vector artwork and animation.
96
+ */
97
+ export declare function X(props: XProps): import("react").JSX.Element;
98
+ export {};
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Provides Animate UI's original x icon from the official registry.
3
+ *
4
+ * Preserves upstream rendering, variants, timing and easing without motion overrides.
5
+ *
6
+ * Follow README.md when updating registry sources; retain the adjacent license notices.
7
+ */
8
+ 'use client';
9
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ import { motion } from 'motion/react';
11
+ import { useIconReducedMotion } from '../reduced-motion.js';
12
+ import { getVariants, useAnimateIconContext, IconWrapper, } from '@animate-ui/react/icons';
13
+ const animations = {
14
+ default: {
15
+ line1: {
16
+ initial: {
17
+ rotate: 0,
18
+ transition: { ease: 'easeInOut', duration: 0.4 },
19
+ },
20
+ animate: {
21
+ rotate: 90,
22
+ transition: { ease: 'easeInOut', duration: 0.4 },
23
+ },
24
+ },
25
+ line2: {
26
+ initial: {
27
+ rotate: 0,
28
+ transition: { ease: 'easeInOut', duration: 0.4, delay: 0.1 },
29
+ },
30
+ animate: {
31
+ rotate: 90,
32
+ transition: { ease: 'easeInOut', duration: 0.4, delay: 0.1 },
33
+ },
34
+ },
35
+ },
36
+ plus: {
37
+ line1: {
38
+ initial: {
39
+ rotate: 0,
40
+ x1: 6,
41
+ y1: 18,
42
+ x2: 18,
43
+ y2: 6,
44
+ transition: { ease: 'easeInOut', duration: 0.3, delay: 0.1 },
45
+ },
46
+ animate: {
47
+ rotate: 45,
48
+ x1: 7.1,
49
+ y1: 16.9,
50
+ x2: 16.9,
51
+ y2: 7.1,
52
+ transition: { ease: 'easeInOut', duration: 0.3, delay: 0.1 },
53
+ },
54
+ },
55
+ line2: {
56
+ initial: {
57
+ rotate: 0,
58
+ x1: 6,
59
+ y1: 6,
60
+ x2: 18,
61
+ y2: 18,
62
+ transition: { ease: 'easeInOut', duration: 0.3 },
63
+ },
64
+ animate: {
65
+ rotate: 45,
66
+ x1: 7.1,
67
+ y1: 7.1,
68
+ x2: 16.9,
69
+ y2: 16.9,
70
+ transition: { ease: 'easeInOut', duration: 0.3 },
71
+ },
72
+ },
73
+ },
74
+ };
75
+ function IconComponent({ size, ...props }) {
76
+ const { controls } = useAnimateIconContext();
77
+ const reduced = useIconReducedMotion();
78
+ const variants = getVariants(animations);
79
+ return (_jsxs(motion.svg, { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx(motion.line, { x1: 6, y1: 18, x2: 18, y2: 6, variants: variants.line1, initial: "initial", animate: reduced ? 'initial' : controls }), _jsx(motion.line, { x1: 6, y1: 6, x2: 18, y2: 18, variants: variants.line2, initial: "initial", animate: reduced ? 'initial' : controls })] }, reduced ? 'static' : 'animated'));
80
+ }
81
+ /** Renders Animate UI's original x icon.
82
+ * @param props - Upstream SVG presentation and playback controls.
83
+ * @returns The original vector artwork and animation.
84
+ */
85
+ export function X(props) {
86
+ return _jsx(IconWrapper, { icon: IconComponent, ...props });
87
+ }
@@ -0,0 +1,22 @@
1
+ import { type Release } from '../../api.js';
2
+ /** Properties owned by the restricted Markdown renderer. */
3
+ export interface ReleaseMarkdownProps {
4
+ projectId: string;
5
+ /** Project owning managed images. */
6
+ release: Release;
7
+ /** Validated public document. */
8
+ openExternal?: (url: string) => void | Promise<void>; /**
9
+ * Optional native HTTP(S) opener.
10
+ * @param url - Safe external destination.
11
+ * @returns Completion of the opening request.
12
+ */
13
+ }
14
+ /**
15
+ * Displays full safe release Markdown, including the editor's image dimensions.
16
+ * @param props - Validated document and image ownership.
17
+ * @param props.projectId - Project owning managed images.
18
+ * @param props.release - Validated complete release.
19
+ * @param props.openExternal - Optional native link opener.
20
+ * @returns Sanitized document elements with no executable HTML.
21
+ */
22
+ export declare function ReleaseMarkdown({ projectId, release, openExternal, }: ReleaseMarkdownProps): import("react").JSX.Element;
@@ -0,0 +1,101 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Renders untrusted release Markdown with a restricted HTML schema.
4
+ *
5
+ * Owns GFM, safe links, release-scoped images and editor image dimensions.
6
+ *
7
+ * Extend the explicit allowlist only after adding an adversarial rendering test.
8
+ */
9
+ import Markdown from 'react-markdown';
10
+ import remarkGfm from 'remark-gfm';
11
+ import rehypeRaw from 'rehype-raw';
12
+ import rehypeSanitize from 'rehype-sanitize';
13
+ import { releaseImageUrl, safeHttpUrl } from '../../api.js';
14
+ const schema = {
15
+ tagNames: [
16
+ 'p',
17
+ 'br',
18
+ 'h1',
19
+ 'h2',
20
+ 'h3',
21
+ 'h4',
22
+ 'h5',
23
+ 'h6',
24
+ 'strong',
25
+ 'em',
26
+ 'del',
27
+ 'blockquote',
28
+ 'ul',
29
+ 'ol',
30
+ 'li',
31
+ 'hr',
32
+ 'pre',
33
+ 'code',
34
+ 'a',
35
+ 'img',
36
+ 'table',
37
+ 'thead',
38
+ 'tbody',
39
+ 'tr',
40
+ 'th',
41
+ 'td',
42
+ 'input',
43
+ ],
44
+ attributes: {
45
+ a: ['href', 'title'],
46
+ img: ['src', 'alt', 'title', 'width', 'height'],
47
+ ol: ['start'],
48
+ li: ['className'],
49
+ code: ['className'],
50
+ th: ['align'],
51
+ td: ['align'],
52
+ input: ['type', 'checked', 'disabled'],
53
+ },
54
+ protocols: { href: ['http', 'https'], src: ['http', 'https'] },
55
+ required: { input: { type: 'checkbox', disabled: true } },
56
+ clobberPrefix: 'fl-notes-',
57
+ strip: [
58
+ 'script',
59
+ 'style',
60
+ 'iframe',
61
+ 'object',
62
+ 'embed',
63
+ 'form',
64
+ 'svg',
65
+ 'math',
66
+ ],
67
+ };
68
+ /**
69
+ * Displays full safe release Markdown, including the editor's image dimensions.
70
+ * @param props - Validated document and image ownership.
71
+ * @param props.projectId - Project owning managed images.
72
+ * @param props.release - Validated complete release.
73
+ * @param props.openExternal - Optional native link opener.
74
+ * @returns Sanitized document elements with no executable HTML.
75
+ */
76
+ export function ReleaseMarkdown({ projectId, release, openExternal, }) {
77
+ return (_jsx("div", { className: "fl-notes-markdown", children: _jsx(Markdown, { remarkPlugins: [remarkGfm], rehypePlugins: [rehypeRaw, [rehypeSanitize, schema]], urlTransform: (value, key) => key === 'src'
78
+ ? releaseImageUrl(projectId, release.id, value)
79
+ : safeHttpUrl(value), components: {
80
+ a({ href, children, title }) {
81
+ return (_jsx("a", { href: href, title: title, target: "_blank", rel: "noopener noreferrer", onClick: openExternal && href
82
+ ? (event) => {
83
+ event.preventDefault();
84
+ void openExternal(href);
85
+ }
86
+ : undefined, children: children }));
87
+ },
88
+ img({ src, alt, title, width, height }) {
89
+ const safe = typeof src === 'string' ? safeHttpUrl(src) : undefined;
90
+ if (!safe)
91
+ return alt ? _jsx("span", { children: alt }) : null;
92
+ const dimension = (value) => {
93
+ const number = Number(value);
94
+ return Number.isInteger(number) && number > 0 && number <= 10000
95
+ ? number
96
+ : undefined;
97
+ };
98
+ return (_jsx("img", { src: safe, alt: alt ?? '', title: title, width: dimension(width), height: dimension(height), loading: "lazy", referrerPolicy: "no-referrer" }));
99
+ },
100
+ }, children: release.markdown }) }));
101
+ }
@@ -0,0 +1,51 @@
1
+ import { type Release } from '../../api.js';
2
+ import { type ReleaseNotesReaderOptions } from '../../connectors/use-release-note-list-connector.js';
3
+ /** Public browser reader configuration. */
4
+ export interface ReleaseNotesProps extends ReleaseNotesReaderOptions {
5
+ theme?: 'system' | 'light' | 'dark';
6
+ /** Reader color scheme; system follows the operating system. */
7
+ onReleaseRendered?: (release: Release, state: {
8
+ cached: boolean;
9
+ }) => void; /**
10
+ * Reports an exact note mounted in the reader.
11
+ * @param release - The rendered document.
12
+ * @param release.id - Stable public release identifier.
13
+ * @param release.version - Optional exact application version.
14
+ * @param release.title - Human-readable title.
15
+ * @param release.excerpt - Optional plain-text preview.
16
+ * @param release.previewImageSource - Optional preview image source.
17
+ * @param release.markdown - Complete release document.
18
+ * @param release.date - Publication calendar date.
19
+ * @param release.url - Public article URL.
20
+ * @param state - Whether the document came from offline storage.
21
+ * @param state.cached - True for an offline copy.
22
+ * @returns Nothing.
23
+ */
24
+ openExternal?: (url: string) => void | Promise<void>; /**
25
+ * Optional HTTP(S) link opener.
26
+ * @param url - Safe destination.
27
+ * @returns Opening completion.
28
+ */
29
+ }
30
+ /**
31
+ * Renders published project notes without providers, keys or native dependencies.
32
+ * @param props - Public project, initial exact version and color scheme.
33
+ * @param props.projectId - Public project identifier.
34
+ * @param props.version - Optional exact semantic version.
35
+ * @param props.theme - Reader color scheme.
36
+ * @param props.onReleaseRendered - Confirms an exact note mounted in the reader.
37
+ * @param props.openExternal - Optional safe HTTP(S) link opener.
38
+ * @returns A self-contained anonymous release-note reader.
39
+ */
40
+ export declare function ReleaseNotes(props: ReleaseNotesProps): import("react").JSX.Element;
41
+ /**
42
+ * Shares reader content with optional native window adapters.
43
+ * @param props - Public reader properties and optional presentation callbacks.
44
+ * @param props.projectId - Public project identifier.
45
+ * @param props.version - Optional exact semantic version.
46
+ * @param props.theme - Reader color scheme.
47
+ * @param props.onReleaseRendered - Optional exact-note render confirmation.
48
+ * @param props.openExternal - Optional native link opener.
49
+ * @returns The complete accessible release reader.
50
+ */
51
+ export declare function ReleaseNotesReader({ projectId, version, theme, onReleaseRendered, openExternal, }: ReleaseNotesProps): import("react").JSX.Element;
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Displays the version-first anonymous release reader.
4
+ *
5
+ * Owns exact-version navigation, display states and native render confirmation.
6
+ *
7
+ * Keep data loading in the reader connector and external links restricted to HTTP(S).
8
+ */
9
+ import { useEffect, useRef, useState } from 'react';
10
+ import { normalizeReleaseVersion, releaseProjectUrl, safeHttpUrl, } from '../../api.js';
11
+ import { useReleaseNoteListConnector, } from '../../connectors/use-release-note-list-connector.js';
12
+ import { ReleaseMarkdown } from '../release-markdown/index.js';
13
+ /**
14
+ * Renders published project notes without providers, keys or native dependencies.
15
+ * @param props - Public project, initial exact version and color scheme.
16
+ * @param props.projectId - Public project identifier.
17
+ * @param props.version - Optional exact semantic version.
18
+ * @param props.theme - Reader color scheme.
19
+ * @param props.onReleaseRendered - Confirms an exact note mounted in the reader.
20
+ * @param props.openExternal - Optional safe HTTP(S) link opener.
21
+ * @returns A self-contained anonymous release-note reader.
22
+ */
23
+ export function ReleaseNotes(props) {
24
+ return _jsx(ReleaseNotesReader, { ...props });
25
+ }
26
+ /**
27
+ * Shares reader content with optional native window adapters.
28
+ * @param props - Public reader properties and optional presentation callbacks.
29
+ * @param props.projectId - Public project identifier.
30
+ * @param props.version - Optional exact semantic version.
31
+ * @param props.theme - Reader color scheme.
32
+ * @param props.onReleaseRendered - Optional exact-note render confirmation.
33
+ * @param props.openExternal - Optional native link opener.
34
+ * @returns The complete accessible release reader.
35
+ */
36
+ export function ReleaseNotesReader({ projectId, version, theme = 'system', onReleaseRendered, openExternal, }) {
37
+ let normalizedVersion = version?.trim();
38
+ if (version !== undefined) {
39
+ try {
40
+ normalizedVersion = normalizeReleaseVersion(version);
41
+ }
42
+ catch {
43
+ /* Request reports invalid versions through the reader error state. */
44
+ }
45
+ }
46
+ const [historyFor, setHistoryFor] = useState(null);
47
+ const inputIdentity = JSON.stringify([projectId, normalizedVersion ?? null]);
48
+ const requestedVersion = historyFor === inputIdentity ? undefined : normalizedVersion;
49
+ const { loadMore, retry, ...current } = useReleaseNoteListConnector({
50
+ projectId,
51
+ version: requestedVersion,
52
+ });
53
+ const renderCallback = useRef(onReleaseRendered);
54
+ renderCallback.current = onReleaseRendered;
55
+ useEffect(() => {
56
+ if (requestedVersion &&
57
+ !current.loading &&
58
+ current.page?.items.length === 1) {
59
+ renderCallback.current?.(current.page.items[0], {
60
+ cached: current.cached,
61
+ });
62
+ }
63
+ }, [
64
+ projectId,
65
+ requestedVersion,
66
+ current.page,
67
+ current.loading,
68
+ current.cached,
69
+ ]);
70
+ function externalClick(event) {
71
+ if (openExternal) {
72
+ event.preventDefault();
73
+ void openExternal(event.currentTarget.href);
74
+ }
75
+ }
76
+ const fallback = current.page?.items[0]?.url ?? releaseProjectUrl(projectId);
77
+ return (_jsxs("section", { className: "fl-release-notes", "data-theme": theme, "aria-label": "Release notes", "aria-busy": current.loading || current.loadingMore, children: [requestedVersion !== undefined && (_jsx("button", { className: "fl-notes-button fl-notes-back", onClick: () => setHistoryFor(inputIdentity), children: "\u2190 All versions" })), current.loading && (_jsxs("div", { className: "fl-notes-status", role: "status", children: [_jsx("h2", { children: "Loading release notes\u2026" }), _jsx("p", { children: "The latest published notes will appear here." })] })), !current.loading && current.cached && (_jsx("p", { className: "fl-notes-notice", role: "status", children: "You\u2019re viewing a saved copy. Connect to load the latest notes." })), !current.loading && current.error && !current.cached && (_jsxs("div", { className: "fl-notes-status", role: "alert", children: [_jsx("h2", { children: current.unavailable
78
+ ? 'Release notes unavailable'
79
+ : 'Couldn’t load release notes' }), _jsx("p", { children: current.unavailable
80
+ ? 'This project or version is not available.'
81
+ : 'Check your connection and try again.' })] })), !current.loading &&
82
+ !current.error &&
83
+ current.page?.items.length === 0 && (_jsxs("div", { className: "fl-notes-status", children: [_jsx("h2", { children: "No release notes yet" }), _jsx("p", { children: requestedVersion
84
+ ? 'No published notes match this version.'
85
+ : 'Published updates will appear here.' })] })), current.page?.items.map((release) => (_jsxs("article", { className: "fl-notes-release", children: [_jsxs("header", { className: "fl-notes-heading", children: [_jsx("h2", { children: release.version ?? release.title }), _jsx("time", { dateTime: release.date, children: new Intl.DateTimeFormat(undefined, {
86
+ dateStyle: 'long',
87
+ timeZone: 'UTC',
88
+ }).format(new Date(`${release.date}T12:00:00Z`)) })] }), release.version && release.title !== release.version && (_jsx("h3", { className: "fl-notes-title", children: release.title })), _jsx(ReleaseMarkdown, { projectId: projectId, release: release, openExternal: openExternal })] }, release.id))), !current.loading && (_jsxs("footer", { className: "fl-notes-footer", children: [current.error && !current.unavailable && !current.cached && (_jsx("button", { className: "fl-notes-button", onClick: retry, children: "Try again" })), !current.cached && current.page?.nextCursor && !current.error && (_jsx("button", { className: "fl-notes-button", disabled: current.loadingMore, onClick: () => void loadMore(), children: current.loadingMore ? 'Loading…' : 'Load more' })), safeHttpUrl(fallback) && (_jsx("a", { href: fallback, target: "_blank", rel: "noopener noreferrer", onClick: externalClick, children: "View on the web \u2197" })), current.cached && (_jsx("button", { className: "fl-notes-button", onClick: retry, children: "Try again" }))] }))] }));
89
+ }
@@ -0,0 +1,24 @@
1
+ import { type ReleasePage } from '../api.js';
2
+ /** Public reader data configuration; navigation remains app-owned. */
3
+ export interface ReleaseNotesReaderOptions {
4
+ projectId: string;
5
+ /** Public project identifier. */
6
+ version?: string;
7
+ }
8
+ /**
9
+ * Loads anonymous notes with isolated offline copies and bounded pagination.
10
+ * @param options - Project and optional exact version.
11
+ * @param options.projectId - Public project identifier.
12
+ * @param options.version - Optional exact version.
13
+ * @returns Reader state, continuation and retry operations.
14
+ */
15
+ export declare function useReleaseNoteListConnector({ projectId, version, }: ReleaseNotesReaderOptions): {
16
+ page: ReleasePage | undefined;
17
+ loading: boolean;
18
+ loadingMore: boolean;
19
+ cached: boolean;
20
+ error: boolean;
21
+ unavailable: boolean;
22
+ loadMore: () => Promise<void> | undefined;
23
+ retry: () => void;
24
+ };