smbls 3.14.2 → 3.14.6

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/src/index.js DELETED
@@ -1,245 +0,0 @@
1
- 'use strict'
2
-
3
- import { deepMerge, isObject, isUndefined } from '@symbo.ls/utils'
4
-
5
- import * as utils from './utilImports.js'
6
-
7
- import { onpopstateRouter } from './router.js'
8
- import { fetchAsync, fetchSync } from './fetchOnCreate.js'
9
- import { destroy } from './destroy.js'
10
-
11
- import DEFAULT_CREATE_OPTIONS from './options.js'
12
- import { createDomqlElement } from './createDomql.js'
13
-
14
- const mergeWithLocalFile = (options, optionsExternalFile) =>
15
- deepMerge(
16
- options,
17
- isObject(optionsExternalFile) ? optionsExternalFile : {}
18
- )
19
-
20
- // Sync theme resolver. Order of precedence:
21
- // 1. `?globalTheme=<name>` URL parameter — used by embedded iframes to
22
- // push a theme into the child app.
23
- // 2. `options.themeStorageKey` via `localStorage` — previously remembered
24
- // user choice. Supply `themeStorageKey: false` to opt out entirely.
25
- // 3. `options.globalTheme` — the value configured in the project.
26
- // The resolved value lands on `options.globalTheme` (for downstream
27
- // `scratch.set`) and on `options.themeRoot.setAttribute('data-theme', …)`
28
- // for the first paint. `'auto'` follows `prefers-color-scheme` and writes
29
- // either 'dark' or 'light' onto the attribute so per-element
30
- // `[data-theme="…"] &` rules can resolve without any @media wrapper.
31
- // Scratch.set then takes over and registers a live `prefers-color-scheme`
32
- // listener so later OS changes flip the attribute automatically.
33
- const resolveAndApplyTheme = (options) => {
34
- if (typeof document === 'undefined') return
35
- const scopeRoot = options.themeRoot ||
36
- (options.document && options.document.documentElement) ||
37
- document.documentElement
38
- if (!scopeRoot || typeof scopeRoot.setAttribute !== 'function') return
39
-
40
- let theme = options.globalTheme || 'auto'
41
-
42
- // URL override — preview/editor-style iframe integration. Forces a theme.
43
- try {
44
- if (typeof window !== 'undefined' && window.location) {
45
- const urlTheme = new URLSearchParams(window.location.search).get('globalTheme')
46
- if (urlTheme) theme = urlTheme
47
- }
48
- } catch (e) {} // jsdom / sandboxed windows can throw
49
-
50
- // Persisted user choice — only consulted when no explicit config/URL
51
- // value is forcing a different one.
52
- const storageKey = options.themeStorageKey
53
- if (theme === 'auto' && storageKey && typeof localStorage !== 'undefined') {
54
- try {
55
- const stored = localStorage.getItem(storageKey)
56
- if (stored) theme = stored
57
- } catch (e) {}
58
- }
59
-
60
- // Early-paint attribute: we always need a concrete `data-theme` so the
61
- // single CSS selector pattern `[data-theme="<scheme>"]` resolves. For
62
- // `auto`, resolve once from `prefers-color-scheme` — scratch.set will
63
- // install a listener later so subsequent OS changes update the attr
64
- // live.
65
- const resolvedForAttr = theme === 'auto'
66
- ? (() => {
67
- try {
68
- return (typeof window !== 'undefined' && window.matchMedia &&
69
- window.matchMedia('(prefers-color-scheme: dark)').matches)
70
- ? 'dark' : 'light'
71
- } catch (e) { return 'light' }
72
- })()
73
- : theme
74
-
75
- scopeRoot.setAttribute('data-theme', resolvedForAttr)
76
-
77
- // Keep `options.globalTheme` semantic: only overwrite if we resolved to
78
- // a forced value (URL / localStorage). Leaving it as `'auto'` tells
79
- // scratch.set to register the `prefers-color-scheme` listener.
80
- options.globalTheme = theme
81
- options.themeRoot = scopeRoot
82
- }
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
-
114
- export const create = (
115
- App,
116
- options = DEFAULT_CREATE_OPTIONS,
117
- optionsExternalFile
118
- ) => {
119
- const redefinedOptions = {
120
- ...DEFAULT_CREATE_OPTIONS,
121
- ...mergeWithLocalFile(options, optionsExternalFile)
122
- }
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
-
129
- // Resolve the active theme synchronously, before the async init chain,
130
- // and write `data-theme` to the scope's root element. This gives the
131
- // first paint the correct theme — no project-side setAttribute hack,
132
- // no flash of the wrong OS theme. The resolved value is written back
133
- // into options so the downstream scratch.set() uses the same value
134
- // (instead of re-resolving from its own defaults).
135
- resolveAndApplyTheme(redefinedOptions)
136
-
137
- const domqlApp = createDomqlElement(App, redefinedOptions).then((app) => {
138
- onpopstateRouter(app, redefinedOptions)
139
-
140
- // Ergonomic shortcut so callers can `app.destroy()` instead of importing.
141
- app.destroy = () => destroy(app)
142
-
143
- if (app.onCreate) app.onCreate(app, app.state, app.context, redefinedOptions)
144
-
145
- // Hydration gate: flip the analyze plugin from dormant → active.
146
- // Browser/network listeners attach here; pre-ready error buffer is drained.
147
- if (app.context?.analyze?.activate) {
148
- try { app.context.analyze.activate(app.context) } catch (err) {
149
- console.error('[analyze] activate error:', err)
150
- }
151
- }
152
-
153
- return app
154
- }).catch((err) => {
155
- console.error('[smbls] create error:', err)
156
- throw err
157
- })
158
-
159
- return domqlApp
160
- }
161
-
162
- export const createAsync = (
163
- App,
164
- options = DEFAULT_CREATE_OPTIONS,
165
- optionsExternalFile
166
- ) => {
167
- const domqlApp = create(App, options, optionsExternalFile)
168
-
169
- const redefinedOptions = {
170
- ...DEFAULT_CREATE_OPTIONS,
171
- ...mergeWithLocalFile(options, optionsExternalFile)
172
- }
173
- const key = redefinedOptions.key
174
- fetchAsync(domqlApp, key, { utils, ...redefinedOptions })
175
-
176
- return domqlApp
177
- }
178
-
179
- export const createSync = async (
180
- App,
181
- options = DEFAULT_CREATE_OPTIONS,
182
- optionsExternalFile
183
- ) => {
184
- const redefinedOptions = {
185
- ...DEFAULT_CREATE_OPTIONS,
186
- ...mergeWithLocalFile(options, optionsExternalFile)
187
- }
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
-
195
- // const SYMBOLS_KEY = process.env.SYMBOLS_KEY
196
- const key = options.key
197
- await fetchSync(key, redefinedOptions)
198
-
199
- const domqlApp = await createDomqlElement(App, redefinedOptions)
200
- onpopstateRouter(domqlApp, redefinedOptions)
201
- domqlApp.destroy = () => destroy(domqlApp)
202
- if (redefinedOptions.onCreate)
203
- await redefinedOptions.onCreate(
204
- domqlApp,
205
- domqlApp.state,
206
- domqlApp.context,
207
- redefinedOptions
208
- )
209
-
210
- return domqlApp
211
- }
212
-
213
- export const createSkeleton = (
214
- App = {},
215
- options = DEFAULT_CREATE_OPTIONS,
216
- optionsExternalFile
217
- ) => {
218
- return create(
219
- {
220
- deps: { isUndefined },
221
- ...App
222
- },
223
- deepMerge({ domqlOptions: { onlyResolveExtends: true } }, options),
224
- optionsExternalFile
225
- )
226
- }
227
-
228
- export { destroy } from './destroy.js'
229
-
230
- export default create
231
-
232
- export * from './init.js'
233
- export { DEFAULT_CONTEXT, DESIGN_SYSTEM_OPTIONS, ROUTER_OPTIONS } from './options.js'
234
- export { defaultDefine, createDefine } from './define.js'
235
-
236
- // Polyglot i18n plugin
237
- export { polyglotPlugin, translate, setLang, getActiveLang, getLanguages, loadTranslations, upsertTranslation, initPolyglot, getLocalStateLang } from '@symbo.ls/polyglot'
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/init.js DELETED
@@ -1,172 +0,0 @@
1
- 'use strict'
2
-
3
- import {
4
- set,
5
- getActiveConfig,
6
- getFontFaceString,
7
- appendSVGSprite,
8
- appendSvgIconsSprite,
9
- changeGlobalTheme as _changeGlobalTheme
10
- } from '@symbo.ls/scratch'
11
-
12
- import { isObject, deepMerge, deepClone } from '@symbo.ls/utils'
13
-
14
- import { css, injectGlobal } from '@symbo.ls/css'
15
-
16
- const CONFIG = getActiveConfig()
17
-
18
- const mergeWithLocalFile = (config = CONFIG, options) => {
19
- const rcfile = isObject(options.localFile)
20
- ? options.localFile
21
- : {}
22
- const clonedFile = deepClone(rcfile.designSystem || {})
23
- return deepMerge(config, clonedFile)
24
- }
25
-
26
- const SET_OPTIONS = {
27
- useVariable: true,
28
- useReset: true,
29
- useFontImport: true,
30
- useIconSprite: true,
31
- useDocumentTheme: true,
32
- useSvgSprite: true
33
- }
34
-
35
- export const init = (config, options = SET_OPTIONS) => {
36
- const resultConfig = mergeWithLocalFile(config || {}, options)
37
- const scope = options.scopeSelector || ':root'
38
- const themeScope = scope === ':root' ? ':root:not([data-theme])' : `${scope}:not([data-theme])`
39
-
40
- // Allow URL param to override globalTheme (used by preview iframe)
41
- let globalTheme = options.globalTheme
42
- if (typeof window !== 'undefined' && window.location) {
43
- const urlTheme = new URLSearchParams(window.location.search).get('globalTheme')
44
- if (urlTheme) globalTheme = urlTheme
45
- }
46
-
47
- const conf = set(
48
- {
49
- verbose: options.verbose,
50
- useReset: options.useReset,
51
- useFontImport: options.useFontImport,
52
- useVariable: options.useVariable,
53
- useSvgSprite: options.useSvgSprite,
54
- useDocumentTheme: options.useDocumentTheme,
55
- useIconSprite: options.useIconSprite,
56
- useDefaultConfig: options.useDefaultConfig,
57
- globalTheme,
58
- themeRoot: options.themeRoot,
59
- files: options.files,
60
- assets: options.assets,
61
- ...resultConfig
62
- },
63
- { newConfig: options.newConfig, config: options.config }
64
- )
65
- // Remember the scope selector on the config so downstream consumers
66
- // (e.g. set.js live updates) can target the right CSS rule.
67
- if (conf) conf.scopeSelector = scope
68
-
69
- const FontFace = getFontFaceString(conf.font, conf.files)
70
-
71
- const useReset = conf.useReset
72
- const useVariable = conf.useVariable
73
- const useFontImport = conf.useFontImport
74
- const useSvgSprite = conf.useSvgSprite
75
- const hasSvgs = config.svg
76
- const useIconSprite = conf.useIconSprite
77
- const hasIcons = config.icons
78
-
79
- if (useFontImport) injectGlobal(FontFace)
80
- if (useVariable) {
81
- injectGlobal({ [scope]: conf.CSS_VARS })
82
- // Inject theme-switching CSS vars (media queries + data-theme selectors)
83
- if (conf.CSS_MEDIA_VARS) {
84
- const themeStyles = {}
85
- for (const key in conf.CSS_MEDIA_VARS) {
86
- if (key.startsWith('@media')) {
87
- // Media query — only apply when no data-theme forces a theme
88
- themeStyles[key] = { [themeScope]: conf.CSS_MEDIA_VARS[key] }
89
- } else {
90
- // Selector ([data-theme="..."]) — apply directly
91
- themeStyles[key] = conf.CSS_MEDIA_VARS[key]
92
- }
93
- }
94
- injectGlobal(themeStyles)
95
- }
96
- }
97
- if (useReset) injectGlobal(conf.reset)
98
-
99
- // Register all ANIMATION entries as global @keyframes
100
- const animations = conf.animation
101
- if (animations) {
102
- const keyframesCSS = {}
103
- for (const name in animations) {
104
- keyframesCSS[`@keyframes ${name}`] = animations[name]
105
- }
106
- injectGlobal(keyframesCSS)
107
- }
108
-
109
- if (hasSvgs || useSvgSprite)
110
- appendSVGSprite(conf.svg, { document: options.document })
111
-
112
- if (hasIcons || useIconSprite)
113
- appendSvgIconsSprite(conf.icons, { document: options.document })
114
-
115
- return conf
116
- }
117
-
118
- const UPDATE_OPTIONS = {}
119
-
120
- export const reinit = (config, options = UPDATE_OPTIONS) => {
121
- const resultConfig = mergeWithLocalFile(config || {}, options)
122
- const scope = options.scopeSelector || ':root'
123
- const themeScope = scope === ':root' ? ':root:not([data-theme])' : `${scope}:not([data-theme])`
124
- const conf = set({
125
- verbose: false,
126
- ...resultConfig
127
- })
128
- if (!options.preventInject) {
129
- injectGlobal({ [scope]: conf.CSS_VARS })
130
- if (conf.CSS_MEDIA_VARS) {
131
- const themeStyles = {}
132
- for (const key in conf.CSS_MEDIA_VARS) {
133
- if (key.startsWith('@media')) {
134
- themeStyles[key] = { [themeScope]: conf.CSS_MEDIA_VARS[key] }
135
- } else {
136
- themeStyles[key] = conf.CSS_MEDIA_VARS[key]
137
- }
138
- }
139
- injectGlobal(themeStyles)
140
- }
141
- injectGlobal(conf.reset)
142
- }
143
- return conf
144
- }
145
-
146
- export const applyCSS = (styles, options = UPDATE_OPTIONS) => {
147
- injectGlobal(styles)
148
- }
149
-
150
- export const updateVars = (config, options = UPDATE_OPTIONS) => {
151
- const scope = options.scopeSelector || ':root'
152
- const themeScope = scope === ':root' ? ':root:not([data-theme])' : `${scope}:not([data-theme])`
153
- injectGlobal({ [scope]: config.CSS_VARS })
154
- if (config.CSS_MEDIA_VARS) {
155
- const themeStyles = {}
156
- for (const key in config.CSS_MEDIA_VARS) {
157
- if (key.startsWith('@media')) {
158
- themeStyles[key] = { [themeScope]: config.CSS_MEDIA_VARS[key] }
159
- } else {
160
- themeStyles[key] = config.CSS_MEDIA_VARS[key]
161
- }
162
- }
163
- injectGlobal(themeStyles)
164
- }
165
- }
166
-
167
- export const changeGlobalTheme = (newTheme, targetConfig) => {
168
- return _changeGlobalTheme(newTheme, targetConfig)
169
- }
170
-
171
- export const setClass = (props, options = UPDATE_OPTIONS) => {} // setClassname(props, css)
172
-
package/src/options.js DELETED
@@ -1,35 +0,0 @@
1
- 'use strict'
2
-
3
- import { defaultDefine } from './define.js'
4
-
5
- export const DESIGN_SYSTEM_OPTIONS = {
6
- useReset: true,
7
- useVariable: true,
8
- useIconSprite: true,
9
- useSvgSprite: true,
10
- useDocumentTheme: true,
11
- useDefaultIcons: true,
12
- useFontImport: true,
13
- useDefaultConfig: true
14
- }
15
-
16
- export const ROUTER_OPTIONS = {
17
- initRouter: true,
18
- popState: true,
19
- injectRouterInLinkComponent: true
20
- }
21
-
22
- export const DEFAULT_CONTEXT = {
23
- ...DESIGN_SYSTEM_OPTIONS,
24
- router: ROUTER_OPTIONS
25
- }
26
-
27
- export const CREATE_OPTIONS = {
28
- state: {},
29
- pages: {},
30
- components: {},
31
- router: ROUTER_OPTIONS,
32
- define: defaultDefine
33
- }
34
-
35
- export default CREATE_OPTIONS