@nordcraft/runtime 1.0.58 → 1.0.59

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.
@@ -3,9 +3,9 @@
3
3
  /* eslint-disable no-case-declarations */
4
4
  /* eslint-disable no-fallthrough */
5
5
  import { isLegacyApi } from '@nordcraft/core/dist/api/api'
6
+ import { isLegacyPluginAction } from '@nordcraft/core/dist/component/actionUtils'
6
7
  import {
7
8
  HeadTagTypes,
8
- type AnimationKeyframe,
9
9
  type Component,
10
10
  type ComponentData,
11
11
  type MetaEntry,
@@ -24,7 +24,6 @@ import {
24
24
  type PluginFormula,
25
25
  type ToddleFormula,
26
26
  } from '@nordcraft/core/dist/formula/formulaTypes'
27
- import { valueFormula } from '@nordcraft/core/dist/formula/formulaUtils'
28
27
  import { getClassName } from '@nordcraft/core/dist/styling/className'
29
28
  import { appendUnit } from '@nordcraft/core/dist/styling/customProperty'
30
29
  import type { OldTheme, Theme } from '@nordcraft/core/dist/styling/theme'
@@ -57,7 +56,15 @@ import { dragMove } from './editor/drag-drop/dragMove'
57
56
  import { dragReorder } from './editor/drag-drop/dragReorder'
58
57
  import { dragStarted } from './editor/drag-drop/dragStarted'
59
58
  import { introspectApiRequest } from './editor/graphql'
60
- import type { DragState } from './editor/types'
59
+ import { isInputTarget } from './editor/input'
60
+ import { updateComponentLinks } from './editor/links'
61
+ import { getRectData } from './editor/overlay'
62
+ import {
63
+ TextNodeComputedStyles,
64
+ type DragState,
65
+ type EditorPostMessageType,
66
+ type NordcraftPreviewEvent,
67
+ } from './editor/types'
61
68
  import { handleAction } from './events/handleAction'
62
69
  import type { Signal } from './signal/signal'
63
70
  import { signal } from './signal/signal'
@@ -77,143 +84,6 @@ import {
77
84
  storeScrollState,
78
85
  } from './utils/storeScrollState'
79
86
 
80
- type ToddlePreviewEvent =
81
- | {
82
- type: 'style_variant_changed'
83
- variantIndex: number | null
84
- }
85
- | {
86
- type: 'component'
87
- component: Component
88
- }
89
- | { type: 'components'; components: Component[] }
90
- | {
91
- type: 'packages'
92
- packages: Record<
93
- string,
94
- {
95
- components: Record<string, Component>
96
- formulas: Record<
97
- string,
98
- PluginFormula<FormulaHandlerV2> | PluginFormula<string>
99
- >
100
- actions: Record<string, PluginActionV2 | PluginAction>
101
- manifest: {
102
- name: string
103
- // commit represents the commit hash (version) of the package
104
- commit: string
105
- }
106
- }
107
- >
108
- }
109
- | {
110
- type: 'global_formulas'
111
- formulas: Record<
112
- string,
113
- PluginFormula<FormulaHandlerV2> | PluginFormula<string>
114
- >
115
- }
116
- | {
117
- type: 'global_actions'
118
- actions: Record<string, PluginActionV2 | PluginAction>
119
- }
120
- | { type: 'theme'; theme: Record<string, OldTheme | Theme> }
121
- | { type: 'mode'; mode: 'design' | 'test' }
122
- | { type: 'attrs'; attrs: Record<string, unknown> }
123
- | { type: 'selection'; selectedNodeId: string | null }
124
- | { type: 'highlight'; highlightedNodeId: string | null }
125
- | {
126
- type: 'click' | 'mousemove' | 'dblclick'
127
- metaKey: boolean
128
- x: number
129
- y: number
130
- }
131
- | { type: 'report_document_scroll_size' }
132
- | { type: 'update_inner_text'; innerText: string }
133
- | { type: 'reload' }
134
- | { type: 'fetch_api'; apiKey: string }
135
- | { type: 'introspect_qraphql_api'; apiKey: string }
136
- | { type: 'drag-started'; x: number; y: number }
137
- | { type: 'drag-ended'; canceled?: true }
138
- | { type: 'keydown'; key: string; altKey: boolean; metaKey: boolean }
139
- | { type: 'keyup'; key: string; altKey: boolean; metaKey: boolean }
140
- | {
141
- type: 'get_computed_style'
142
- styles?: string[]
143
- }
144
- | {
145
- type: 'set_timeline_keyframes'
146
- keyframes: Record<string, AnimationKeyframe> | null
147
- }
148
- | {
149
- type: 'set_timeline_time'
150
- time: number | null
151
- timingFunction:
152
- | 'linear'
153
- | 'ease'
154
- | 'ease-in'
155
- | 'ease-out'
156
- | 'ease-in-out'
157
- | 'step-start'
158
- | 'step-end'
159
- | string
160
- | undefined
161
- fillMode: 'none' | 'forwards' | 'backwards' | 'both' | undefined
162
- }
163
- | {
164
- type: 'preview_style'
165
- styles: Record<string, string> | null
166
- theme?: {
167
- key: string
168
- value: Theme
169
- }
170
- }
171
- | {
172
- type: 'preview_theme'
173
- theme: string | null
174
- }
175
-
176
- /**
177
- * Styles required for rendering the same exact text again somewhere else (on a overlay rect in the editor)
178
- */
179
- enum TextNodeComputedStyles {
180
- // Caret color is important as it is the only visible part of the text node (when text is not highlighted)
181
- CARET_COLOR = 'caret-color',
182
- DISPLAY = 'display',
183
- FONT_FAMILY = 'font-family',
184
- FONT_SIZE = 'font-size',
185
- FONT_WEIGHT = 'font-weight',
186
- FONT_STYLE = 'font-style',
187
- FONT_VARIANT = 'font-variant',
188
- FONT_STRETCH = 'font-stretch',
189
- LINE_HEIGHT = 'line-height',
190
- TEXT_ALIGN = 'text-align',
191
- TEXT_TRANSFORM = 'text-transform',
192
- LETTER_SPACING = 'letter-spacing',
193
- WHITE_SPACE = 'white-space',
194
- WORD_SPACING = 'word-spacing',
195
- TEXT_INDENT = 'text-indent',
196
- TEXT_OVERFLOW = 'text-overflow',
197
- TEXT_RENDERING = 'text-rendering',
198
- WORD_BREAK = 'word-break',
199
- WORD_WRAP = 'word-wrap',
200
- DIRECTION = 'direction',
201
- UNICODE_BIDI = 'unicode-bidi',
202
- VERTICAL_ALIGN = 'vertical-align',
203
- FONT_KERNING = 'font-kerning',
204
- FONT_FEATURE_SETTINGS = 'font-feature-settings',
205
- FONT_VARIATION_SETTINGS = 'font-variation-settings',
206
- FONT_SMOOTHING = '-webkit-font-smoothing',
207
- ANTI_ALIASING = '-moz-osx-font-smoothing',
208
- FONT_OPTICAL_SIZING = 'font-optical-sizing',
209
- TAB_SIZE = 'tab-size',
210
- HYPHENS = 'hyphens',
211
- TEXT_ORIENTATION = 'text-orientation',
212
- WRITING_MODE = 'writing-mode',
213
- LINE_BREAK = 'line-break',
214
- OVERFLOW_WRAP = 'overflow-wrap',
215
- }
216
-
217
87
  let env: ToddleEnv
218
88
 
219
89
  export const initGlobalObject = () => {
@@ -312,6 +182,18 @@ export const initGlobalObject = () => {
312
182
  )
313
183
  }
314
184
 
185
+ const EMPTY_COMPONENT_DATA: ComponentData = {
186
+ Location: {
187
+ query: {},
188
+ params: {},
189
+ page: '/',
190
+ path: '/',
191
+ hash: '',
192
+ },
193
+ Attributes: {},
194
+ Variables: {},
195
+ }
196
+
315
197
  // imported by "/.toddle/preview" (see worker/src/preview.ts)
316
198
  export const createRoot = (
317
199
  domNode: HTMLElement | null = document.getElementById('App'),
@@ -319,35 +201,8 @@ export const createRoot = (
319
201
  if (!domNode) {
320
202
  throw new Error('Cant find root domNode')
321
203
  }
322
- const isInputTarget = (event: Event) => {
323
- const target = event.target
324
- if (target instanceof HTMLElement) {
325
- if (
326
- target.tagName === 'INPUT' ||
327
- target.tagName === 'TEXTAREA' ||
328
- target.tagName === 'SELECT' ||
329
- target.tagName === 'STYLE-EDITOR'
330
- ) {
331
- return true
332
- }
333
- if (target.contentEditable?.toLocaleLowerCase() === 'true') {
334
- return true
335
- }
336
- }
337
- return false
338
- }
339
204
 
340
- const dataSignal = signal<ComponentData>({
341
- Location: {
342
- query: {},
343
- params: {},
344
- page: '/',
345
- path: '/',
346
- hash: '',
347
- },
348
- Attributes: {},
349
- Variables: {},
350
- })
205
+ const dataSignal = signal(EMPTY_COMPONENT_DATA)
351
206
  let ctxDataSignal: Signal<ComponentData> | undefined
352
207
 
353
208
  let ctx: ComponentContext | null = null
@@ -387,87 +242,26 @@ export const createRoot = (
387
242
  let previewStyleAnimationFrame = -1
388
243
  let timelineTimeAnimationFrame = -1
389
244
 
390
- /**
391
- * Modifies all link nodes on a component
392
- * NOTE: alters in place
393
- */
394
- const updateComponentLinks = (component: Component) => {
395
- // Find all links and add target="_blank" to them
396
- Object.entries(component.nodes ?? {}).forEach(([_, node]) => {
397
- if (node.type === 'element' && node.tag === 'a') {
398
- node.attrs['target'] = valueFormula('_blank')
399
- }
400
- })
401
- return component
402
- }
403
-
404
- const registerActions = (
405
- allActions: Record<string, PluginActionV2 | PluginAction>,
406
- packageName?: string,
407
- ) => {
408
- const actions: Record<string, PluginActionV2> = {}
409
- Object.entries(allActions ?? {}).forEach(([name, action]) => {
410
- if (typeof action.name === 'string' && action.version === undefined) {
411
- // Legacy actions are self-registering. We need to execute them to register them
412
- Function(action.handler)()
413
- return
414
- }
415
- // We need to convert the handler string into a real function
416
- actions[name] = {
417
- ...(action as PluginActionV2),
418
- handler:
419
- typeof action.handler === 'string'
420
- ? (new Function(
421
- 'args, ctx',
422
- `${action.handler}
423
- return ${safeFunctionName(action.name)}(args, ctx)`,
424
- ) as ActionHandlerV2)
425
- : action.handler,
426
- }
427
- })
428
- window.toddle.actions[packageName ?? window.__toddle.project] = actions
429
- }
430
-
431
- const registerFormulas = (
432
- allFormulas: Record<
433
- string,
434
- ToddleFormula | CodeFormula<FormulaHandlerV2> | CodeFormula<string>
435
- >,
436
- packageName?: string,
437
- ) => {
438
- const formulas: Record<string, PluginFormula<FormulaHandlerV2>> = {}
439
- Object.entries(allFormulas ?? {}).forEach(([name, formula]) => {
440
- if (
441
- !isToddleFormula<FormulaHandlerV2 | string>(formula) &&
442
- typeof formula.name === 'string' &&
443
- formula.version === undefined
444
- ) {
445
- // Legacy formulas are self-registering. We need to execute them to register them
446
- Function(formula.handler as unknown as string)()
447
- return
448
- } else if (!isToddleFormula<FormulaHandlerV2 | string>(formula)) {
449
- // For code formulas we need to convert the handler string into a real function
450
- formulas[name] = {
451
- ...formula,
452
- handler:
453
- typeof formula.handler === 'string'
454
- ? (new Function(
455
- 'args, ctx',
456
- `${formula.handler}
457
- return ${safeFunctionName(formula.name)}(args, ctx)`,
458
- ) as FormulaHandlerV2)
459
- : formula.handler,
245
+ const setupDataSignalSubscribers = () => {
246
+ dataSignal.subscribe((data) => {
247
+ if (component && components && packageComponents && data) {
248
+ try {
249
+ postMessageToEditor({ type: 'data', data })
250
+ } catch {
251
+ // If we're unable to send the data, let's try to JSON serialize it
252
+ postMessageToEditor({
253
+ type: 'data',
254
+ data: JSON.parse(JSON.stringify(data)),
255
+ })
460
256
  }
461
- return
462
257
  }
463
- formulas[name] = formula as PluginFormula<FormulaHandlerV2>
464
258
  })
465
- window.toddle.formulas[packageName ?? window.__toddle.project] = formulas
466
259
  }
260
+ setupDataSignalSubscribers()
467
261
 
468
262
  window.addEventListener(
469
263
  'message',
470
- async (message: MessageEvent<ToddlePreviewEvent>) => {
264
+ async (message: MessageEvent<NordcraftPreviewEvent>) => {
471
265
  if (!message.isTrusted) {
472
266
  console.error('UNTRUSTED MESSAGE')
473
267
  }
@@ -481,11 +275,22 @@ export const createRoot = (
481
275
  | undefined
482
276
 
483
277
  if (message.data.component.name !== component?.name) {
278
+ // Store scroll state for the previous component
484
279
  storeScrollState(component?.name)
280
+ // Remove all subscribers from the previous showSignal
485
281
  showSignal.cleanSubscribers()
282
+ // Clear any previously overridden conditional elements
283
+ showSignal.set({ displayedNodes: [], testMode: mode === 'test' })
284
+ // Restore scroll state for the new component
486
285
  scrollStateRestorer = getScrollStateRestorer(
487
286
  message.data.component.name,
488
287
  )
288
+ // Destroy the dataSignal (including subscribers) for the previous component
289
+ dataSignal.destroy()
290
+ // Re-subscribe all dataSignal subscribers
291
+ setupDataSignalSubscribers()
292
+ // Re-initialize the data signal for the new component
293
+ ctxDataSignal?.destroy()
489
294
  }
490
295
 
491
296
  component = updateComponentLinks(message.data.component)
@@ -1758,68 +1563,7 @@ export const createRoot = (
1758
1563
  return ctx
1759
1564
  }
1760
1565
 
1761
- document.addEventListener('keydown', (event) => {
1762
- if (isInputTarget(event)) {
1763
- return
1764
- }
1765
- switch (event.key) {
1766
- case 'k':
1767
- if (event.metaKey) {
1768
- event.preventDefault()
1769
- }
1770
- }
1771
- postMessageToEditor({
1772
- type: 'keydown',
1773
- event: {
1774
- key: event.key,
1775
- metaKey: event.metaKey,
1776
- shiftKey: event.shiftKey,
1777
- altKey: event.altKey,
1778
- },
1779
- })
1780
- })
1781
- document.addEventListener('keyup', (event) => {
1782
- if (isInputTarget(event)) {
1783
- return
1784
- }
1785
- postMessageToEditor({
1786
- type: 'keyup',
1787
- event: {
1788
- key: event.key,
1789
- metaKey: event.metaKey,
1790
- shiftKey: event.shiftKey,
1791
- altKey: event.altKey,
1792
- },
1793
- })
1794
- })
1795
- document.addEventListener('keypress', (event) => {
1796
- if (isInputTarget(event)) {
1797
- return
1798
- }
1799
- postMessageToEditor({
1800
- type: 'keypress',
1801
- event: {
1802
- key: event.key,
1803
- metaKey: event.metaKey,
1804
- shiftKey: event.shiftKey,
1805
- altKey: event.altKey,
1806
- },
1807
- })
1808
- })
1809
-
1810
- dataSignal.subscribe((data) => {
1811
- if (component && components && packageComponents && data) {
1812
- try {
1813
- postMessageToEditor({ type: 'data', data })
1814
- } catch {
1815
- // If we're unable to send the data, let's try to JSON serialize it
1816
- postMessageToEditor({
1817
- type: 'data',
1818
- data: JSON.parse(JSON.stringify(data)),
1819
- })
1820
- }
1821
- }
1822
- })
1566
+ initKeyListeners()
1823
1567
 
1824
1568
  const clearSelectedStyleVariant = () => {
1825
1569
  if (styleVariantSelection) {
@@ -1880,28 +1624,6 @@ export const createRoot = (
1880
1624
  })()
1881
1625
  }
1882
1626
 
1883
- function getRectData(selectedNode: Element | null | undefined) {
1884
- if (!selectedNode) {
1885
- return null
1886
- }
1887
-
1888
- const { borderRadius, rotate } = window.getComputedStyle(selectedNode)
1889
- const rect: DOMRect = selectedNode.getBoundingClientRect()
1890
-
1891
- return {
1892
- left: rect.left,
1893
- right: rect.right,
1894
- top: rect.top,
1895
- bottom: rect.bottom,
1896
- width: rect.width,
1897
- height: rect.height,
1898
- x: rect.x,
1899
- y: rect.y,
1900
- borderRadius: borderRadius.split(' '),
1901
- rotate,
1902
- }
1903
- }
1904
-
1905
1627
  const insertOrReplaceHeadNode = (id: string, node: Node) => {
1906
1628
  const existing = document.head.querySelector(`[data-meta-id="${id}"]`)
1907
1629
  if (existing) {
@@ -2004,90 +1726,121 @@ const insertTheme = (
2004
1726
  parent.appendChild(styleElem)
2005
1727
  }
2006
1728
 
2007
- type PostMessageType =
2008
- | {
2009
- type: 'textComputedStyle'
2010
- computedStyle: Record<string, string>
2011
- }
2012
- | {
2013
- type: 'selection'
2014
- selectedNodeId: string | null
2015
- }
2016
- | {
2017
- type: 'highlight'
2018
- highlightedNodeId: string | null
2019
- }
2020
- | {
2021
- type: 'navigate'
2022
- name: string
2023
- }
2024
- | {
2025
- type: 'documentScrollSize'
2026
- scrollHeight: number
2027
- scrollWidth: number
2028
- }
2029
- | {
2030
- type: 'nodeMoved'
2031
- copy: boolean
2032
- parent?: string | null
2033
- index?: number
2034
- }
2035
- | {
2036
- type: 'computedStyle'
2037
- computedStyle: Record<string, string>
2038
- }
2039
- | {
2040
- type: 'style'
2041
- time: string
1729
+ const initKeyListeners = () => {
1730
+ document.addEventListener('keydown', (event) => {
1731
+ if (isInputTarget(event)) {
1732
+ return
2042
1733
  }
2043
- | {
2044
- type: 'component event'
2045
- event: any
2046
- time: string
2047
- data: any
1734
+ switch (event.key) {
1735
+ case 'k':
1736
+ if (event.metaKey) {
1737
+ event.preventDefault()
1738
+ }
2048
1739
  }
2049
- | {
2050
- type: 'keydown'
1740
+ postMessageToEditor({
1741
+ type: 'keydown',
2051
1742
  event: {
2052
- key: string
2053
- metaKey: boolean
2054
- shiftKey: boolean
2055
- altKey: boolean
2056
- }
1743
+ key: event.key,
1744
+ metaKey: event.metaKey,
1745
+ shiftKey: event.shiftKey,
1746
+ altKey: event.altKey,
1747
+ },
1748
+ })
1749
+ })
1750
+ document.addEventListener('keyup', (event) => {
1751
+ if (isInputTarget(event)) {
1752
+ return
2057
1753
  }
2058
- | {
2059
- type: 'keyup'
1754
+ postMessageToEditor({
1755
+ type: 'keyup',
2060
1756
  event: {
2061
- key: string
2062
- metaKey: boolean
2063
- shiftKey: boolean
2064
- altKey: boolean
2065
- }
1757
+ key: event.key,
1758
+ metaKey: event.metaKey,
1759
+ shiftKey: event.shiftKey,
1760
+ altKey: event.altKey,
1761
+ },
1762
+ })
1763
+ })
1764
+ document.addEventListener('keypress', (event) => {
1765
+ if (isInputTarget(event)) {
1766
+ return
2066
1767
  }
2067
- | {
2068
- type: 'keypress'
1768
+ postMessageToEditor({
1769
+ type: 'keypress',
2069
1770
  event: {
2070
- key: string
2071
- metaKey: boolean
2072
- shiftKey: boolean
2073
- altKey: boolean
2074
- }
2075
- }
2076
- | { type: 'data'; data: ComponentData }
2077
- | {
2078
- type: 'selectionRect'
2079
- rect: ReturnType<typeof getRectData>
1771
+ key: event.key,
1772
+ metaKey: event.metaKey,
1773
+ shiftKey: event.shiftKey,
1774
+ altKey: event.altKey,
1775
+ },
1776
+ })
1777
+ })
1778
+ }
1779
+
1780
+ const registerActions = (
1781
+ allActions: Record<string, PluginAction>,
1782
+ packageName?: string,
1783
+ ) => {
1784
+ const actions: Record<string, PluginActionV2> = {}
1785
+ Object.entries(allActions ?? {}).forEach(([name, action]) => {
1786
+ if (isLegacyPluginAction(action)) {
1787
+ // Legacy actions are self-registering. We need to execute them to register them
1788
+ Function(action.handler)()
1789
+ return
2080
1790
  }
2081
- | {
2082
- type: 'highlightRect'
2083
- rect: ReturnType<typeof getRectData>
1791
+ // We need to convert the handler string into a real function
1792
+ actions[name] = {
1793
+ ...(action as PluginActionV2),
1794
+ handler:
1795
+ typeof action.handler === 'string'
1796
+ ? (new Function(
1797
+ 'args, ctx',
1798
+ `${action.handler}
1799
+ return ${safeFunctionName(action.name)}(args, ctx)`,
1800
+ ) as ActionHandlerV2)
1801
+ : action.handler,
2084
1802
  }
2085
- | {
2086
- type: 'introspectionResult'
2087
- data: any
2088
- apiKey: string
1803
+ })
1804
+ window.toddle.actions[packageName ?? window.__toddle.project] = actions
1805
+ }
1806
+
1807
+ const registerFormulas = (
1808
+ allFormulas: Record<
1809
+ string,
1810
+ ToddleFormula | CodeFormula<FormulaHandlerV2> | CodeFormula<string>
1811
+ >,
1812
+ packageName?: string,
1813
+ ) => {
1814
+ const formulas: Record<string, PluginFormula<FormulaHandlerV2>> = {}
1815
+ Object.entries(allFormulas ?? {}).forEach(([name, formula]) => {
1816
+ if (
1817
+ !isToddleFormula<FormulaHandlerV2 | string>(formula) &&
1818
+ typeof formula.name === 'string' &&
1819
+ formula.version === undefined
1820
+ ) {
1821
+ // Legacy formulas are self-registering. We need to execute them to register them
1822
+ Function(formula.handler as unknown as string)()
1823
+ return
1824
+ } else if (!isToddleFormula<FormulaHandlerV2 | string>(formula)) {
1825
+ // For code formulas we need to convert the handler string into a real function
1826
+ formulas[name] = {
1827
+ ...formula,
1828
+ handler:
1829
+ typeof formula.handler === 'string'
1830
+ ? (new Function(
1831
+ 'args, ctx',
1832
+ `${formula.handler}
1833
+ return ${safeFunctionName(formula.name)}(args, ctx)`,
1834
+ ) as FormulaHandlerV2)
1835
+ : formula.handler,
1836
+ }
1837
+ return
2089
1838
  }
1839
+ formulas[name] = formula as PluginFormula<FormulaHandlerV2>
1840
+ })
1841
+ window.toddle.formulas[packageName ?? window.__toddle.project] = formulas
1842
+ }
2090
1843
 
2091
- const postMessageToEditor = (message: PostMessageType) => {
1844
+ const postMessageToEditor = (message: EditorPostMessageType) => {
2092
1845
  window.parent?.postMessage(message, '*')
2093
1846
  }
@@ -50,7 +50,10 @@ describe('CustomPropertyStyleSheet', () => {
50
50
  })('256px')
51
51
  expect(instance.getStyleSheet().cssRules.length).toBe(1)
52
52
  expect(instance.getStyleSheet().cssRules[0].cssText).toBe(
53
- '@media (max-width: 600px) { .my-class { --my-property: 256px; } }',
53
+ `\
54
+ @media (max-width: 600px) {
55
+ .my-class { --my-property: 256px; }
56
+ }`,
54
57
  )
55
58
  })
56
59
 
@@ -87,7 +90,10 @@ describe('CustomPropertyStyleSheet', () => {
87
90
  setter('256px')
88
91
  expect(instance.getStyleSheet().cssRules.length).toBe(1)
89
92
  expect(instance.getStyleSheet().cssRules[0].cssText).toBe(
90
- '@media (max-width: 600px) { .my-class-with-media { --my-property-with-media: 256px; } }',
93
+ `\
94
+ @media (max-width: 600px) {
95
+ .my-class-with-media { --my-property-with-media: 256px; }
96
+ }`,
91
97
  )
92
98
 
93
99
  instance.unregisterProperty(
@@ -98,7 +104,10 @@ describe('CustomPropertyStyleSheet', () => {
98
104
  },
99
105
  )
100
106
  expect(instance.getStyleSheet().cssRules[0].cssText).toBe(
101
- '@media (max-width: 600px) { .my-class-with-media { } }',
107
+ `\
108
+ @media (max-width: 600px) {
109
+ .my-class-with-media { }
110
+ }`,
102
111
  )
103
112
  })
104
113
  })