|
| 1 | +# Design Builder |
| 2 | + |
| 3 | +Complete documentation for the Design Builder runtime and component-level customization tool. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The Design Builder runtime has two execution modes in the same entry file: |
| 8 | + |
| 9 | +1. Full page mode (route: /design-builder) |
| 10 | +2. Component page mode (global docs pages with customize assets loaded) |
| 11 | + |
| 12 | +Entry file: |
| 13 | +- source/design-builder/index.ts |
| 14 | + |
| 15 | +Styles: |
| 16 | +- source/design-builder/design-builder.scss |
| 17 | + |
| 18 | +Control rendering helpers: |
| 19 | +- source/design-builder/controls.ts |
| 20 | + |
| 21 | +Global token/preset storage helpers (full page mode): |
| 22 | +- source/design-builder/storage.ts |
| 23 | + |
| 24 | +## Mode 1: Full page Design Builder |
| 25 | + |
| 26 | +### Activation |
| 27 | + |
| 28 | +Full page mode starts when the DOM contains: |
| 29 | +- [data-design-builder] |
| 30 | + |
| 31 | +The container must also include: |
| 32 | +- data-tokens="...json..." |
| 33 | + |
| 34 | +Template source: |
| 35 | +- views/pages/design-builder.blade.php |
| 36 | + |
| 37 | +### Behavior |
| 38 | + |
| 39 | +- Renders categorized controls from source/data/design-tokens.json payload. |
| 40 | +- Applies token overrides directly on :root. |
| 41 | +- Persists overrides in localStorage. |
| 42 | +- Supports: |
| 43 | + - reset all |
| 44 | + - import/export JSON |
| 45 | + - presets (save/load/delete) |
| 46 | + - optional display of locked fields |
| 47 | + - draggable split between controls and preview |
| 48 | + |
| 49 | +### Storage keys (full page mode) |
| 50 | + |
| 51 | +From source/design-builder/storage.ts and source/design-builder/index.ts: |
| 52 | + |
| 53 | +- design-tokens-overrides |
| 54 | +- design-tokens-presets |
| 55 | +- design-tokens-active-preset |
| 56 | +- design-builder-split |
| 57 | + |
| 58 | +## Mode 2: Component-level customization |
| 59 | + |
| 60 | +### Activation |
| 61 | + |
| 62 | +Component mode starts when: |
| 63 | + |
| 64 | +1. No [data-design-builder] container is found, and |
| 65 | +2. window.styleguideCustomizeData exists, and |
| 66 | +3. window.styleguideDesignTokenLibrary exists and is valid |
| 67 | + |
| 68 | +Payloads are injected in: |
| 69 | +- views/layout/master.blade.php |
| 70 | + |
| 71 | +Payloads are produced by: |
| 72 | +- source/php/Customize/CustomizeAssets.php |
| 73 | + |
| 74 | +### Component discovery |
| 75 | + |
| 76 | +Targets are discovered by: |
| 77 | +- [data-component] |
| 78 | + |
| 79 | +Examples: |
| 80 | +- data-component="button" |
| 81 | +- data-component="typography" |
| 82 | + |
| 83 | +Component names are normalized to lowercase and c- prefix is removed. |
| 84 | + |
| 85 | +### Editable determination |
| 86 | + |
| 87 | +A component is editable when: |
| 88 | +- It appears in styleguideCustomizeData, and |
| 89 | +- It has declared tokens that can be matched against token library categories/settings. |
| 90 | + |
| 91 | +### Floating customizer panel |
| 92 | + |
| 93 | +Rendered as: |
| 94 | +- .db-component-tool |
| 95 | + |
| 96 | +Features: |
| 97 | +- Open/close panel |
| 98 | +- Select editable component |
| 99 | +- Reset selected component (current scope only) |
| 100 | +- Reset all components (all scopes) |
| 101 | +- Render controls for mapped token categories |
| 102 | + |
| 103 | +### UX behaviors on editable targets |
| 104 | + |
| 105 | +Editable targets get: |
| 106 | + |
| 107 | +- Hover affordance |
| 108 | +- Active selection highlight |
| 109 | +- Tooltip text |
| 110 | + - "Customize [Component Name]" |
| 111 | + - If scoped: "Customize [Component Name] ([scope])" |
| 112 | +- Link click prevention inside editable targets |
| 113 | + - Prevents accidental navigation while customizing |
| 114 | + |
| 115 | +## Scopes |
| 116 | + |
| 117 | +### Scope attribute |
| 118 | + |
| 119 | +Scoped behavior is enabled via: |
| 120 | +- data-scope="your-scope-name" |
| 121 | + |
| 122 | +Scope resolution is nearest ancestor based: |
| 123 | +- For a clicked/updated target, closest ancestor [data-scope] is used. |
| 124 | +- If no scope ancestor exists, runtime uses global scope. |
| 125 | + |
| 126 | +Internal global scope key: |
| 127 | +- __global__ |
| 128 | + |
| 129 | +Internal named scope key format: |
| 130 | +- scope:your-scope-name |
| 131 | + |
| 132 | +### Scope effect |
| 133 | + |
| 134 | +For component-level mode, token changes apply only to elements where: |
| 135 | + |
| 136 | +- data-component matches selected component, and |
| 137 | +- resolved scope key matches the active scope key |
| 138 | + |
| 139 | +This allows same component type to be customized differently per context. |
| 140 | + |
| 141 | +Example: |
| 142 | + |
| 143 | +- Typography inside Paper with data-scope="content-card" |
| 144 | +- Typography inside Hero with data-scope="hero" |
| 145 | + |
| 146 | +Changes in one scope do not affect the other. |
| 147 | + |
| 148 | +## Storage model (component-level mode) |
| 149 | + |
| 150 | +Storage key: |
| 151 | +- design-tokens-component-overrides |
| 152 | + |
| 153 | +Current shape: |
| 154 | + |
| 155 | +{ |
| 156 | + "__global__": { |
| 157 | + "button": { |
| 158 | + "--c-button--color--primary": "#0055aa" |
| 159 | + } |
| 160 | + }, |
| 161 | + "scope:content-card": { |
| 162 | + "typography": { |
| 163 | + "--c-typography--font-size-200": "1.125rem" |
| 164 | + } |
| 165 | + } |
| 166 | +} |
| 167 | + |
| 168 | +### Legacy migration |
| 169 | + |
| 170 | +Legacy unscoped saved data is still accepted. |
| 171 | +If old shape is detected (component -> variables), runtime migrates it in-memory to: |
| 172 | + |
| 173 | +- __global__ -> component -> variables |
| 174 | + |
| 175 | +and continues with scoped model. |
| 176 | + |
| 177 | +## Data contracts |
| 178 | + |
| 179 | +### styleguideCustomizeData |
| 180 | + |
| 181 | +Source file generated at project root: |
| 182 | +- component-design-tokens.json |
| 183 | + |
| 184 | +Injected as: |
| 185 | +- window.styleguideCustomizeData |
| 186 | + |
| 187 | +Contains per-component metadata, including token names used to map editable controls. |
| 188 | + |
| 189 | +### styleguideDesignTokenLibrary |
| 190 | + |
| 191 | +Source file: |
| 192 | +- source/data/design-tokens.json |
| 193 | + |
| 194 | +Injected as: |
| 195 | +- window.styleguideDesignTokenLibrary |
| 196 | + |
| 197 | +Contains categories and settings used to render controls. |
| 198 | + |
| 199 | +### Important |
| 200 | + |
| 201 | +Component-level mode is DOM payload driven. |
| 202 | +No fetch fallback is used for token library in current implementation. |
| 203 | + |
| 204 | +## Token mapping logic in component mode |
| 205 | + |
| 206 | +For selected component "button" and token "color--primary": |
| 207 | + |
| 208 | +- Token variable from library (base): --color--primary |
| 209 | +- Localized variable applied to component target: --c-button--color--primary |
| 210 | + |
| 211 | +Rendered controls are grouped by token category from token library. |
| 212 | + |
| 213 | +## Server integration |
| 214 | + |
| 215 | +CustomizeAssets::get() returns: |
| 216 | + |
| 217 | +- script |
| 218 | +- style |
| 219 | +- data |
| 220 | +- tokenLibrary |
| 221 | + |
| 222 | +References: |
| 223 | +- source/php/Customize/CustomizeAssets.php |
| 224 | +- source/php/Tests/CustomizeAssetsTest.php |
| 225 | + |
| 226 | +## Styling notes |
| 227 | + |
| 228 | +Component-level tool and target styles live in: |
| 229 | +- source/design-builder/design-builder.scss |
| 230 | + |
| 231 | +Relevant class groups: |
| 232 | + |
| 233 | +- .db-component-tool* |
| 234 | +- .db-component-target |
| 235 | +- .db-component-target--active |
| 236 | + |
| 237 | +## Development workflow |
| 238 | + |
| 239 | +Typical commands: |
| 240 | + |
| 241 | +- npm run tokens |
| 242 | +- npm run watch |
| 243 | +- npm run build |
| 244 | + |
| 245 | +Build generates: |
| 246 | + |
| 247 | +- assets/dist/js/design-builder.js |
| 248 | +- assets/dist/css/design-builder.css |
| 249 | + |
| 250 | +## Adding or extending functionality |
| 251 | + |
| 252 | +### Add new token control behavior |
| 253 | + |
| 254 | +- Update control model and renderers in source/design-builder/controls.ts |
| 255 | +- Ensure source/data/design-tokens.json has correct type/options metadata |
| 256 | + |
| 257 | +### Add new customizable component |
| 258 | + |
| 259 | +- Ensure component has data-component in rendered markup |
| 260 | +- Ensure component exists in component-design-tokens.json |
| 261 | +- Ensure referenced tokens exist in source/data/design-tokens.json |
| 262 | + |
| 263 | +### Add scoped example context |
| 264 | + |
| 265 | +Wrap region with: |
| 266 | + |
| 267 | +- data-scope="my-scope" |
| 268 | + |
| 269 | +Any data-component targets inside that region become scope-bound for apply/reset. |
| 270 | + |
| 271 | +## Troubleshooting |
| 272 | + |
| 273 | +### Component panel does not show |
| 274 | + |
| 275 | +Check: |
| 276 | + |
| 277 | +- customize assets script/style loaded in layout |
| 278 | +- window.styleguideCustomizeData exists |
| 279 | +- window.styleguideDesignTokenLibrary exists |
| 280 | +- page has at least one editable [data-component] |
| 281 | + |
| 282 | +### Component not selectable |
| 283 | + |
| 284 | +Check: |
| 285 | + |
| 286 | +- data-component value matches component key or slug normalization |
| 287 | +- Component has token list in component-design-tokens.json |
| 288 | +- Tokens are present in design token library categories/settings |
| 289 | + |
| 290 | +### Setting does not apply |
| 291 | + |
| 292 | +Check: |
| 293 | + |
| 294 | +- Selected target scope context matches expected data-scope |
| 295 | +- Variable exists for component token mapping |
| 296 | +- Component CSS consumes localized variable (for example --c-button--...) |
| 297 | + |
| 298 | +### Nested components select wrong target |
| 299 | + |
| 300 | +Current behavior chooses clicked target and stops propagation. |
| 301 | +If selection still feels wrong, verify nested markup and where data-component is placed. |
| 302 | + |
| 303 | +## Current limitations |
| 304 | + |
| 305 | +- Scope picker UI is not present; scope is inferred from selected target. |
| 306 | +- Component dropdown is component-first, scope retained from active target when possible. |
| 307 | +- Component-level mode focuses on direct editable targets marked with data-component. |
| 308 | + |
| 309 | +## Suggested future improvements |
| 310 | + |
| 311 | +- Add explicit scope selector in panel |
| 312 | +- Add breadcrumb for selected target path (component + scope) |
| 313 | +- Add per-scope export/import |
| 314 | +- Add optional keyboard navigation for target picking |
0 commit comments