starlight-theme-nova 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -97,7 +97,10 @@
97
97
  .nova-link-card-icon{--nova-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 12h14m-7-7l7 7l-7 7'/%3E%3C/svg%3E");-webkit-mask:var(--nova-icon) no-repeat;mask:var(--nova-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1em;height:1em;margin-left:0.5rem;width:1.25rem;height:1.25rem;transition-property:all;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
98
98
  .nova-pagination-link-icon-left{--nova-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m15 18l-6-6l6-6'/%3E%3C/svg%3E");-webkit-mask:var(--nova-icon) no-repeat;mask:var(--nova-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1em;height:1em;display:block;min-width:1.25rem;min-height:1.25rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
99
99
  .nova-pagination-link-icon-right{--nova-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m9 18l6-6l-6-6'/%3E%3C/svg%3E");-webkit-mask:var(--nova-icon) no-repeat;mask:var(--nova-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1em;height:1em;display:block;min-width:1.25rem;min-height:1.25rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
100
- .nova-code-container{position:relative;}
100
+ .nova-theme-select-icon-dark{--nova-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M12 1.992a10 10 0 1 0 9.236 13.838c.341-.82-.476-1.644-1.298-1.31a6.5 6.5 0 0 1-6.864-10.787l.077-.08c.551-.63.113-1.653-.758-1.653h-.266l-.068-.006z'/%3E%3C/svg%3E");-webkit-mask:var(--nova-icon) no-repeat;mask:var(--nova-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1em;height:1em;}
101
+ .nova-theme-select-icon-light{--nova-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M12 19a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1m-4.95-2.05a1 1 0 0 1 0 1.414l-1.414 1.414a1 1 0 1 1-1.414-1.414l1.414-1.414a1 1 0 0 1 1.414 0m11.314 0l1.414 1.414a1 1 0 0 1-1.414 1.414l-1.414-1.414a1 1 0 0 1 1.414-1.414m-5.049-9.836a5 5 0 1 1-2.532 9.674a5 5 0 0 1 2.532-9.674M4 11a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2zm18 0a1 1 0 0 1 0 2h-2a1 1 0 0 1 0-2zM5.636 4.222L7.05 5.636A1 1 0 0 1 5.636 7.05L4.222 5.636a1 1 0 0 1 1.414-1.414m14.142 0a1 1 0 0 1 0 1.414L18.364 7.05a1 1 0 0 1-1.414-1.414l1.414-1.414a1 1 0 0 1 1.414 0M12 1a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0V2a1 1 0 0 1 1-1'/%3E%3C/svg%3E");-webkit-mask:var(--nova-icon) no-repeat;mask:var(--nova-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1em;height:1em;}
102
+ .nova-code-container{position:relative;overflow:hidden;border-width:1px;border-color:var(--sl-color-gray-5);border-radius:0.375rem;border-style:solid;}
103
+ .nova-code-container pre{position:relative;}
101
104
  .nova-code-copy-button{position:absolute;right:0.5rem;top:0.5rem;margin:0;width:1.5rem;height:1.5rem;border-width:1px;border-color:var(--sl-color-gray-5);border-radius:0.25rem;border-style:solid;background-color:rgb(243 244 246 / 0.3) /* #f3f4f6 */;padding:0.25rem;--nova-text-opacity:1;color:rgb(0 0 0 / var(--nova-text-opacity)) /* #000 */;--nova-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--nova-backdrop-blur) var(--nova-backdrop-brightness) var(--nova-backdrop-contrast) var(--nova-backdrop-grayscale) var(--nova-backdrop-hue-rotate) var(--nova-backdrop-invert) var(--nova-backdrop-opacity) var(--nova-backdrop-saturate) var(--nova-backdrop-sepia);backdrop-filter:var(--nova-backdrop-blur) var(--nova-backdrop-brightness) var(--nova-backdrop-contrast) var(--nova-backdrop-grayscale) var(--nova-backdrop-hue-rotate) var(--nova-backdrop-invert) var(--nova-backdrop-opacity) var(--nova-backdrop-saturate) var(--nova-backdrop-sepia);transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
102
105
  .nova-link-card{position:relative;display:flex;flex-direction:column;gap:0.5rem;border-width:1px;border-color:var(--sl-color-gray-5);border-radius:0.75rem;border-style:solid;--nova-bg-opacity:1;background-color:rgb(255 255 255 / var(--nova-bg-opacity)) /* #fff */;padding-left:1.25rem;padding-right:1.25rem;padding-top:1rem;padding-bottom:1rem;--nova-text-opacity:1;color:rgb(55 65 81 / var(--nova-text-opacity)) /* #374151 */;--nova-shadow:var(--nova-shadow-inset) 0 1px 2px 0 var(--nova-shadow-color, rgb(0 0 0 / 0.05));box-shadow:var(--nova-ring-offset-shadow), var(--nova-ring-shadow), var(--nova-shadow);transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;transition-duration:200ms;}
103
106
  .nova-page-frame-header{position:fixed;inset:0;z-index:var(--sl-z-index-navbar);box-sizing:border-box;width:100%;height:var(--sl-nav-height);border-width:0px;border-bottom-width:1px;border-color:var(--sl-color-hairline);border-style:solid;background-color:var(--sl-color-bg-nav) /* var(--sl-color-bg-nav) */;padding-top:var(--sl-nav-pad-y);padding-bottom:var(--sl-nav-pad-y);padding-left:var(--sl-nav-pad-x);padding-right:var(--sl-nav-pad-x);--nova-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--nova-backdrop-blur) var(--nova-backdrop-brightness) var(--nova-backdrop-contrast) var(--nova-backdrop-grayscale) var(--nova-backdrop-hue-rotate) var(--nova-backdrop-invert) var(--nova-backdrop-opacity) var(--nova-backdrop-saturate) var(--nova-backdrop-sepia);backdrop-filter:var(--nova-backdrop-blur) var(--nova-backdrop-brightness) var(--nova-backdrop-contrast) var(--nova-backdrop-grayscale) var(--nova-backdrop-hue-rotate) var(--nova-backdrop-invert) var(--nova-backdrop-opacity) var(--nova-backdrop-saturate) var(--nova-backdrop-sepia);}
@@ -106,6 +109,8 @@
106
109
  .nova-pagination-link{margin:0;display:flex;align-items:center;justify-content:flex-end;gap:0.5rem;border-radius:0.75rem;padding:0.5rem;color:var(--sl-color-gray-2) /* var(--sl-color-gray-2) */;font-weight:500;text-decoration:none;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;transition-duration:100ms;}
107
110
  .nova-link-button{margin-inline-end:0.5rem;margin-top:0.5rem;margin-bottom:0.5rem;display:inline-flex;align-items:center;justify-content:space-between;gap:0.5rem;border-width:1px;border-color:transparent;border-radius:0.75rem;border-style:solid;padding-left:1.5rem;padding-right:1.5rem;padding-top:0.75rem;padding-bottom:0.75rem;font-weight:500;text-decoration:none;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;transition-duration:200ms;}
108
111
  .nova-header{box-sizing:border-box;height:100%;display:flex;align-items:center;gap:0.5rem;}
112
+ div[data-nova-code-container][data-nova-code-title] .nova-code-title{display:block;}
113
+ .nova-code-title{display:none;border-bottom-width:1px;border-bottom-color:var(--sl-color-gray-5);border-bottom-style:solid;background-color:var(--sl-color-bg) /* var(--sl-color-bg) */;padding-left:1rem;padding-right:1rem;padding-top:0.5rem;padding-bottom:0.5rem;font-size:0.875rem;line-height:1.25rem;color:var(--sl-color-gray-3) /* var(--sl-color-gray-3) */;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;}
109
114
  .nova-header-actions{display:none;align-items:center;gap:0.5rem;}
110
115
  .nova-social-icons-link{width:2rem;height:2rem;display:flex;border-radius:0.375rem;padding:0.5rem;color:var(--sl-color-text) /* var(--sl-color-text) */;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
111
116
  .nova-theme-select{width:2rem;height:2rem;border-radius:0.375rem;padding:0.5rem;color:var(--sl-color-text) /* var(--sl-color-text) */;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
@@ -124,6 +129,7 @@
124
129
  .nova-pagination-link:active[data-side="left"]{--nova-translate-x:-0.25rem;transform:translateX(var(--nova-translate-x)) translateY(var(--nova-translate-y)) translateZ(var(--nova-translate-z)) rotate(var(--nova-rotate)) rotateX(var(--nova-rotate-x)) rotateY(var(--nova-rotate-y)) rotateZ(var(--nova-rotate-z)) skewX(var(--nova-skew-x)) skewY(var(--nova-skew-y)) scaleX(var(--nova-scale-x)) scaleY(var(--nova-scale-y)) scaleZ(var(--nova-scale-z));}
125
130
  .nova-pagination-link:active[data-side="right"]{--nova-translate-x:0.25rem;transform:translateX(var(--nova-translate-x)) translateY(var(--nova-translate-y)) translateZ(var(--nova-translate-z)) rotate(var(--nova-rotate)) rotateX(var(--nova-rotate-x)) rotateY(var(--nova-rotate-y)) rotateZ(var(--nova-rotate-z)) skewX(var(--nova-skew-x)) skewY(var(--nova-skew-y)) scaleX(var(--nova-scale-x)) scaleY(var(--nova-scale-y)) scaleZ(var(--nova-scale-z));}
126
131
  .nova-code-copy-button:active{--nova-scale-x:0.9;--nova-scale-y:0.9;transform:translateX(var(--nova-translate-x)) translateY(var(--nova-translate-y)) translateZ(var(--nova-translate-z)) rotate(var(--nova-rotate)) rotateX(var(--nova-rotate-x)) rotateY(var(--nova-rotate-y)) rotateZ(var(--nova-rotate-z)) skewX(var(--nova-skew-x)) skewY(var(--nova-skew-y)) scaleX(var(--nova-scale-x)) scaleY(var(--nova-scale-y)) scaleZ(var(--nova-scale-z));}
132
+ .sl-markdown-content .nova-code-container pre.astro-code{border-width:0px;border-color:transparent;border-radius:0;}
127
133
  .nova-page-frame-sidebar-pane{border-width:0px;border-color:var(--sl-color-hairline);border-style:solid;}
128
134
  .nova-link-button-secondary{border-color:var(--sl-color-gray-5);--nova-bg-opacity:1;background-color:rgb(255 255 255 / var(--nova-bg-opacity)) /* #fff */;--nova-text-opacity:1;color:rgb(55 65 81 / var(--nova-text-opacity)) /* #374151 */;--nova-shadow:var(--nova-shadow-inset) 0 1px 2px 0 var(--nova-shadow-color, rgb(0 0 0 / 0.05));box-shadow:var(--nova-ring-offset-shadow), var(--nova-ring-shadow), var(--nova-shadow);}
129
135
  .nova-mobile-table-of-contents summary{border-bottom-color:var(--sl-color-hairline);}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "starlight-theme-nova",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "description": "",
6
6
  "author": "ocavue <ocavue@gmail.com>",
7
7
  "license": "MIT",
@@ -29,8 +29,10 @@
29
29
  "@shikijs/transformers": "^3.2.1",
30
30
  "@shikijs/twoslash": "^3.2.1",
31
31
  "@shikijs/types": "^3.2.1",
32
+ "@types/hast": "^3.0.4",
32
33
  "astro-theme-toggle": "^0.6.0",
33
34
  "hast-util-is-element": "^3.0.0",
35
+ "rehype": "^13.0.2",
34
36
  "shiki-twoslash-renderer": "0.0.2"
35
37
  },
36
38
  "devDependencies": {
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  import { Tabs } from '@astrojs/starlight/components'
3
+ import { processCodeTabs } from './rehype-code-tabs'
3
4
 
4
5
  interface Props {
5
6
  border?: boolean
@@ -7,11 +8,14 @@ interface Props {
7
8
  }
8
9
 
9
10
  const { border = true, syncKey } = Astro.props
11
+
12
+ const originalHtml = await Astro.slots.render('default')
13
+ const processedHtml = processCodeTabs(originalHtml)
10
14
  ---
11
15
 
12
16
  <div class:list={['code-tabs', border ? 'code-tabs-border' : undefined]}>
13
17
  <Tabs syncKey={syncKey}>
14
- <slot />
18
+ <Fragment set:html={processedHtml} />
15
19
  </Tabs>
16
20
  </div>
17
21
 
@@ -59,12 +63,14 @@ const { border = true, syncKey } = Astro.props
59
63
  margin: 0;
60
64
  }
61
65
 
62
- div[role='tabpanel'] pre {
63
- border-color: transparent;
66
+ .astro-code {
67
+ border-radius: 0;
64
68
  }
65
69
 
66
- .astro-code {
70
+ .nova-code-container {
67
71
  border-radius: 0;
72
+ border-width: 0;
73
+ border-color: transparent;
68
74
  }
69
75
  }
70
76
  </style>
@@ -2,4 +2,11 @@
2
2
  import { Toggle } from 'astro-theme-toggle'
3
3
  ---
4
4
 
5
- <Toggle class="nova-theme-select" />
5
+ <Toggle class="nova-theme-select">
6
+ <Fragment slot="icon-light">
7
+ <div class="nova-theme-select-icon-light"></div>
8
+ </Fragment>
9
+ <Fragment slot="icon-dark">
10
+ <div class="nova-theme-select-icon-dark"></div>
11
+ </Fragment>
12
+ </Toggle>
@@ -0,0 +1,56 @@
1
+ import type { Element, ElementContent } from 'hast'
2
+ import { rehype } from 'rehype'
3
+
4
+ import { CODE_PROPERTY_CONTAINER, CODE_PROPERTY_TITLE } from '../constants'
5
+
6
+ // https://github.com/withastro/starlight/blob/bdb05e704a6cf06a029367f99b6bf2f575e5a5f3/packages/starlight/user-components/rehype-tabs.ts#L20
7
+ export const TabItemTagname = 'starlight-tab-item'
8
+
9
+ /**
10
+ * Rehype processor to extract tab panel data and turn each
11
+ * `<starlight-tab-item>` into a `<div>` with the necessary
12
+ * attributes.
13
+ */
14
+ const tabsProcessor = rehype()
15
+ .data('settings', { fragment: true })
16
+ .use(() => {
17
+ return (tree: Element) => {
18
+ return {
19
+ ...tree,
20
+ children: tree.children.map(replacePre),
21
+ }
22
+ }
23
+ })
24
+
25
+ function replacePre(node: ElementContent): ElementContent {
26
+ if (
27
+ node.type === 'element' &&
28
+ node.tagName === 'div' &&
29
+ node.properties[CODE_PROPERTY_CONTAINER] != null
30
+ ) {
31
+ const title = node.properties[CODE_PROPERTY_TITLE]
32
+
33
+ if (title) {
34
+ node.properties[CODE_PROPERTY_TITLE] = undefined
35
+ return {
36
+ type: 'element',
37
+ tagName: TabItemTagname,
38
+ properties: {
39
+ dataLabel: title,
40
+ },
41
+ children: [node],
42
+ }
43
+ }
44
+ }
45
+
46
+ return node
47
+ }
48
+
49
+ /**
50
+ * Processes the children of the `<CodeTabs>` component to transform
51
+ * any code blocks with "title" meta information into a <TabItem> component.
52
+ */
53
+ export function processCodeTabs(html: string): string {
54
+ const file = tabsProcessor.processSync({ value: html })
55
+ return file.toString()
56
+ }
package/src/constants.ts CHANGED
@@ -1 +1,5 @@
1
1
  export const PAGE_TITLE_ID = '_top'
2
+
3
+ export const CODE_PROPERTY_CONTAINER = 'dataNovaCodeContainer'
4
+
5
+ export const CODE_PROPERTY_TITLE = 'dataNovaCodeTitle'
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  transformerMetaHighlight,
3
3
  transformerMetaWordHighlight,
4
- transformerNotationDiff,
4
+ transformerNotationDiff,transformerRemoveNotationEscape,
5
5
  transformerNotationHighlight,
6
6
  transformerNotationWordHighlight,
7
7
  } from '@shikijs/transformers'
@@ -10,6 +10,7 @@ import type { ShikiTransformer } from '@shikijs/types'
10
10
  import type { ShikiConfig } from 'astro'
11
11
  import { createRenderer } from 'shiki-twoslash-renderer'
12
12
 
13
+ import { transformerContainer } from './shiki-transformer-container'
13
14
  import { transformerCopyButton } from './shiki-transformer-copy-button'
14
15
 
15
16
  export function createShikiConfig(options: { twoslash: boolean }): ShikiConfig {
@@ -19,8 +20,10 @@ export function createShikiConfig(options: { twoslash: boolean }): ShikiConfig {
19
20
  transformerNotationDiff(),
20
21
  transformerNotationHighlight(),
21
22
  transformerNotationWordHighlight(),
23
+ transformerRemoveNotationEscape(),
22
24
 
23
25
  transformerCopyButton(),
26
+ transformerContainer(),
24
27
  options.twoslash
25
28
  ? transformerTwoslash({
26
29
  renderer: createRenderer(),
@@ -0,0 +1,6 @@
1
+ export function parseTitleString(meta: string): string | null {
2
+ if (!meta) return null
3
+ const match = meta.match(/title="([^"]+)"/)
4
+ if (!match) return null
5
+ return match[1]
6
+ }
@@ -0,0 +1,70 @@
1
+ import type { ShikiTransformer } from '@shikijs/types'
2
+ import type { ElementContent, RootContent } from 'hast'
3
+ import { isElement } from 'hast-util-is-element'
4
+
5
+ import { CODE_PROPERTY_CONTAINER, CODE_PROPERTY_TITLE } from './constants'
6
+ import { parseTitleString } from './shiki-meta-title'
7
+
8
+ const name = 'starlight-theme-nova-shiki-transformer-container'
9
+
10
+ /**
11
+ * A transformer to wrap code blocks in a container.
12
+ */
13
+ export function transformerContainer(): ShikiTransformer {
14
+ return {
15
+ name: name,
16
+ root(node) {
17
+ if (node.children.length === 0) {
18
+ throw new Error(`[${name}] Expected at least one child`)
19
+ }
20
+
21
+ const pre = node.children.find((child) => isElement(child, 'pre'))
22
+
23
+ if (!pre) {
24
+ throw new Error(
25
+ `[${name}] Expected a <pre> element in the root node but got ${JSON.stringify(node)}`,
26
+ )
27
+ }
28
+
29
+ const title = parseTitleString(this.options.meta?.__raw || '')
30
+
31
+ const children: ElementContent[] = normalizeContent(node.children)
32
+
33
+ if (title) {
34
+ children.unshift({
35
+ type: 'element',
36
+ tagName: 'div',
37
+ properties: {
38
+ class: 'nova-code-title',
39
+ },
40
+ children: [
41
+ {
42
+ type: 'text',
43
+ value: title,
44
+ },
45
+ ],
46
+ })
47
+ }
48
+
49
+ node.children = [
50
+ {
51
+ type: 'element',
52
+ tagName: 'div',
53
+ properties: {
54
+ [CODE_PROPERTY_CONTAINER]: '',
55
+ [CODE_PROPERTY_TITLE]: title || undefined,
56
+ class: 'nova-code-container not-content',
57
+ },
58
+ children,
59
+ },
60
+ ]
61
+
62
+ return node
63
+ },
64
+ }
65
+ }
66
+
67
+ // A simple function to make typescript happy
68
+ function normalizeContent(children: RootContent[]): ElementContent[] {
69
+ return children.filter((child) => child.type !== 'doctype')
70
+ }
@@ -1,5 +1,4 @@
1
1
  import type { ShikiTransformer } from '@shikijs/types'
2
- import { isElement } from 'hast-util-is-element'
3
2
 
4
3
  const name = 'starlight-theme-nova-shiki-transformer-copy-button'
5
4
 
@@ -9,42 +8,25 @@ const name = 'starlight-theme-nova-shiki-transformer-copy-button'
9
8
  export function transformerCopyButton(): ShikiTransformer {
10
9
  return {
11
10
  name: name,
12
- root(node) {
13
- if (node.children.length !== 1) {
14
- throw new Error(`[${name}] Expected exactly one child`)
15
- }
16
-
17
- const pre = node.children[0]
18
- if (!isElement(pre, 'pre')) {
19
- throw new Error(
20
- `[${name}] Expected a <pre> element but got ${JSON.stringify({ ...pre, children: '...' })}`,
21
- )
22
- }
23
-
24
- node.children = [
25
- {
26
- type: 'element',
27
- tagName: 'div',
28
- properties: {
29
- class: 'nova-code-container not-content',
30
- },
31
- children: [
32
- pre,
33
- {
34
- type: 'element',
35
- tagName: 'nova-code-copy-button',
36
- properties: {
37
- type: 'button',
38
- 'data-code': this.source,
39
- title: 'Copy code',
40
- 'aria-label': 'Copy code',
41
- class: 'nova-code-copy-button',
42
- },
43
- children: [],
11
+ pre(node) {
12
+ return {
13
+ ...node,
14
+ children: [
15
+ ...node.children,
16
+ {
17
+ type: 'element',
18
+ tagName: 'nova-code-copy-button',
19
+ properties: {
20
+ type: 'button',
21
+ 'data-code': this.source,
22
+ title: 'Copy code',
23
+ 'aria-label': 'Copy code',
24
+ class: 'nova-code-copy-button',
44
25
  },
45
- ],
46
- },
47
- ]
26
+ children: [],
27
+ },
28
+ ],
29
+ }
48
30
  },
49
31
  }
50
32
  }