@curvenote/theme-ui 2.0.2 → 2.1.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.
Files changed (43) hide show
  1. package/dist/components/index.d.ts +1 -0
  2. package/dist/components/index.d.ts.map +1 -1
  3. package/dist/components/index.js +1 -0
  4. package/dist/components/layout/app-layout.d.ts +1 -1
  5. package/dist/components/layout/app-layout.d.ts.map +1 -1
  6. package/dist/components/layout/app-layout.js +8 -2
  7. package/dist/components/layout/site-header.d.ts.map +1 -1
  8. package/dist/components/layout/site-header.js +4 -2
  9. package/dist/components/layout/types.d.ts +5 -0
  10. package/dist/components/layout/types.d.ts.map +1 -1
  11. package/dist/components/providers/curvenote-providers.d.ts +15 -2
  12. package/dist/components/providers/curvenote-providers.d.ts.map +1 -1
  13. package/dist/components/providers/curvenote-providers.js +18 -4
  14. package/dist/components/site-renderers/host-import-map-script.d.ts +8 -0
  15. package/dist/components/site-renderers/host-import-map-script.d.ts.map +1 -0
  16. package/dist/components/site-renderers/host-import-map-script.js +30 -0
  17. package/dist/components/site-renderers/host-import-map.d.ts +40 -0
  18. package/dist/components/site-renderers/host-import-map.d.ts.map +1 -0
  19. package/dist/components/site-renderers/host-import-map.js +136 -0
  20. package/dist/components/site-renderers/host-react-modules.d.ts +15 -0
  21. package/dist/components/site-renderers/host-react-modules.d.ts.map +1 -0
  22. package/dist/components/site-renderers/host-react-modules.js +17 -0
  23. package/dist/components/site-renderers/index.d.ts +6 -0
  24. package/dist/components/site-renderers/index.d.ts.map +1 -0
  25. package/dist/components/site-renderers/index.js +7 -0
  26. package/dist/components/site-renderers/site-myst-providers.d.ts +8 -0
  27. package/dist/components/site-renderers/site-myst-providers.d.ts.map +1 -0
  28. package/dist/components/site-renderers/site-myst-providers.js +40 -0
  29. package/dist/components/site-renderers/site-renderers.d.ts +23 -0
  30. package/dist/components/site-renderers/site-renderers.d.ts.map +1 -0
  31. package/dist/components/site-renderers/site-renderers.js +48 -0
  32. package/dist/components/ui/article-card.d.ts.map +1 -1
  33. package/dist/components/ui/article-card.js +8 -3
  34. package/dist/components/ui/index.d.ts +1 -0
  35. package/dist/components/ui/index.d.ts.map +1 -1
  36. package/dist/components/ui/index.js +1 -0
  37. package/dist/components/ui/site-color-styles.d.ts +8 -0
  38. package/dist/components/ui/site-color-styles.d.ts.map +1 -0
  39. package/dist/components/ui/site-color-styles.js +16 -0
  40. package/dist/lib/site-colors.d.ts +10 -0
  41. package/dist/lib/site-colors.d.ts.map +1 -0
  42. package/dist/lib/site-colors.js +20 -0
  43. package/package.json +4 -4
@@ -1,4 +1,5 @@
1
1
  export * from './layout/index.js';
2
2
  export * from './providers/index.js';
3
+ export * from './site-renderers/index.js';
3
4
  export * from './ui/index.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export * from './layout/index.js';
2
2
  export * from './providers/index.js';
3
+ export * from './site-renderers/index.js';
3
4
  export * from './ui/index.js';
@@ -1,5 +1,5 @@
1
1
  import type { LayoutProps } from './types.js';
