smbls 3.14.1 → 3.14.2
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/dist/cjs/package.json +4 -0
- package/index.js +2 -2
- package/package.json +1 -1
- package/src/createDomql.js +56 -10
- package/src/hydrate.js +1 -1
- package/src/index.js +48 -0
- package/src/prepare.js +15 -5
- package/src/syncExtend.js +11 -44
- package/dist/iife/index-string.js +0 -2
- package/dist/iife/index.js +0 -44
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// v3.14 entry point - re-exports all framework packages
|
|
4
4
|
|
|
5
|
-
// Core
|
|
5
|
+
// Core v3.14 primitives (NEW)
|
|
6
6
|
export * from '@symbo.ls/signal'
|
|
7
7
|
export * from '@symbo.ls/css'
|
|
8
8
|
|
package/package.json
CHANGED
package/src/createDomql.js
CHANGED
|
@@ -4,14 +4,10 @@ import { create as createElement } from '@symbo.ls/element'
|
|
|
4
4
|
import * as uikit from '@symbo.ls/default-config/components'
|
|
5
5
|
import { CSS_PROPS_REGISTRY } from 'css-in-props'
|
|
6
6
|
|
|
7
|
-
import { isString, isNode, isObject, destringifyGlobalScope, deepDestringifyFunctions } from '@symbo.ls/utils'
|
|
7
|
+
import { isString, isNode, isObject, destringifyGlobalScope, deepDestringifyFunctions, setActiveRootState } from '@symbo.ls/utils'
|
|
8
8
|
import { defaultDefine } from './define.js'
|
|
9
9
|
import { initRouter } from './router.js'
|
|
10
|
-
import {
|
|
11
|
-
initializeExtend,
|
|
12
|
-
initializeNotifications,
|
|
13
|
-
initializeSync
|
|
14
|
-
} from './syncExtend.js'
|
|
10
|
+
import { initializeExtend } from './syncExtend.js'
|
|
15
11
|
|
|
16
12
|
import {
|
|
17
13
|
prepareComponents,
|
|
@@ -34,6 +30,8 @@ import { fetchPlugin } from '@symbo.ls/fetch'
|
|
|
34
30
|
import { capsizePlugin, capsizeHandler } from '@symbo.ls/capsize'
|
|
35
31
|
import { shorthandPlugin } from '@symbo.ls/shorthand'
|
|
36
32
|
import { analyzePlugin, createAnalyzeState } from '@symbo.ls/analyze'
|
|
33
|
+
import { syncPlugin, notificationsPlugin } from '@symbo.ls/sync'
|
|
34
|
+
import { inspectPlugin } from '@symbo.ls/inspect'
|
|
37
35
|
|
|
38
36
|
// hydrate utilities available for future true-hydration opt-in
|
|
39
37
|
// import { hydrate, assignBrKeysFromRegistry } from './hydrate.js'
|
|
@@ -77,6 +75,12 @@ export const prepareContext = async (app, context = {}) => {
|
|
|
77
75
|
|
|
78
76
|
const state = prepareState(app, context)
|
|
79
77
|
context.state = state
|
|
78
|
+
// Register the active root state in the framework registry so
|
|
79
|
+
// `getRootState()` (called without `this`) can find it during early
|
|
80
|
+
// render. Eliminates the requirement that projects pre-set
|
|
81
|
+
// `window.smblsApp = { state }` in their `index.js` — the runner
|
|
82
|
+
// bypasses project-side index.js entirely, and now no longer needs to.
|
|
83
|
+
setActiveRootState(state)
|
|
80
84
|
context.pages = preparePages(app, context)
|
|
81
85
|
context.components = prepareComponents(context)
|
|
82
86
|
context.utils = prepareUtils(context)
|
|
@@ -104,7 +108,7 @@ export const prepareContext = async (app, context = {}) => {
|
|
|
104
108
|
// nominal type — invalid CSS for `transform`, dead listeners for
|
|
105
109
|
// `onClick`, raw source code shown for `text`, etc. — which is the root
|
|
106
110
|
// cause of every "works on dev / dead on remote" divergence we've ever
|
|
107
|
-
// seen for
|
|
111
|
+
// seen for v3.14 published projects. Walks the same buckets prepareContext
|
|
108
112
|
// populated above, mutating each into a tree where every detectable
|
|
109
113
|
// function-string has been `eval`'d back to a real function.
|
|
110
114
|
// ESM-namespace-shaped buckets (`import * as functions from ...`) have
|
|
@@ -170,6 +174,36 @@ export const prepareContext = async (app, context = {}) => {
|
|
|
170
174
|
context.plugins.push(analyzePlugin)
|
|
171
175
|
}
|
|
172
176
|
|
|
177
|
+
// Sync plugin — HMR module for both transports (mermaid-served collab and
|
|
178
|
+
// runner-served local). Plugged ON by default; users opt out by setting
|
|
179
|
+
// `context.sync = false` (or `editor.liveSync = false`) or by removing
|
|
180
|
+
// syncPlugin from `context.plugins` before calling `create()`. With
|
|
181
|
+
// `context.sync = false` the plugin is never pushed, so SyncComponent
|
|
182
|
+
// never reaches `app.extends` and no socket connection is attempted.
|
|
183
|
+
if (context.sync !== false && !hasPlugin('sync')) {
|
|
184
|
+
context.plugins.push(syncPlugin)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Inspect plugin — element inspector overlay. Default OFF. Opt-in by
|
|
188
|
+
// setting `context.inspect = true` (or a config object) — this auto-
|
|
189
|
+
// registers the plugin which adds Alt+Shift highlight + click capture.
|
|
190
|
+
// See `@symbo.ls/inspect` README for the shortcut + `editor.onInspect`
|
|
191
|
+
// callback contract.
|
|
192
|
+
if (context.inspect && !hasPlugin('inspect')) {
|
|
193
|
+
context.plugins.push(inspectPlugin)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Notifications plugin — toast overlay for sync connect/disconnect.
|
|
197
|
+
// Default OFF. Opt-in via `context.notifications = true` (or the
|
|
198
|
+
// legacy `editor.verbose = true` for backwards compat). Plugin's
|
|
199
|
+
// beforeCreate filters again so flipping `context.notifications =
|
|
200
|
+
// false` short-circuits even if the plugin is pushed manually.
|
|
201
|
+
const notificationsOptIn = context.notifications === true ||
|
|
202
|
+
(context.editor && context.editor.verbose === true)
|
|
203
|
+
if (notificationsOptIn && context.notifications !== false && !hasPlugin('notifications')) {
|
|
204
|
+
context.plugins.push(notificationsPlugin)
|
|
205
|
+
}
|
|
206
|
+
|
|
173
207
|
return context
|
|
174
208
|
}
|
|
175
209
|
|
|
@@ -242,8 +276,20 @@ export const createDomqlElement = async (app, ctx) => {
|
|
|
242
276
|
)
|
|
243
277
|
}
|
|
244
278
|
|
|
245
|
-
|
|
246
|
-
|
|
279
|
+
// Run plugin `beforeCreate` lifecycle. All sync/notifications/inspect
|
|
280
|
+
// injection happens here — the framework knows nothing about which
|
|
281
|
+
// plugins run. Remove the relevant plugin from `ctx.plugins` (or set
|
|
282
|
+
// `context.sync = false` / `context.inspect = false` / etc) and no
|
|
283
|
+
// attach happens.
|
|
284
|
+
for (const plugin of ctx.plugins) {
|
|
285
|
+
if (typeof plugin.beforeCreate === 'function') {
|
|
286
|
+
try {
|
|
287
|
+
plugin.beforeCreate(app, ctx)
|
|
288
|
+
} catch (err) {
|
|
289
|
+
console.error(`[smbls] plugin "${plugin.name || '?'}" beforeCreate error:`, err)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
247
293
|
|
|
248
294
|
const doc = ctx.document
|
|
249
295
|
if (!doc || !doc.createElement) return app
|
|
@@ -254,7 +300,7 @@ export const createDomqlElement = async (app, ctx) => {
|
|
|
254
300
|
return fallbackRender(createElement, app, parentNode, ctx, win, ssrStyles)
|
|
255
301
|
}
|
|
256
302
|
|
|
257
|
-
//
|
|
303
|
+
// v3.14: use @symbo.ls/element create directly
|
|
258
304
|
const smblsApp = createElement(app, parentNode, ctx.key, {
|
|
259
305
|
verbose: ctx.verbose,
|
|
260
306
|
context: ctx,
|
package/src/hydrate.js
CHANGED
|
@@ -436,7 +436,7 @@ const bindEvents = (el) => {
|
|
|
436
436
|
|
|
437
437
|
if (!el.__ref.__eventCleanup) el.__ref.__eventCleanup = []
|
|
438
438
|
|
|
439
|
-
//
|
|
439
|
+
// v3.14: event handlers are flat on element as onX properties
|
|
440
440
|
for (const key in el) {
|
|
441
441
|
if (key.length <= 2 || key[0] !== 'o' || key[1] !== 'n') continue
|
|
442
442
|
if (typeof el[key] !== 'function') continue
|
package/src/index.js
CHANGED
|
@@ -81,6 +81,36 @@ const resolveAndApplyTheme = (options) => {
|
|
|
81
81
|
options.themeRoot = scopeRoot
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
// Read `<meta name="symbols-runtime" content="...">` from the served
|
|
85
|
+
// document. This is how the runner signals its mode to the framework
|
|
86
|
+
// without a window global — it injects the meta tag into the served
|
|
87
|
+
// HTML, the framework reads it once at create() time and stamps the
|
|
88
|
+
// matching `editor.runtime` so syncPlugin (and anyone else who cares)
|
|
89
|
+
// can detect runner mode via context.
|
|
90
|
+
const readRuntimeMeta = () => {
|
|
91
|
+
if (typeof document === 'undefined') return null
|
|
92
|
+
try {
|
|
93
|
+
const m = document.querySelector('meta[name="symbols-runtime"]')
|
|
94
|
+
const v = m && m.getAttribute('content')
|
|
95
|
+
return (typeof v === 'string' && v) ? v : null
|
|
96
|
+
} catch (_) {
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const stampRuntimeFromMeta = (options) => {
|
|
102
|
+
const runtime = readRuntimeMeta()
|
|
103
|
+
if (!runtime) return
|
|
104
|
+
if (!options.editor) options.editor = {}
|
|
105
|
+
// Don't clobber an explicit project setting — projects can override
|
|
106
|
+
// by setting `editor.runtime` themselves before calling create.
|
|
107
|
+
if (!options.editor.runtime) options.editor.runtime = runtime
|
|
108
|
+
// Default livesync on for runner mode unless the project disabled it.
|
|
109
|
+
if (runtime === 'runner' && typeof options.editor.livesync === 'undefined') {
|
|
110
|
+
options.editor.livesync = true
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
84
114
|
export const create = (
|
|
85
115
|
App,
|
|
86
116
|
options = DEFAULT_CREATE_OPTIONS,
|
|
@@ -91,6 +121,11 @@ export const create = (
|
|
|
91
121
|
...mergeWithLocalFile(options, optionsExternalFile)
|
|
92
122
|
}
|
|
93
123
|
|
|
124
|
+
// Pick up runner-mode (or any future runtime tag) from the served HTML.
|
|
125
|
+
// Has to happen before `createDomqlElement` so syncPlugin's beforeCreate
|
|
126
|
+
// sees the stamped editor.runtime.
|
|
127
|
+
stampRuntimeFromMeta(redefinedOptions)
|
|
128
|
+
|
|
94
129
|
// Resolve the active theme synchronously, before the async init chain,
|
|
95
130
|
// and write `data-theme` to the scope's root element. This gives the
|
|
96
131
|
// first paint the correct theme — no project-side setAttribute hack,
|
|
@@ -151,6 +186,12 @@ export const createSync = async (
|
|
|
151
186
|
...mergeWithLocalFile(options, optionsExternalFile)
|
|
152
187
|
}
|
|
153
188
|
|
|
189
|
+
// Pick up runner-mode from the served HTML's meta tag — same path
|
|
190
|
+
// `create` uses. Required because projects often boot via createSync
|
|
191
|
+
// (e.g. starter-kit, docs/developers) and the runner needs to detect
|
|
192
|
+
// its mode regardless of which entry point the project chose.
|
|
193
|
+
stampRuntimeFromMeta(redefinedOptions)
|
|
194
|
+
|
|
154
195
|
// const SYMBOLS_KEY = process.env.SYMBOLS_KEY
|
|
155
196
|
const key = options.key
|
|
156
197
|
await fetchSync(key, redefinedOptions)
|
|
@@ -195,3 +236,10 @@ export { defaultDefine, createDefine } from './define.js'
|
|
|
195
236
|
// Polyglot i18n plugin
|
|
196
237
|
export { polyglotPlugin, translate, setLang, getActiveLang, getLanguages, loadTranslations, upsertTranslation, initPolyglot, getLocalStateLang } from '@symbo.ls/polyglot'
|
|
197
238
|
export { polyglotFunctions } from '@symbo.ls/polyglot/functions'
|
|
239
|
+
|
|
240
|
+
// Theme switching — exposed on the IIFE bundle so project code can call
|
|
241
|
+
// `Smbls.changeGlobalTheme('dark')` from within serialized handlers
|
|
242
|
+
// (mermaid SSR runtime). Without an explicit re-export here, the bundler
|
|
243
|
+
// tree-shakes the symbol out of dist/iife/index.js because nothing in the
|
|
244
|
+
// smbls/src tree calls it directly.
|
|
245
|
+
export { changeGlobalTheme } from '@symbo.ls/scratch'
|
package/src/prepare.js
CHANGED
|
@@ -18,7 +18,12 @@ import { init } from './init.js'
|
|
|
18
18
|
import { getActiveConfig, createConfig, pushConfig, popConfig } from '@symbo.ls/scratch'
|
|
19
19
|
import { DEFAULT_CONTEXT } from './options.js'
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
// FT-FRAMEWORK-1: source from the explicit COMPONENTS manifest, not from
|
|
22
|
+
// `import * as uikit`. Parcel under `sideEffects: false` was pruning entries
|
|
23
|
+
// off the namespace import — projects ended up with atoms missing from
|
|
24
|
+
// `context.components`. The manifest is a plain object literal so the
|
|
25
|
+
// bundler can't mistake any entry for an unused import.
|
|
26
|
+
import { COMPONENTS as uikit } from '@symbo.ls/default-config/components'
|
|
22
27
|
import * as utils from './utilImports.js'
|
|
23
28
|
import * as routerUtils from '@symbo.ls/router'
|
|
24
29
|
|
|
@@ -472,10 +477,15 @@ export const prepareState = (app, context) => {
|
|
|
472
477
|
// Merge polyglot translations for active language into state
|
|
473
478
|
const poly = context.polyglot
|
|
474
479
|
if (poly?.translations) {
|
|
475
|
-
// Check localStorage for persisted language preference
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
480
|
+
// Check localStorage for persisted language preference. Wrap the
|
|
481
|
+
// access — sandboxed iframes / Firefox storage-disabled mode throw on
|
|
482
|
+
// .getItem(), not just on .setItem().
|
|
483
|
+
let storedLang = null
|
|
484
|
+
try {
|
|
485
|
+
if (typeof localStorage !== 'undefined') {
|
|
486
|
+
storedLang = localStorage.getItem(poly.storageLangKey || 'smbls_lang') || localStorage.getItem('lang')
|
|
487
|
+
}
|
|
488
|
+
} catch (e) {}
|
|
479
489
|
const lang = storedLang || state.lang || poly.defaultLang || 'en'
|
|
480
490
|
if (storedLang && storedLang !== state.lang) state.lang = storedLang
|
|
481
491
|
const langT = poly.translations[lang]
|
package/src/syncExtend.js
CHANGED
|
@@ -1,50 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
import { isObjectLike
|
|
4
|
-
|
|
3
|
+
import { isObjectLike } from '@symbo.ls/utils'
|
|
4
|
+
|
|
5
|
+
// All sync-related auto-injection moved to plugins:
|
|
6
|
+
// - `syncPlugin` (HMR) in `@symbo.ls/sync`
|
|
7
|
+
// - `notificationsPlugin` (toasts) in `@symbo.ls/sync`
|
|
8
|
+
// - `inspectPlugin` (overlay) in `@symbo.ls/inspect`
|
|
9
|
+
// The framework registers them through the generic `context.plugins`
|
|
10
|
+
// mechanism in `prepareContext` (`./createDomql.js`). This file only
|
|
11
|
+
// exposes the lone helper that survived: `initializeExtend`, which
|
|
12
|
+
// normalises `app.extends` to an array before any plugin's
|
|
13
|
+
// `beforeCreate` runs.
|
|
5
14
|
|
|
6
15
|
export const initializeExtend = (app, ctx) => {
|
|
7
16
|
return isObjectLike(app.extends) ? app.extends : []
|
|
8
17
|
}
|
|
9
|
-
|
|
10
|
-
export const initializeSync = (app, ctx) => {
|
|
11
|
-
const { editor } = ctx
|
|
12
|
-
if (!editor) return
|
|
13
|
-
const liveSync = isUndefined(editor.liveSync) ? isDevelopment() : editor.liveSync
|
|
14
|
-
if (liveSync) {
|
|
15
|
-
if (isArray(app.extends)) app.extends.push(SyncComponent)
|
|
16
|
-
else if (app.extends) {
|
|
17
|
-
app.extends = [app.extends, SyncComponent]
|
|
18
|
-
} else {
|
|
19
|
-
app.extends = [SyncComponent]
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const initializeInspect = (app, ctx) => {
|
|
25
|
-
const { editor } = ctx
|
|
26
|
-
if (!editor) return
|
|
27
|
-
const inspect = isUndefined(editor.inspect) ? isDevelopment() : editor.inspect
|
|
28
|
-
if (inspect) {
|
|
29
|
-
if (isArray(app.extends)) app.extends.push(Inspect)
|
|
30
|
-
else if (app.extends) {
|
|
31
|
-
app.extends = [app.extends, Inspect]
|
|
32
|
-
} else {
|
|
33
|
-
app.extends = [Inspect]
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const initializeNotifications = (app, ctx) => {
|
|
39
|
-
const { editor } = ctx
|
|
40
|
-
if (!editor) return
|
|
41
|
-
const verbose = isUndefined(editor.verbose) ? isDevelopment() || ctx.verbose : editor.verbose
|
|
42
|
-
if (verbose) {
|
|
43
|
-
if (isArray(app.extends)) app.extends.push(Notifications)
|
|
44
|
-
else if (app.extends) {
|
|
45
|
-
app.extends = [app.extends, Notifications]
|
|
46
|
-
} else {
|
|
47
|
-
app.extends = [Notifications]
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|