@nordcraft/runtime 1.0.50 → 1.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -4,8 +4,8 @@
4
4
  "type": "module",
5
5
  "homepage": "https://github.com/nordcraftengine/nordcraft",
6
6
  "dependencies": {
7
- "@nordcraft/core": "1.0.50",
8
- "@nordcraft/std-lib": "1.0.50",
7
+ "@nordcraft/core": "1.0.51",
8
+ "@nordcraft/std-lib": "1.0.51",
9
9
  "fast-deep-equal": "3.1.3",
10
10
  "path-to-regexp": "6.3.0"
11
11
  },
@@ -21,5 +21,5 @@
21
21
  "files": ["dist", "src"],
22
22
  "main": "dist/page.main.js",
23
23
  "types": "dist/page.main.d.ts",
24
- "version": "1.0.50"
24
+ "version": "1.0.51"
25
25
  }
@@ -25,7 +25,7 @@ export function subscribeToContext(
25
25
  if (!formulaDataSignal) {
26
26
  // eslint-disable-next-line no-console
27
27
  console.warn(
28
- `Provider ${providerName} does not expose a formula named "${formulaName}". Available formulas are: ["${Object.keys(
28
+ `Component error(${component.name}): Provider ${providerName} does not expose a formula named "${formulaName}". Available formulas are: ["${Object.keys(
29
29
  provider.formulaDataSignals,
30
30
  ).join('", "')}"]`,
31
31
  )
@@ -63,7 +63,7 @@ export function subscribeToContext(
63
63
  if (!testProvider) {
64
64
  // eslint-disable-next-line no-console
65
65
  console.error(
66
- `Could not find provider "${providerName}". No such component exist.`,
66
+ `Component error(${component.name}): Could not find provider "${providerName}". No such component exist.`,
67
67
  )
68
68
  return
69
69
  }
@@ -116,7 +116,7 @@ export function subscribeToContext(
116
116
  if (!formula) {
117
117
  // eslint-disable-next-line no-console
118
118
  console.warn(
119
- `Could not find formula "${formulaName}" in component "${providerName}"`,
119
+ `Component error(${component.name}): Could not find formula "${formulaName}" in provider "${providerName}"`,
120
120
  )
121
121
  return [formulaName, null]
122
122
  }
@@ -31,11 +31,11 @@ export class ToddleComponent extends HTMLElement {
31
31
  #ctx: ComponentContext
32
32
  #shadowRoot: ShadowRoot
33
33
  #signal: Signal<ComponentData>
34
- #files: { themes: Theme[] }
34
+ #files: { themes: Record<string, Theme> }
35
35
 
36
36
  constructor(
37
37
  component: Component,
38
- options: { components: Component[]; themes: Theme[] },
38
+ options: { components: Component[]; themes: Record<string, Theme> },
39
39
  toddle: Toddle<LocationSignal, never>,
40
40
  ) {
41
41
  super()
@@ -175,7 +175,9 @@ export class ToddleComponent extends HTMLElement {
175
175
  const styles = createStylesheet(
176
176
  this.#ctx.component,
177
177
  this.#ctx.components,
178
- this.#files.themes ? Object.values(this.#files.themes)[0] : defaultTheme,
178
+ Object.entries(this.#files.themes ?? {}).length > 0
179
+ ? this.#files.themes
180
+ : { defaultTheme },
179
181
  { includeResetStyle: true, createFontFaces: false },
180
182
  )
181
183
  const stylesElem = document.createElement('style')
@@ -27,7 +27,7 @@ export const defineComponents = (
27
27
  componentNames: string[],
28
28
  options: {
29
29
  components: Component[]
30
- themes: Theme[]
30
+ themes: Record<string, Theme>
31
31
  },
32
32
  toddle: Toddle<LocationSignal, never>,
33
33
  ) => {
@@ -25,8 +25,7 @@ import {
25
25
  import { valueFormula } from '@nordcraft/core/dist/formula/formulaUtils'
26
26
  import { getClassName } from '@nordcraft/core/dist/styling/className'
27
27
  import type { OldTheme, Theme } from '@nordcraft/core/dist/styling/theme'
28
- import { getThemeCss } from '@nordcraft/core/dist/styling/theme'
29
- import { theme } from '@nordcraft/core/dist/styling/theme.const'
28
+ import { getThemeCss, renderTheme } from '@nordcraft/core/dist/styling/theme'
30
29
  import type {
31
30
  ActionHandler,
32
31
  ActionHandlerV2,
@@ -109,7 +108,7 @@ type ToddlePreviewEvent =
109
108
  type: 'global_actions'
110
109
  actions: Record<string, PluginActionV2 | PluginAction>
111
110
  }
112
- | { type: 'theme'; theme: Theme | OldTheme }
111
+ | { type: 'theme'; theme: Record<string, OldTheme | Theme> }
113
112
  | { type: 'mode'; mode: 'design' | 'test' }
114
113
  | { type: 'attrs'; attrs: Record<string, unknown> }
115
114
  | { type: 'selection'; selectedNodeId: string | null }
@@ -152,7 +151,14 @@ type ToddlePreviewEvent =
152
151
  | undefined
153
152
  fillMode: 'none' | 'forwards' | 'backwards' | 'both' | undefined
154
153
  }
155
- | { type: 'preview_style'; styles: Record<string, string> | null }
154
+ | {
155
+ type: 'preview_style'
156
+ styles: Record<string, string> | null
157
+ theme?: {
158
+ key: string
159
+ value: Theme
160
+ }
161
+ }
156
162
 
157
163
  /**
158
164
  * Styles required for rendering the same exact text again somewhere else (on a overlay rect in the editor)
@@ -305,7 +311,6 @@ export const createRoot = (
305
311
  return false
306
312
  }
307
313
 
308
- insertTheme(document.head, theme)
309
314
  const dataSignal = signal<ComponentData>({
310
315
  Location: {
311
316
  query: {},
@@ -1051,7 +1056,7 @@ export const createRoot = (
1051
1056
  })
1052
1057
  break
1053
1058
  case 'preview_style':
1054
- const { styles: previewStyleStyles } = message.data
1059
+ const { styles: previewStyleStyles, theme } = message.data
1055
1060
  cancelAnimationFrame(previewStyleAnimationFrame)
1056
1061
  previewStyleAnimationFrame = requestAnimationFrame(() => {
1057
1062
  // Update or create a new style tag and set the given styles with important priority
@@ -1091,13 +1096,52 @@ export const createRoot = (
1091
1096
  }
1092
1097
  }
1093
1098
 
1094
- const previewStyles = Object.entries(previewStyleStyles)
1095
- .map(([key, value]) => `${key}: ${value} !important;`)
1096
- .join('\n')
1097
- styleTag.innerHTML = `[data-id="${selectedNodeId}"]${pseudoElement}, [data-id="${selectedNodeId}"] ~ [data-id^="${selectedNodeId}("]${pseudoElement} {
1099
+ // If theme property preview, then override happens at root level and with reasonable specificity.
1100
+ // Otherwise, force (!important) the style directly on the element.
1101
+ if (theme) {
1102
+ theme.value.propertyDefinitions = Object.fromEntries(
1103
+ Object.entries(theme.value.propertyDefinitions ?? {})
1104
+ .filter(([key]) => previewStyleStyles[key])
1105
+ .map(([key, val]) => [
1106
+ key,
1107
+ { ...val, value: previewStyleStyles[key] },
1108
+ ]),
1109
+ )
1110
+ const cssBlocks: string[] = []
1111
+ if (theme.value.default) {
1112
+ cssBlocks.push(renderTheme(`:host, :root`, theme.value))
1113
+ }
1114
+ if (theme.value.defaultDark) {
1115
+ cssBlocks.push(
1116
+ renderTheme(
1117
+ `:host, :root`,
1118
+ theme.value,
1119
+ '@media (prefers-color-scheme: dark)',
1120
+ ),
1121
+ )
1122
+ }
1123
+ if (theme.value.defaultLight) {
1124
+ cssBlocks.push(
1125
+ renderTheme(
1126
+ `:host, :root`,
1127
+ theme.value,
1128
+ '@media (prefers-color-scheme: light)',
1129
+ ),
1130
+ )
1131
+ }
1132
+ cssBlocks.push(
1133
+ renderTheme(`[data-theme~="${theme.key}"]`, theme.value),
1134
+ )
1135
+ styleTag.innerHTML = cssBlocks.join('\n')
1136
+ } else {
1137
+ const previewStyles = Object.entries(previewStyleStyles)
1138
+ .map(([key, value]) => `${key}: ${value} !important;`)
1139
+ .join('\n')
1140
+ styleTag.innerHTML = `[data-id="${selectedNodeId}"]${pseudoElement}, [data-id="${selectedNodeId}"] ~ [data-id^="${selectedNodeId}("]${pseudoElement} {
1098
1141
  ${previewStyles}
1099
1142
  transition: none !important;
1100
1143
  }`
1144
+ }
1101
1145
  })
1102
1146
  break
1103
1147
  }
@@ -1882,12 +1926,15 @@ function getNodeId(component: Component, path: string[]) {
1882
1926
  return getId(path, 'root')
1883
1927
  }
1884
1928
 
1885
- const insertTheme = (parent: HTMLElement, theme: Theme | OldTheme) => {
1929
+ const insertTheme = (
1930
+ parent: HTMLElement,
1931
+ themes: Record<string, OldTheme | Theme>,
1932
+ ) => {
1886
1933
  document.getElementById('theme-style')?.remove()
1887
1934
  const styleElem = document.createElement('style')
1888
1935
  styleElem.setAttribute('type', 'text/css')
1889
1936
  styleElem.setAttribute('id', 'theme-style')
1890
- styleElem.innerHTML = getThemeCss(theme, {
1937
+ styleElem.innerHTML = getThemeCss(themes, {
1891
1938
  includeResetStyle: false,
1892
1939
  createFontFaces: true,
1893
1940
  })