2
- export declare function AppLayout({ children, header, footer, trailing, hideNav }: LayoutProps): import("react").JSX.Element;
2
+ export declare function AppLayout({ children, header, footer, trailing, hideNav, headerHeight, }: LayoutProps): import("react").JSX.Element;
3
3
  export declare function AppContainer({ children, header, className, }: {
4
4
  children: React.ReactNode;
5
5
  header?: React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"app-layout.d.ts","sourceRoot":"","sources":["../../../src/components/layout/app-layout.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,+BA0BrF;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,MAAM,EACN,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BA0BA"}
1
+ {"version":3,"file":"app-layout.d.ts","sourceRoot":"","sources":["../../../src/components/layout/app-layout.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,YAAY,GACb,EAAE,WAAW,+BAkCb;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,MAAM,EACN,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BA0BA"}
@@ -8,8 +8,14 @@ import { cn } from '../../lib/utils.js';
8
8
  import { Banner, useBannerStyle } from '../ui/index.js';
9
9
  import { createSkipToTargets, SkipTo } from '../ui/accessibility-skip-to.js';
10
10
  import { useDesign } from '../providers/index.js';
11
- export function AppLayout({ children, header, footer, trailing, hideNav }) {
12
- return (_jsxs(_Fragment, { children: [_jsx(SkipTo, { targets: createSkipToTargets() }), _jsx("div", { className: cn('flex flex-col min-h-screen', {
11
+ export function AppLayout({ children, header, footer, trailing, hideNav, headerHeight, }) {
12
+ // A header of another height replaces the default 2rem, under the site nav (3.5rem) if shown
13
+ const customHeight = header && headerHeight
14
+ ? {
15
+ '--header-height': hideNav ? headerHeight : `calc(${headerHeight} + 3.5rem)`,
16
+ }
17
+ : undefined;
18
+ return (_jsxs(_Fragment, { children: [_jsx(SkipTo, { targets: createSkipToTargets() }), _jsx("div", { style: customHeight, className: cn('flex flex-col min-h-screen', {
13
19
  '[--header-height:calc(--spacing(22))]': header && !hideNav,
14
20
  '[--header-height:calc(--spacing(14))]': !header && !hideNav,
15
21
  // Preview banner only (no site nav)
@@ -1 +1 @@
1
- {"version":3,"file":"site-header.d.ts","sourceRoot":"","sources":["../../../src/components/layout/site-header.tsx"],"names":[],"mappings":"AA0MA,wBAAgB,UAAU,CAAC,EACzB,UAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,cAAqB,EACrB,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,+BA4KA"}
1
+ {"version":3,"file":"site-header.d.ts","sourceRoot":"","sources":["../../../src/components/layout/site-header.tsx"],"names":[],"mappings":"AA2MA,wBAAgB,UAAU,CAAC,EACzB,UAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,cAAqB,EACrB,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,+BA4KA"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { ExternalLink, ChevronDown, MenuIcon, SearchIcon, SidebarIcon } from 'lucide-react';
4
- import { NavLink } from 'react-router';
4
+ import { Link, NavLink } from 'react-router';
5
5
  import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, buttonVariants, SearchDialog, SimpleTooltip, BreadcrumbList, Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbSeparator, BreadcrumbPage, Separator, ArticleActions, ThemeButton, } from '../ui/index.js';
6
6
  import { cn } from '../../lib/utils.js';
7
7
  import { usePlatformConfig, usePlatformSite } from '../providers/platform-providers.js';
@@ -32,7 +32,9 @@ function MobileNavigationItem({ item, closeMobileMenu, }) {
32
32
  function SiteLogo({ logo, logoDark, logoText, title, className, }) {
33
33
  if (!logo && !logoDark && !logoText)
34
34
  return null;
35
- return (_jsxs("a", { href: "/", className: cn('flex gap-2 items-center mr-2 shrink-0', className), children: [logo && (_jsx("img", { src: logo, alt: title || 'Site Logo', className: cn('w-auto h-8 max-h-8', { 'dark:hidden': !!logoDark }) })), logoDark && (_jsx("img", { src: logoDark, alt: title || 'Site Logo', className: "hidden w-auto h-8 max-h-8 dark:block" })), logoText && _jsx("div", { className: "text-lg", children: logoText })] }));
35
+ return (
36
+ // A router link, so going home doesn't reload the whole app
37
+ _jsxs(Link, { to: "/", className: cn('flex gap-2 items-center mr-2 shrink-0', className), children: [logo && (_jsx("img", { src: logo, alt: title || 'Site Logo', className: cn('w-auto h-8 max-h-8', { 'dark:hidden': !!logoDark }) })), logoDark && (_jsx("img", { src: logoDark, alt: title || 'Site Logo', className: "hidden w-auto h-8 max-h-8 dark:block" })), logoText && _jsx("div", { className: "text-lg", children: logoText })] }));
36
38
  }
37
39
  export function SiteHeader({ showSearch = false, showBreadcrumbs, showArticleActions, showMobileMenu = true, brandBar, trailing, }) {
38
40
  const { toggleSidebar } = useSidebar() ?? {};
@@ -14,5 +14,10 @@ export interface LayoutProps {
14
14
  * where site-wide navigation is misleading.
15
15
  */
16
16
  hideNav?: boolean;
17
+ /**
18
+ * The height of `header` as CSS, when it isn't the default 2rem (a preview banner). The app
19
+ * layout offsets its sidebar by the height of everything above it.
20
+ */
21
+ headerHeight?: string;
17
22
  }
18
23
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/layout/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/layout/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB"}
@@ -12,6 +12,14 @@ type ManifestProject = Required<SiteManifest>['projects'][0];
12
12
  * @returns - a resolved set of options that can be applied to the article without the need for further fallback logic
13
13
  */
14
14
  export declare function resolveArticleConfigOptions(kindName: string, config?: SiteThemeConfig): ArticleThemeConfig;
15
+ /**
16
+ * Where compute settings come from. With 'site', the platform site's `theme_config.jupyter` turns
17
+ * compute on and configures it, and the project can switch it off. With 'project', the site's
18
+ * `jupyter` settings are ignored and the project's own `jupyter` frontmatter alone decides.
19
+ */
20
+ export type ComputeSettingsSource = 'site' | 'project';
21
+ /** `resolveArticleConfigOptions`, with the `jupyter` settings taken from `source`. */
22
+ export declare function resolveArticleConfigForCompute(kindName: string, config: SiteThemeConfig | undefined, source: ComputeSettingsSource): ArticleThemeConfig;
15
23
  export declare function resolveThemeAndProjectComputeOptions(resolvedArticleConfig: ArticleThemeConfig, project: Required<SiteManifest>['projects'][0]): ArticleThemeConfig;
16
24
  type RepoProviderSpec = any;
17
25
  type AdditionalThemeComputeConfig = {
@@ -28,14 +36,19 @@ export declare function getCustomRepoProviders(names: string[]): RepoProviderSpe
28
36
  * Get the Jupyter configuration based on a combination of the theme's
29
37
  * features and overrides, and the site manifest
30
38
  */
31
- export declare function getAdditionalThemeComputeConfig(resolvedConfig: ArticleThemeConfig, mecaUrl: string | null, respectLocalServerSettings?: boolean): AdditionalThemeComputeConfig;
39
+ export declare function getAdditionalThemeComputeConfig(resolvedConfig: ArticleThemeConfig, mecaUrl: string | null, respectLocalServerSettings?: boolean, computeSettings?: ComputeSettingsSource): AdditionalThemeComputeConfig;
32
40
  type CurvenoteDesignConfig = DesignPresetConfig | DesignOptions;
33
41
  export declare function getFullyQualifiedUrlToMECABundle(project: ManifestProject): string | null;
34
- export declare function CurvenoteProviders({ children, submissionKind, design, mode, pingFn: providedPingFn, }: {
42
+ export declare function CurvenoteProviders({ children, submissionKind, design, mode, computeSettings, pingFn: providedPingFn, }: {
35
43
  children: React.ReactNode;
36
44
  submissionKind: string;
37
45
  design?: CurvenoteDesignConfig | CurvenoteDesignConfig[];
38
46
  mode?: 'development' | 'production';
47
+ /**
48
+ * Where compute settings come from, 'site' by default. The Curvenote CLI theme uses 'project':
49
+ * it previews a local project, not a site.
50
+ */
51
+ computeSettings?: ComputeSettingsSource;
39
52
  /**
40
53
  * Optional ping function with route-specific metadata.
41
54
  * If provided, this will be used for bridge-jupyter LogBoundary instead of the default.
@@ -1 +1 @@
1
- {"version":3,"file":"curvenote-providers.d.ts","sourceRoot":"","sources":["../../../src/components/providers/curvenote-providers.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAElB,aAAa,EACb,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,MAAM,EACZ,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAYhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,KAAK,eAAe,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7D;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,eAAe,GACvB,kBAAkB,CAyBpB;AAED,wBAAgB,oCAAoC,CAClD,qBAAqB,EAAE,kBAAkB,EACzC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,sBAqC/C;AAED,KAAK,gBAAgB,GAAG,GAAG,CAAC;AAG5B,KAAK,4BAA4B,GAAG;IAClC,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,mBAAmB,KAAK,mBAAmB,GAAG,SAAS,CAAC;IACnF,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACzC,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE;QACP,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KAC/B,CAAC;CACH,CAAC;AA0BF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAE1E;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,cAAc,EAAE,kBAAkB,EAClC,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,0BAA0B,CAAC,EAAE,OAAO,GACnC,4BAA4B,CA4D9B;AAQD,KAAK,qBAAqB,GAAG,kBAAkB,GAAG,aAAa,CAAC;AAEhE,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAIxF;AAED,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,cAA6B,EAC7B,MAAM,EACN,IAAmB,EACnB,MAAM,EAAE,cAAc,GACvB,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,qBAAqB,GAAG,qBAAqB,EAAE,CAAC;IACzD,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IACpC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,+BA0DA"}
1
+ {"version":3,"file":"curvenote-providers.d.ts","sourceRoot":"","sources":["../../../src/components/providers/curvenote-providers.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAElB,aAAa,EACb,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,MAAM,EACZ,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAYhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,KAAK,eAAe,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7D;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,eAAe,GACvB,kBAAkB,CAyBpB;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEvD,sFAAsF;AACtF,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,GAAG,SAAS,EACnC,MAAM,EAAE,qBAAqB,GAC5B,kBAAkB,CAMpB;AAED,wBAAgB,oCAAoC,CAClD,qBAAqB,EAAE,kBAAkB,EACzC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,sBAqC/C;AAED,KAAK,gBAAgB,GAAG,GAAG,CAAC;AAG5B,KAAK,4BAA4B,GAAG;IAClC,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,mBAAmB,KAAK,mBAAmB,GAAG,SAAS,CAAC;IACnF,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACzC,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE;QACP,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KAC/B,CAAC;CACH,CAAC;AA0BF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAE1E;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,cAAc,EAAE,kBAAkB,EAClC,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,0BAA0B,CAAC,EAAE,OAAO,EACpC,eAAe,GAAE,qBAA8B,GAC9C,4BAA4B,CAgE9B;AAQD,KAAK,qBAAqB,GAAG,kBAAkB,GAAG,aAAa,CAAC;AAEhE,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAIxF;AAED,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,cAA6B,EAC7B,MAAM,EACN,IAAmB,EACnB,eAAwB,EACxB,MAAM,EAAE,cAAc,GACvB,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,qBAAqB,GAAG,qBAAqB,EAAE,CAAC;IACzD,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IACpC;;;OAGG;IACH,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,+BAmEA"}
@@ -41,6 +41,15 @@ export function resolveArticleConfigOptions(kindName, config) {
41
41
  }
42
42
  return articleConfig;
43
43
  }
44
+ /** `resolveArticleConfigOptions`, with the `jupyter` settings taken from `source`. */
45
+ export function resolveArticleConfigForCompute(kindName, config, source) {
46
+ const articleConfig = resolveArticleConfigOptions(kindName, config);
47
+ if (source === 'site')
48
+ return articleConfig;
49
+ // The notebook toolbar and figure controls; resolveThemeAndProjectComputeOptions then switches
50
+ // them off unless the project sets `jupyter`.
51
+ return { ...articleConfig, jupyter: { notebookCompute: true, figureCompute: true } };
52
+ }
44
53
  export function resolveThemeAndProjectComputeOptions(resolvedArticleConfig, project) {
45
54
  const themeEnablesCompute = !!resolvedArticleConfig.jupyter && resolvedArticleConfig.jupyter.enable !== false;
46
55
  const projectJupyterConfig = project.thebe ?? project.jupyter; // future proofing
@@ -95,7 +104,7 @@ export function getCustomRepoProviders(names) {
95
104
  * Get the Jupyter configuration based on a combination of the theme's
96
105
  * features and overrides, and the site manifest
97
106
  */
98
- export function getAdditionalThemeComputeConfig(resolvedConfig, mecaUrl, respectLocalServerSettings) {
107
+ export function getAdditionalThemeComputeConfig(resolvedConfig, mecaUrl, respectLocalServerSettings, computeSettings = 'site') {
99
108
  const jupyter = resolvedConfig.jupyter;
100
109
  if (!jupyter || jupyter.enable === false)
101
110
  return {};
@@ -104,6 +113,11 @@ export function getAdditionalThemeComputeConfig(resolvedConfig, mecaUrl, respect
104
113
  return undefined;
105
114
  if (opts?.serverSettings && respectLocalServerSettings)
106
115
  return opts;
116
+ // Compute from the project alone (the Curvenote theme) has no site to supply a Binder, MECA
117
+ // bundle or hub, and doesn't run JupyterLite (CN-2749), so it needs the project's own server
118
+ // or Binder.
119
+ if (computeSettings === 'project' && !opts?.binderOptions)
120
+ return undefined;
107
121
  const { useJupyterLite, ...rest } = opts ?? {};
108
122
  const enableJupyterLite = jupyter.allowLite && useJupyterLite;
109
123
  const useBinder = !enableJupyterLite && jupyter.dedicatedHub === undefined;
@@ -156,19 +170,19 @@ export function getFullyQualifiedUrlToMECABundle(project) {
156
170
  const meca = (project?.exports).find((e) => e.format === 'meca');
157
171
  return meca?.url ?? null;
158
172
  }
159
- export function CurvenoteProviders({ children, submissionKind = 'SITE_PAGES', design, mode = 'production', pingFn: providedPingFn, }) {
173
+ export function CurvenoteProviders({ children, submissionKind = 'SITE_PAGES', design, mode = 'production', computeSettings = 'site', pingFn: providedPingFn, }) {
160
174
  const platformSite = usePlatformSite();
161
175
  const site = useSiteManifest();
162
176
  const project = useProjectManifest();
163
177
  const page = usePage();
164
- const config = resolveArticleConfigOptions(submissionKind, platformSite.theme_config);
178
+ const config = resolveArticleConfigForCompute(submissionKind, platformSite.theme_config, computeSettings);
165
179
  const references = useReferences();
166
180
  const articleConfig = resolveThemeAndProjectComputeOptions(config, project);
167
181
  const mecaUrl = getFullyQualifiedUrlToMECABundle(project);
168
182
  const respectLocalServerSettings = mode === 'development';
169
183
  const resolved = {
170
184
  ...articleConfig,
171
- ...getAdditionalThemeComputeConfig(articleConfig, mecaUrl, respectLocalServerSettings),
185
+ ...getAdditionalThemeComputeConfig(articleConfig, mecaUrl, respectLocalServerSettings, computeSettings),
172
186
  };
173
187
  const images = useImages({ mdast: references?.article });
174
188
  const enable = articleConfig?.jupyter?.enable !== false;
@@ -0,0 +1,8 @@
1
+ import { HOST_REACT_MODULES } from './host-react-modules.js';
2
+ export { HOST_REACT_MODULES };
3
+ /**
4
+ * Emits the host React import map as static SSR markup in <head> (before
5
+ * <Scripts />). Host module registration happens at module scope above.
6
+ */
7
+ export declare function HostImportMap(): import("react").JSX.Element;
8
+ //# sourceMappingURL=host-import-map-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-import-map-script.d.ts","sourceRoot":"","sources":["../../../src/components/site-renderers/host-import-map-script.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAA4B,MAAM,yBAAyB,CAAC;AAEvF,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAsB9B;;;GAGG;AACH,wBAAgB,aAAa,gCAQ5B"}
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { HOST_IMPORT_EXPORT_NAMES, IMPORT_MAP_ATTR, buildHostImportMap, } from './host-import-map.js';
3
+ import { HOST_REACT_MODULES, registerReactHostModules } from './host-react-modules.js';
4
+ export { HOST_REACT_MODULES };
5
+ // Register as soon as this module evaluates (SSR + client). Must not wait for
6
+ // an effect — the import map is live from first HTML byte and shims read this
7
+ // global unconditionally once a bare specifier is imported.
8
+ registerReactHostModules();
9
+ /**
10
+ * Import-map JSON from the shared export allowlist (not Object.keys of the
11
+ * local React build), so SSR and client emit the same mappings even when
12
+ * Node resolves react.development.js and the browser bundle uses production.
13
+ */
14
+ const HOST_IMPORT_MAP_JSON = JSON.stringify(buildHostImportMap(HOST_IMPORT_EXPORT_NAMES));
15
+ const importMapScriptProps = {
16
+ type: 'importmap',
17
+ [IMPORT_MAP_ATTR]: 'true',
18
+ // Match React Router's own importmap script: SSR/client text can still
19
+ // differ under unusual bundling; never fail hydration over map markup.
20
+ suppressHydrationWarning: true,
21
+ };
22
+ /**
23
+ * Emits the host React import map as static SSR markup in <head> (before
24
+ * <Scripts />). Host module registration happens at module scope above.
25
+ */
26
+ export function HostImportMap() {
27
+ return (_jsx("script", { ...importMapScriptProps,
28
+ // Import map JSON must be text content, not a child React node.
29
+ dangerouslySetInnerHTML: { __html: HOST_IMPORT_MAP_JSON } }));
30
+ }
@@ -0,0 +1,40 @@
1
+ export declare const HOST_MODULES_KEY = "__CURVENOTE_HOST_IMPORT_MODULES__";
2
+ export declare const IMPORT_MAP_ATTR = "data-curvenote-host-importmap";
3
+ /**
4
+ * Stable public React exports shared by SSR and client import-map shims.
5
+ * Deliberately excludes development-only exports (act, captureOwnerStack) and
6
+ * internals so Object.keys() differences between React builds cannot diverge
7
+ * the emitted map.
8
+ */
9
+ export declare const HOST_REACT_EXPORT_NAMES: readonly ["Activity", "Children", "Component", "Fragment", "Profiler", "PureComponent", "StrictMode", "Suspense", "cache", "cacheSignal", "cloneElement", "createContext", "createElement", "createRef", "forwardRef", "isValidElement", "lazy", "memo", "startTransition", "use", "useActionState", "useCallback", "useContext", "useDebugValue", "useDeferredValue", "useEffect", "useEffectEvent", "useId", "useImperativeHandle", "useInsertionEffect", "useLayoutEffect", "useMemo", "useOptimistic", "useReducer", "useRef", "useState", "useSyncExternalStore", "useTransition", "version"];
10
+ export declare const HOST_JSX_RUNTIME_EXPORT_NAMES: readonly ["Fragment", "jsx", "jsxs"];
11
+ export declare const HOST_JSX_DEV_RUNTIME_EXPORT_NAMES: readonly ["Fragment", "jsxDEV"];
12
+ /** Stable public react-dom exports; private internals and unstable APIs are excluded. */
13
+ export declare const HOST_REACT_DOM_EXPORT_NAMES: readonly ["createPortal", "flushSync", "preconnect", "prefetchDNS", "preinit", "preinitModule", "preload", "preloadModule", "requestFormReset", "useFormState", "useFormStatus", "version"];
14
+ export declare const HOST_REACT_DOM_CLIENT_EXPORT_NAMES: readonly ["createRoot", "hydrateRoot", "version"];
15
+ /** Specifier → export names used when building the host import map. */
16
+ export declare const HOST_IMPORT_EXPORT_NAMES: {
17
+ readonly react: readonly ["Activity", "Children", "Component", "Fragment", "Profiler", "PureComponent", "StrictMode", "Suspense", "cache", "cacheSignal", "cloneElement", "createContext", "createElement", "createRef", "forwardRef", "isValidElement", "lazy", "memo", "startTransition", "use", "useActionState", "useCallback", "useContext", "useDebugValue", "useDeferredValue", "useEffect", "useEffectEvent", "useId", "useImperativeHandle", "useInsertionEffect", "useLayoutEffect", "useMemo", "useOptimistic", "useReducer", "useRef", "useState", "useSyncExternalStore", "useTransition", "version"];
18
+ readonly 'react/jsx-runtime': readonly ["Fragment", "jsx", "jsxs"];
19
+ readonly 'react/jsx-dev-runtime': readonly ["Fragment", "jsxDEV"];
20
+ readonly 'react-dom': readonly ["createPortal", "flushSync", "preconnect", "prefetchDNS", "preinit", "preinitModule", "preload", "preloadModule", "requestFormReset", "useFormState", "useFormStatus", "version"];
21
+ readonly 'react-dom/client': readonly ["createRoot", "hydrateRoot", "version"];
22
+ };
23
+ /** ESM shim source that re-exports a namespace already registered on globalThis. */
24
+ export declare function createNamespaceShimSource(specifier: string, exportNames: readonly string[]): string;
25
+ /**
26
+ * Build an import map document using data: URLs (SSR-safe; no blob:).
27
+ * Export names come from an explicit allowlist, not Object.keys(runtimeNamespace).
28
+ */
29
+ export declare function buildHostImportMap(exportsBySpecifier: Record<string, readonly string[]>): {
30
+ imports: Record<string, string>;
31
+ };
32
+ /** Populate globalThis so data: shim modules can resolve host exports. */
33
+ export declare function registerHostModules(modules: Record<string, object>): void;
34
+ /**
35
+ * True when a dynamic import failed because the host import map was missing,
36
+ * rejected (inserted too late), did not cover a bare specifier, or the shim
37
+ * ran before registerHostModules.
38
+ */
39
+ export declare function isImportMapResolutionError(error: unknown): boolean;
40
+ //# sourceMappingURL=host-import-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-import-map.d.ts","sourceRoot":"","sources":["../../../src/components/site-renderers/host-import-map.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,sCAAsC,CAAC;AACpE,eAAO,MAAM,eAAe,kCAAkC,CAAC;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,okBAwC1B,CAAC;AAEX,eAAO,MAAM,6BAA6B,sCAAuC,CAAC;AAElF,eAAO,MAAM,iCAAiC,iCAAkC,CAAC;AAEjF,yFAAyF;AACzF,eAAO,MAAM,2BAA2B,6LAa9B,CAAC;AAEX,eAAO,MAAM,kCAAkC,mDAAoD,CAAC;AAEpG,uEAAuE;AACvE,eAAO,MAAM,wBAAwB;;;;;;CAM3B,CAAC;AAsBX,oFAAoF;AACpF,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,MAAM,CAUR;AAOD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,GAAG;IACzF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAMA;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAKlE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQlE"}
@@ -0,0 +1,136 @@
1
+ export const HOST_MODULES_KEY = '__CURVENOTE_HOST_IMPORT_MODULES__';
2
+ export const IMPORT_MAP_ATTR = 'data-curvenote-host-importmap';
3
+ /**
4
+ * Stable public React exports shared by SSR and client import-map shims.
5
+ * Deliberately excludes development-only exports (act, captureOwnerStack) and
6
+ * internals so Object.keys() differences between React builds cannot diverge
7
+ * the emitted map.
8
+ */
9
+ export const HOST_REACT_EXPORT_NAMES = [
10
+ 'Activity',
11
+ 'Children',
12
+ 'Component',
13
+ 'Fragment',
14
+ 'Profiler',
15
+ 'PureComponent',
16
+ 'StrictMode',
17
+ 'Suspense',
18
+ 'cache',
19
+ 'cacheSignal',
20
+ 'cloneElement',
21
+ 'createContext',
22
+ 'createElement',
23
+ 'createRef',
24
+ 'forwardRef',
25
+ 'isValidElement',
26
+ 'lazy',
27
+ 'memo',
28
+ 'startTransition',
29
+ 'use',
30
+ 'useActionState',
31
+ 'useCallback',
32
+ 'useContext',
33
+ 'useDebugValue',
34
+ 'useDeferredValue',
35
+ 'useEffect',
36
+ 'useEffectEvent',
37
+ 'useId',
38
+ 'useImperativeHandle',
39
+ 'useInsertionEffect',
40
+ 'useLayoutEffect',
41
+ 'useMemo',
42
+ 'useOptimistic',
43
+ 'useReducer',
44
+ 'useRef',
45
+ 'useState',
46
+ 'useSyncExternalStore',
47
+ 'useTransition',
48
+ 'version',
49
+ ];
50
+ export const HOST_JSX_RUNTIME_EXPORT_NAMES = ['Fragment', 'jsx', 'jsxs'];
51
+ export const HOST_JSX_DEV_RUNTIME_EXPORT_NAMES = ['Fragment', 'jsxDEV'];
52
+ /** Stable public react-dom exports; private internals and unstable APIs are excluded. */
53
+ export const HOST_REACT_DOM_EXPORT_NAMES = [
54
+ 'createPortal',
55
+ 'flushSync',
56
+ 'preconnect',
57
+ 'prefetchDNS',
58
+ 'preinit',
59
+ 'preinitModule',
60
+ 'preload',
61
+ 'preloadModule',
62
+ 'requestFormReset',
63
+ 'useFormState',
64
+ 'useFormStatus',
65
+ 'version',
66
+ ];
67
+ export const HOST_REACT_DOM_CLIENT_EXPORT_NAMES = ['createRoot', 'hydrateRoot', 'version'];
68
+ /** Specifier → export names used when building the host import map. */
69
+ export const HOST_IMPORT_EXPORT_NAMES = {
70
+ react: HOST_REACT_EXPORT_NAMES,
71
+ 'react/jsx-runtime': HOST_JSX_RUNTIME_EXPORT_NAMES,
72
+ 'react/jsx-dev-runtime': HOST_JSX_DEV_RUNTIME_EXPORT_NAMES,
73
+ 'react-dom': HOST_REACT_DOM_EXPORT_NAMES,
74
+ 'react-dom/client': HOST_REACT_DOM_CLIENT_EXPORT_NAMES,
75
+ };
76
+ function getHostModules() {
77
+ const g = globalThis;
78
+ g[HOST_MODULES_KEY] ??= {};
79
+ return g[HOST_MODULES_KEY];
80
+ }
81
+ function isValidExportName(name) {
82
+ return name !== 'default' && /^[$A-Z_a-z][\w$]*$/.test(name);
83
+ }
84
+ function encodeBase64Utf8(text) {
85
+ if (typeof Buffer !== 'undefined') {
86
+ return Buffer.from(text, 'utf8').toString('base64');
87
+ }
88
+ // Shim sources are ASCII-only; btoa is sufficient in browsers without Buffer.
89
+ return btoa(text);
90
+ }
91
+ /** ESM shim source that re-exports a namespace already registered on globalThis. */
92
+ export function createNamespaceShimSource(specifier, exportNames) {
93
+ const names = exportNames.filter(isValidExportName).sort();
94
+ return `
95
+ const __ns = globalThis[${JSON.stringify(HOST_MODULES_KEY)}]?.[${JSON.stringify(specifier)}];
96
+ if (!__ns) {
97
+ throw new Error(${JSON.stringify(`host modules not registered for ${specifier}`)});
98
+ }
99
+ export default __ns.default ?? __ns;
100
+ ${names.map((name) => `export const ${name} = __ns[${JSON.stringify(name)}];`).join('\n')}
101
+ `;
102
+ }
103
+ function createNamespaceShimDataUrl(specifier, exportNames) {
104
+ const source = createNamespaceShimSource(specifier, exportNames);
105
+ return `data:text/javascript;base64,${encodeBase64Utf8(source)}`;
106
+ }
107
+ /**
108
+ * Build an import map document using data: URLs (SSR-safe; no blob:).
109
+ * Export names come from an explicit allowlist, not Object.keys(runtimeNamespace).
110
+ */
111
+ export function buildHostImportMap(exportsBySpecifier) {
112
+ const imports = {};
113
+ for (const [specifier, exportNames] of Object.entries(exportsBySpecifier)) {
114
+ imports[specifier] = createNamespaceShimDataUrl(specifier, exportNames);
115
+ }
116
+ return { imports };
117
+ }
118
+ /** Populate globalThis so data: shim modules can resolve host exports. */
119
+ export function registerHostModules(modules) {
120
+ const hostModules = getHostModules();
121
+ for (const [specifier, namespace] of Object.entries(modules)) {
122
+ hostModules[specifier] = namespace;
123
+ }
124
+ }
125
+ /**
126
+ * True when a dynamic import failed because the host import map was missing,
127
+ * rejected (inserted too late), did not cover a bare specifier, or the shim
128
+ * ran before registerHostModules.
129
+ */
130
+ export function isImportMapResolutionError(error) {
131
+ const message = error instanceof Error ? error.message : String(error);
132
+ return (/import map/i.test(message) ||
133
+ /Failed to resolve module specifier/i.test(message) ||
134
+ /Relative references must start with/i.test(message) ||
135
+ /host modules not registered/i.test(message));
136
+ }
@@ -0,0 +1,15 @@
1
+ import * as ReactNamespace from 'react';
2
+ import * as ReactDOMNamespace from 'react-dom';
3
+ import * as ReactDOMClientNamespace from 'react-dom/client';
4
+ import * as JsxRuntime from 'react/jsx-runtime';
5
+ import * as JsxDevRuntime from 'react/jsx-dev-runtime';
6
+ /** Runtime namespaces corresponding exactly to the supported host import-map specifiers. */
7
+ export declare const HOST_REACT_MODULES: {
8
+ react: typeof ReactNamespace;
9
+ 'react/jsx-runtime': typeof JsxRuntime;
10
+ 'react/jsx-dev-runtime': typeof JsxDevRuntime;
11
+ 'react-dom': typeof ReactDOMNamespace;
12
+ 'react-dom/client': typeof ReactDOMClientNamespace;
13
+ };
14
+ export declare function registerReactHostModules(): void;
15
+ //# sourceMappingURL=host-react-modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-react-modules.d.ts","sourceRoot":"","sources":["../../../src/components/site-renderers/host-react-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,cAAc,MAAM,OAAO,CAAC;AACxC,OAAO,KAAK,iBAAiB,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,uBAAuB,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,aAAa,MAAM,uBAAuB,CAAC;AAGvD,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB;;;;;;CAM9B,CAAC;AAEF,wBAAgB,wBAAwB,SAEvC"}
@@ -0,0 +1,17 @@
1
+ import * as ReactNamespace from 'react';
2
+ import * as ReactDOMNamespace from 'react-dom';
3
+ import * as ReactDOMClientNamespace from 'react-dom/client';
4
+ import * as JsxRuntime from 'react/jsx-runtime';
5
+ import * as JsxDevRuntime from 'react/jsx-dev-runtime';
6
+ import { registerHostModules } from './host-import-map.js';
7
+ /** Runtime namespaces corresponding exactly to the supported host import-map specifiers. */
8
+ export const HOST_REACT_MODULES = {
9
+ react: ReactNamespace,
10
+ 'react/jsx-runtime': JsxRuntime,
11
+ 'react/jsx-dev-runtime': JsxDevRuntime,
12
+ 'react-dom': ReactDOMNamespace,
13
+ 'react-dom/client': ReactDOMClientNamespace,
14
+ };
15
+ export function registerReactHostModules() {
16
+ registerHostModules(HOST_REACT_MODULES);
17
+ }
@@ -0,0 +1,6 @@
1
+ export { SiteMystProviders } from './site-myst-providers.js';
2
+ export { HostImportMap, HOST_REACT_MODULES } from './host-import-map-script.js';
3
+ export { registerReactHostModules } from './host-react-modules.js';
4
+ export * from './host-import-map.js';
5
+ export * from './site-renderers.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/site-renderers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,7 @@
1
+ // Site render plugins: renderer modules a site lists in its config (`renderers`), loaded at
2
+ // runtime, plus the host import map that lets those modules share the theme's React.
3
+ export { SiteMystProviders } from './site-myst-providers.js';
4
+ export { HostImportMap, HOST_REACT_MODULES } from './host-import-map-script.js';
5
+ export { registerReactHostModules } from './host-react-modules.js';
6
+ export * from './host-import-map.js';
7
+ export * from './site-renderers.js';
@@ -0,0 +1,8 @@
1
+ import { type ReactNode } from 'react';
2
+ import * as React from 'react';
3
+ import type { NodeRenderers } from '@myst-theme/providers';
4
+ export declare function SiteMystProviders({ children, renderers: baseRenderers, }: {
5
+ children: ReactNode;
6
+ renderers: NodeRenderers;
7
+ }): React.JSX.Element;
8
+ //# sourceMappingURL=site-myst-providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-myst-providers.d.ts","sourceRoot":"","sources":["../../../src/components/site-renderers/site-myst-providers.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAW3D,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,SAAS,EAAE,aAAa,GACzB,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,EAAE,aAAa,CAAC;CAC1B,qBAsCA"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import * as React from 'react';
4
+ import { MyST } from 'myst-to-react';
5
+ import { MystProviders } from '../providers/myst-providers.js';
6
+ import { usePlatformConfig } from '../providers/platform-providers.js';
7
+ import { getSiteRendererUrls, loadSiteRenderers, mergeBaseWithSitePlugins, siteRendererUrlsKey, } from './site-renderers.js';
8
+ export function SiteMystProviders({ children, renderers: baseRenderers, }) {
9
+ const config = usePlatformConfig();
10
+ const [renderers, setRenderers] = useState(baseRenderers);
11
+ const pluginsRef = useRef([]);
12
+ const baseRenderersRef = useRef(baseRenderers);
13
+ baseRenderersRef.current = baseRenderers;
14
+ const urls = getSiteRendererUrls(config.renderers);
15
+ const rendererUrlsKey = siteRendererUrlsKey(urls);
16
+ // Re-merge when base renderers change without clearing loaded plugins.
17
+ useEffect(() => {
18
+ setRenderers(mergeBaseWithSitePlugins(baseRenderers, pluginsRef.current));
19
+ }, [baseRenderers]);
20
+ // Reload plugins only when the renderer URL list actually changes.
21
+ useEffect(() => {
22
+ if (!urls.length) {
23
+ pluginsRef.current = [];
24
+ setRenderers(baseRenderersRef.current);
25
+ return;
26
+ }
27
+ let cancelled = false;
28
+ void loadSiteRenderers(urls, { React, ASTComponent: MyST }).then((plugins) => {
29
+ if (cancelled)
30
+ return;
31
+ pluginsRef.current = plugins;
32
+ setRenderers(mergeBaseWithSitePlugins(baseRenderersRef.current, plugins));
33
+ });
34
+ return () => {
35
+ cancelled = true;
36
+ };
37
+ // urls is derived from rendererUrlsKey; depend on the stable key only.
38
+ }, [rendererUrlsKey]);
39
+ return _jsx(MystProviders, { renderers: renderers, children: children });
40
+ }
@@ -0,0 +1,23 @@
1
+ import type * as ReactNamespace from 'react';
2
+ import { type NodeRenderers } from '@myst-theme/providers';
3
+ import type { GenericNode } from 'myst-common';
4
+ export type ASTComponentProps = {
5
+ ast?: GenericNode | GenericNode[];
6
+ className?: string;
7
+ };
8
+ export type ASTRendererContext = {
9
+ React: typeof ReactNamespace;
10
+ ASTComponent: ReactNamespace.ComponentType<ASTComponentProps>;
11
+ };
12
+ export type ASTRenderer = (ctx: ASTRendererContext) => NodeRenderers;
13
+ export type SiteRendererRef = string | {
14
+ url: string;
15
+ name?: string;
16
+ };
17
+ export declare function getSiteRendererUrls(renderers: SiteRendererRef[] | undefined | null): string[];
18
+ /** Stable effect dependency when renderer URL lists are equal by value. */
19
+ export declare function siteRendererUrlsKey(urls: string[]): string;
20
+ /** Merge base renderers with loaded plugins, or return base when plugins are empty. */
21
+ export declare function mergeBaseWithSitePlugins(baseRenderers: NodeRenderers, plugins: NodeRenderers[]): NodeRenderers;
22
+ export declare function loadSiteRenderers(urls: string[], ctx: ASTRendererContext): Promise<NodeRenderers[]>;
23
+ //# sourceMappingURL=site-renderers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-renderers.d.ts","sourceRoot":"","sources":["../../../src/components/site-renderers/site-renderers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,cAAc,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,OAAO,cAAc,CAAC;IAC7B,YAAY,EAAE,cAAc,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,kBAAkB,KAAK,aAAa,CAAC;AAErE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,CAK7F;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAE1D;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,aAAa,EAAE,GACvB,aAAa,CAGf;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,aAAa,EAAE,CAAC,CAiC1B"}
@@ -0,0 +1,48 @@
1
+ import { mergeRenderers } from '@myst-theme/providers';
2
+ import { isImportMapResolutionError } from './host-import-map.js';
3
+ import { registerReactHostModules } from './host-react-modules.js';
4
+ export function getSiteRendererUrls(renderers) {
5
+ if (!renderers?.length)
6
+ return [];
7
+ return renderers
8
+ .map((entry) => (typeof entry === 'string' ? entry : entry?.url))
9
+ .filter((url) => typeof url === 'string' && url.length > 0);
10
+ }
11
+ /** Stable effect dependency when renderer URL lists are equal by value. */
12
+ export function siteRendererUrlsKey(urls) {
13
+ return urls.join('\0');
14
+ }
15
+ /** Merge base renderers with loaded plugins, or return base when plugins are empty. */
16
+ export function mergeBaseWithSitePlugins(baseRenderers, plugins) {
17
+ if (!plugins.length)
18
+ return baseRenderers;
19
+ return mergeRenderers([baseRenderers, ...plugins]);
20
+ }
21
+ export async function loadSiteRenderers(urls, ctx) {
22
+ // Ensure namespaces are registered even if HostImportMap has not evaluated yet.
23
+ registerReactHostModules();
24
+ const results = await Promise.all(urls.map(async (url) => {
25
+ try {
26
+ const mod = await import(/* @vite-ignore */ url);
27
+ const exported = mod.default ?? mod.renderers;
28
+ if (typeof exported === 'function') {
29
+ return exported(ctx);
30
+ }
31
+ if (exported && typeof exported === 'object') {
32
+ return exported;
33
+ }
34
+ console.warn(`Site renderer at ${url} must default-export a NodeRenderers map or an ASTRenderer (ctx) => NodeRenderers`);
35
+ return null;
36
+ }
37
+ catch (error) {
38
+ if (isImportMapResolutionError(error)) {
39
+ console.warn(`Failed to load site renderer (host import map missing or applied too late for bare specifiers): ${url}`, error);
40
+ }
41
+ else {
42
+ console.warn(`Failed to load site renderer: ${url}`, error);
43
+ }
44
+ return null;
45
+ }
46
+ }));
47
+ return results.filter((result) => result != null);
48
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"article-card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/article-card.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CACd,IAAI,CACF,cAAc,EACd,IAAI,GAAG,OAAO,GAAG,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,YAAY,GAAG,KAAK,GAAG,OAAO,CACrF,CACF,CAAC;IACF,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,OAAO,EACP,cAAc,EACd,WAAW,EACX,OAAe,EACf,QAAgB,GACjB,EAAE,gBAAgB,+BAmGlB"}
1
+ {"version":3,"file":"article-card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/article-card.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CACd,IAAI,CACF,cAAc,EACd,IAAI,GAAG,OAAO,GAAG,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,YAAY,GAAG,KAAK,GAAG,OAAO,CACrF,CACF,CAAC;IACF,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,OAAO,EACP,cAAc,EACd,WAAW,EACX,OAAe,EACf,QAAgB,GACjB,EAAE,gBAAgB,+BA2GlB"}
@@ -8,15 +8,20 @@ export function ArticleCard({ to, article, showThumbnails, showAuthors, showDoi
8
8
  src: article.links?.thumbnail || '',
9
9
  minDelay: 300,
10
10
  });
11
- return (_jsx(Link, { to: to, className: "block no-underline group hover:no-underline", prefetch: "intent", children: _jsx("article", { className: "overflow-hidden font-ui rounded-sm border transition-shadow border-gray-200/50 hover:shadow-md not-prose", children: _jsxs("div", { className: "flex", children: [showThumbnails && article.links?.thumbnail && (_jsxs("div", { className: "hidden relative w-40 shrink-0 sm:block lg:w-50 xl:w-60", children: [_jsx("div", { className: "absolute inset-0 bg-center bg-no-repeat bg-cover transition-opacity duration-750", style: {
11
+ return (_jsx(Link, { to: to, className: "block no-underline group hover:no-underline", prefetch: "intent", children: _jsx("article", { className: "py-5 font-ui not-prose", children: _jsxs("div", { className: "flex gap-5 items-start", children: [showThumbnails && article.links?.thumbnail && (_jsxs("div", { className: "hidden overflow-hidden relative w-40 rounded-sm aspect-[16/10] shrink-0 sm:block lg:w-48", children: [_jsx("div", { className: "absolute inset-0 bg-center bg-no-repeat bg-cover transition-opacity duration-750", style: {
12
12
  backgroundImage: imageLoaded ? `url(${article.links.thumbnail})` : 'none',
13
13
  opacity: imageLoaded ? 1 : 0,
14
- } }), showPlaceholder && (_jsx("div", { className: "flex relative justify-center items-center h-full bg-gray-100 dark:bg-gray-800", children: _jsx(CurvenoteIcon, { className: "fill-gray-200 dark:fill-gray-900", height: 60, width: 60 }) })), _jsx("img", { ref: imgRef, src: article.links.thumbnail, className: "hidden", onLoad: handleImageLoad })] })), _jsxs("div", { className: "flex-1 p-6 min-w-0", children: [_jsx("div", { className: "mb-2 text-lg text-foreground", children: _jsx("span", { className: "transition-colors group-hover:text-blue-800 dark:group-hover:text-blue-500", children: article.title }) }), article.description && (_jsx("p", { className: "mb-3 text-sm font-light text-muted-foreground line-clamp-2", children: article.description })), _jsxs("div", { className: "flex flex-wrap gap-4 items-center text-xs font-light text-muted-foreground", children: [showAuthors && article.authors && article.authors.length > 0 && (_jsx("div", { className: "flex items-center", children: _jsx("span", { children: article.authors.length <= 3 ? (article.authors.map((author, index) => (_jsxs("span", { children: [author.name, index < (article.authors?.length ?? 0) - 1
14
+ } }), showPlaceholder && (_jsx("div", { className: "flex relative justify-center items-center h-full bg-gray-100 dark:bg-gray-800", children: _jsx(CurvenoteIcon, { className: "fill-gray-200 dark:fill-gray-900", height: 60, width: 60 }) })), _jsx("img", { ref: imgRef, src: article.links.thumbnail, className: "hidden", onLoad: handleImageLoad })] })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "mb-2 text-lg font-semibold font-heading text-foreground", children: _jsx("span", { className: "group-hover:underline decoration-1 underline-offset-[3px] decoration-site-primary", children: article.title }) }), article.description && (_jsx("p", { className: "mb-3 text-sm font-light text-muted-foreground line-clamp-2", children: article.description })), _jsxs("div", { className: "flex flex-wrap gap-4 items-center text-xs font-light text-muted-foreground", children: [showAuthors && article.authors && article.authors.length > 0 && (_jsx("div", { className: "flex items-center", children: _jsx("span", { children: article.authors.length <= 3 ? (article.authors.map((author, index) => (_jsxs("span", { children: [author.name, index < (article.authors?.length ?? 0) - 1
15
15
  ? index === (article.authors?.length ?? 0) - 2
16
16
  ? `${(article.authors?.length ?? 0) > 2 ? ',' : ''} and `
17
17
  : ', '
18
18
  : ''] }, index)))) : (_jsxs(_Fragment, { children: [article.authors
19
19
  .slice(0, 3)
20
20
  .map((a) => a.name)
21
- .join(', '), ' et al.'] })) }) })), showDate && article.date && (_jsx("div", { className: "flex items-center", children: _jsx("span", { children: new Date(article.date).toLocaleDateString() }) })), showDoi && article.doi && (_jsx("div", { className: "flex items-center", children: _jsx("span", { children: buildUrl(article.doi) }) }))] })] })] }) }) }));
21
+ .join(', '), ' et al.'] })) }) })), showDate && article.date && (_jsx("div", { className: "flex items-center", children: _jsx("span", { children: new Date(article.date).toLocaleDateString('en-GB', {
22
+ day: 'numeric',
23
+ month: 'short',
24
+ year: 'numeric',
25
+ timeZone: 'UTC',
26
+ }) }) })), showDoi && article.doi && (_jsx("div", { className: "flex items-center", children: _jsx("span", { children: buildUrl(article.doi) }) }))] })] })] }) }) }));
22
27
  }
@@ -56,6 +56,7 @@ export { Backmatter, useBackmatter, useBackmatterVisibility } from './backmatter
56
56
  export type { BackmatterSection, BackmatterSectionId, BackmatterVisibility } from './backmatter.js';
57
57
  export { Banner, InlineBanner, useBannerStyle } from './banner.js';
58
58
  export { FontStyles, DEFAULT_SITE_FONTS } from './font-styles.js';
59
+ export { SiteColorStyles } from './site-color-styles.js';
59
60
  export type { BannerStyle } from './banner.js';
60
61
  export { DhrCtaButtons } from './dhr-cta-buttons.js';
61
62
  export { ErrorPage } from './error-page.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ui/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ui/index.ts"],"names":[],"mappings":"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"}
@@ -60,6 +60,7 @@ export { Backmatter, useBackmatter, useBackmatterVisibility } from './backmatter
60
60
  // Design Components
61
61
  export { Banner, InlineBanner, useBannerStyle } from './banner.js';
62
62
  export { FontStyles, DEFAULT_SITE_FONTS } from './font-styles.js';
63
+ export { SiteColorStyles } from './site-color-styles.js';
63
64
  export { DhrCtaButtons } from './dhr-cta-buttons.js';
64
65
  // Error Components
65
66
  export { ErrorPage } from './error-page.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Renders a site's brand colours (`theme_config.colors`) as the `--site-primary` and
3
+ * `--site-secondary` tokens in an inline `<style>`. Server-rendered from the site config, so
4
+ * accents never flash the fallback. Renders nothing when the site sets no colours, and the
5
+ * tokens then fall back to the text colour (`@curvenote/styles/theme.css`).
6
+ */
7
+ export declare function SiteColorStyles(): import("react").JSX.Element | null;
8
+ //# sourceMappingURL=site-color-styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-color-styles.d.ts","sourceRoot":"","sources":["../../../src/components/ui/site-color-styles.tsx"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,eAAe,uCAK9B"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { buildSiteColorCss } from '../../lib/site-colors.js';
3
+ import { usePlatformSite } from '../providers/platform-providers.js';
4
+ /**
5
+ * Renders a site's brand colours (`theme_config.colors`) as the `--site-primary` and
6
+ * `--site-secondary` tokens in an inline `<style>`. Server-rendered from the site config, so
7
+ * accents never flash the fallback. Renders nothing when the site sets no colours, and the
8
+ * tokens then fall back to the text colour (`@curvenote/styles/theme.css`).
9
+ */
10
+ export function SiteColorStyles() {
11
+ const site = usePlatformSite();
12
+ const css = buildSiteColorCss(site?.theme_config?.colors);
13
+ if (!css)
14
+ return null;
15
+ return _jsx("style", { dangerouslySetInnerHTML: { __html: css } });
16
+ }
@@ -0,0 +1,10 @@
1
+ import type { SiteThemeConfig } from '@curvenote/common';
2
+ type SiteColors = SiteThemeConfig['colors'];
3
+ /**
4
+ * The `--site-primary` / `--site-secondary` tokens for a site's configured brand colours, as a
5
+ * `:root` rule, or `''` when it sets none. The values come from site config and end up in a
6
+ * `<style>` element, so anything that is not a plain colour value is dropped.
7
+ */
8
+ export declare function buildSiteColorCss(colors: SiteColors): string;
9
+ export {};
10
+ //# sourceMappingURL=site-colors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-colors.d.ts","sourceRoot":"","sources":["../../src/lib/site-colors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,KAAK,UAAU,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAU5C;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,UAQnD"}
@@ -0,0 +1,20 @@
1
+ /** Hex (`#rgb` to `#rrggbbaa`) or a functional notation with only numbers, units and separators. */
2
+ const COLOR = /^(#[0-9a-f]{3,8}|(rgba?|hsla?|hwb|lab|lch|oklab|oklch)\([0-9a-z.%\s,/+-]+\))$/i;
3
+ function safeColor(value) {
4
+ const trimmed = value?.trim();
5
+ return trimmed && COLOR.test(trimmed) ? trimmed : undefined;
6
+ }
7
+ /**
8
+ * The `--site-primary` / `--site-secondary` tokens for a site's configured brand colours, as a
9
+ * `:root` rule, or `''` when it sets none. The values come from site config and end up in a
10
+ * `<style>` element, so anything that is not a plain colour value is dropped.
11
+ */
12
+ export function buildSiteColorCss(colors) {
13
+ const primary = safeColor(colors?.primary);
14
+ const secondary = safeColor(colors?.secondary);
15
+ const decls = [
16
+ primary && `--site-primary:${primary}`,
17
+ secondary && `--site-secondary:${secondary}`,
18
+ ].filter(Boolean);
19
+ return decls.length ? `:root{${decls.join(';')}}` : '';
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curvenote/theme-ui",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/curvenote/curvenote.git"
@@ -30,11 +30,11 @@
30
30
  "prepublishOnly": "bun run build"
31
31
  },
32
32
  "dependencies": {
33
- "@curvenote/bridge-jupyter": "^2.0.2",
33
+ "@curvenote/bridge-jupyter": "^2.1.0",
34
34
  "@curvenote/common": "^0.11.0",
35
- "@curvenote/footers": "^2.0.2",
35
+ "@curvenote/footers": "^2.1.0",
36
36
  "@curvenote/icons": "^0.0.4",
37
- "@curvenote/react-utils": "^2.0.2",
37
+ "@curvenote/react-utils": "^2.1.0",
38
38
  "@myst-theme/common": "^1.3.0",
39
39
  "@myst-theme/providers": "^1.3.0",
40
40
  "@myst-theme/search": "^1.3.0",