@dfosco/storyboard-core 1.21.0 → 1.22.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dfosco/storyboard-core",
3
- "version": "1.21.0",
3
+ "version": "1.22.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,9 +11,11 @@ import { getAllParams } from './session.js'
11
11
  import { isHideMode, getAllShadows } from './hideMode.js'
12
12
  import { subscribeToHash } from './hashSubscribe.js'
13
13
  import { subscribeToStorage } from './localStorage.js'
14
+ import { syncFlagBodyClasses } from './featureFlags.js'
14
15
 
15
16
  const PREFIX = 'sb-'
16
17
  const SCENE_PREFIX = 'sb-scene--'
18
+ const FF_PREFIX = 'sb-ff-'
17
19
 
18
20
  /**
19
21
  * Sanitize a string for use in a CSS class name.
@@ -41,13 +43,13 @@ function overrideClass(key, value) {
41
43
  }
42
44
 
43
45
  /**
44
- * Get all current sb- classes on body (excluding scene classes).
46
+ * Get all current sb- classes on body (excluding scene and feature-flag classes).
45
47
  * @returns {Set<string>}
46
48
  */
47
49
  function getCurrentOverrideClasses() {
48
50
  const classes = new Set()
49
51
  for (const cls of document.body.classList) {
50
- if (cls.startsWith(PREFIX) && !cls.startsWith(SCENE_PREFIX)) {
52
+ if (cls.startsWith(PREFIX) && !cls.startsWith(SCENE_PREFIX) && !cls.startsWith(FF_PREFIX)) {
51
53
  classes.add(cls)
52
54
  }
53
55
  }
@@ -108,8 +110,10 @@ export function setSceneClass(name) {
108
110
  */
109
111
  export function installBodyClassSync() {
110
112
  syncOverrideClasses()
111
- const unsubHash = subscribeToHash(syncOverrideClasses)
112
- const unsubStorage = subscribeToStorage(syncOverrideClasses)
113
+ syncFlagBodyClasses()
114
+ const sync = () => { syncOverrideClasses(); syncFlagBodyClasses() }
115
+ const unsubHash = subscribeToHash(sync)
116
+ const unsubStorage = subscribeToStorage(sync)
113
117
  return () => {
114
118
  unsubHash()
115
119
  unsubStorage()
@@ -15,23 +15,42 @@ import { getParam, setParam, removeParam, getAllParams } from './session.js'
15
15
  import { getLocal, setLocal, removeLocal, getAllLocal } from './localStorage.js'
16
16
 
17
17
  const FLAG_PREFIX = 'flag.'
18
+ const BODY_CLASS_PREFIX = 'sb-ff-'
18
19
 
19
20
  /** Module-level storage for config defaults */
20
21
  let _defaults = {}
21
22
 
23
+ /**
24
+ * Sync body classes for active feature flags.
25
+ * Adds `sb-ff-{name}` for every flag that resolves to true,
26
+ * removes it for every flag that resolves to false.
27
+ */
28
+ export function syncFlagBodyClasses() {
29
+ if (typeof document === 'undefined') return
30
+ for (const key of Object.keys(_defaults)) {
31
+ const cls = BODY_CLASS_PREFIX + key
32
+ if (getFlag(key)) {
33
+ document.body.classList.add(cls)
34
+ } else {
35
+ document.body.classList.remove(cls)
36
+ }
37
+ }
38
+ }
39
+
22
40
  /**
23
41
  * Initialize the feature flag system with config defaults.
24
- * Seeds localStorage with defaults (doesn't overwrite existing values).
42
+ * Syncs localStorage with config defaults on every call.
25
43
  * @param {Record<string, boolean>} defaults - Flag key → default value
26
44
  */
27
45
  export function initFeatureFlags(defaults = {}) {
28
46
  _defaults = { ...defaults }
29
- // Seed localStorage with defaults (don't overwrite existing)
47
+ // Sync localStorage with config defaults always overwrite so config
48
+ // changes take effect. User overrides live in the URL hash, which is
49
+ // checked first by getFlag(), so this is safe.
30
50
  for (const [key, value] of Object.entries(_defaults)) {
31
- if (getLocal(FLAG_PREFIX + key) === null) {
32
- setLocal(FLAG_PREFIX + key, String(value))
33
- }
51
+ setLocal(FLAG_PREFIX + key, String(value))
34
52
  }
53
+ syncFlagBodyClasses()
35
54
  }
36
55
 
37
56
  /**
@@ -59,6 +78,7 @@ export function getFlag(key) {
59
78
  */
60
79
  export function setFlag(key, value) {
61
80
  setParam(FLAG_PREFIX + key, String(value))
81
+ syncFlagBodyClasses()
62
82
  }
63
83
 
64
84
  /**
@@ -101,6 +121,7 @@ export function resetFlags() {
101
121
  removeLocal(localKey)
102
122
  }
103
123
  }
124
+ syncFlagBodyClasses()
104
125
  }
105
126
 
106
127
  /**
package/src/index.js CHANGED
@@ -38,7 +38,7 @@ export { mountSceneDebug } from './sceneDebug.js'
38
38
  export { hash, resolveSceneRoute, getSceneMeta } from './viewfinder.js'
39
39
 
40
40
  // Feature flags
41
- export { initFeatureFlags, getFlag, setFlag, toggleFlag, getAllFlags, resetFlags, getFlagKeys } from './featureFlags.js'
41
+ export { initFeatureFlags, getFlag, setFlag, toggleFlag, getAllFlags, resetFlags, getFlagKeys, syncFlagBodyClasses } from './featureFlags.js'
42
42
 
43
43
  // Plugin configuration
44
44
  export { initPlugins, isPluginEnabled, getPluginsConfig } from './plugins.js'