@sitecore-feaas/clientside 0.1.56 → 0.2.1

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.
Files changed (98) hide show
  1. package/README.md +559 -56
  2. package/build/components/FEAASComponent.js +2 -2
  3. package/build/components/FEAASComponent.js.map +1 -1
  4. package/build/components/FEAASElement.js +408 -37
  5. package/build/components/FEAASElement.js.map +1 -1
  6. package/build/components/FEAASLoader.js +2 -2
  7. package/build/components/FEAASLoader.js.map +1 -1
  8. package/build/components/FEAASReactElement.js +47 -0
  9. package/build/components/FEAASReactElement.js.map +1 -0
  10. package/build/components/FEAASStylesheet.js +2 -2
  11. package/build/components/FEAASStylesheet.js.map +1 -1
  12. package/build/headless.js +4 -3
  13. package/build/headless.js.map +1 -1
  14. package/build/ui/FEAASContext.js +14 -5
  15. package/build/ui/FEAASContext.js.map +1 -1
  16. package/build/ui/FEAASEditor.js +2 -2
  17. package/build/ui/FEAASEditor.js.map +1 -1
  18. package/build/ui/FEAASExternal.js +66 -23
  19. package/build/ui/FEAASExternal.js.map +1 -1
  20. package/build/ui/FEAASPicker.js +3 -2
  21. package/build/ui/FEAASPicker.js.map +1 -1
  22. package/dist/browser/headless.cjs +5 -5
  23. package/dist/browser/headless.cjs.map +4 -4
  24. package/dist/browser/headless.esm.js +5 -5
  25. package/dist/browser/headless.esm.js.map +1 -1
  26. package/dist/browser/index.cjs +7 -7
  27. package/dist/browser/index.cjs.map +4 -4
  28. package/dist/browser/index.esm.js +7 -7
  29. package/dist/browser/index.esm.js.map +1 -1
  30. package/dist/browser/react.cjs +6 -6
  31. package/dist/browser/react.cjs.map +4 -4
  32. package/dist/browser/react.esm.js +6 -6
  33. package/dist/browser/react.esm.js.map +1 -1
  34. package/dist/node/headless.cjs +3 -3
  35. package/dist/node/headless.cjs.map +4 -4
  36. package/dist/node/headless.esm.js +2 -2
  37. package/dist/node/headless.esm.js.map +4 -4
  38. package/dist/node/index.cjs +4 -4
  39. package/dist/node/index.cjs.map +4 -4
  40. package/dist/node/index.esm.js +3 -3
  41. package/dist/node/index.esm.js.map +4 -4
  42. package/dist/node/react.cjs +4 -4
  43. package/dist/node/react.cjs.map +4 -4
  44. package/dist/node/react.esm.js +4 -4
  45. package/dist/node/react.esm.js.map +4 -4
  46. package/headless.cjs +3 -3
  47. package/headless.cjs.map +4 -4
  48. package/headless.js +3 -3
  49. package/headless.js.map +4 -4
  50. package/package.json +10 -2
  51. package/react.cjs +6 -6
  52. package/react.cjs.map +4 -4
  53. package/react.js +6 -6
  54. package/react.js.map +4 -4
  55. package/scripts/test-setup.ts +1 -0
  56. package/src/components/FEAASComponent.tsx +4 -4
  57. package/src/components/FEAASElement.tsx +467 -42
  58. package/src/components/FEAASLoader.tsx +2 -2
  59. package/src/components/FEAASReactElement.tsx +61 -0
  60. package/src/components/FEAASStylesheet.tsx +3 -3
  61. package/src/headless.ts +5 -4
  62. package/src/ui/FEAASContext.tsx +16 -7
  63. package/src/ui/FEAASEditor.tsx +7 -7
  64. package/src/ui/FEAASExternal.tsx +77 -23
  65. package/src/ui/FEAASPicker.tsx +4 -3
  66. package/src/ui/tsconfig.json +1 -1
  67. package/test/FEAASBase.test.tsx +2 -2
  68. package/test/FEAASComponent.test.tsx +3 -1
  69. package/test/FEAASContext.test.tsx +206 -29
  70. package/test/FEAASPicker.test.tsx +4 -2
  71. package/types/components/FEAASComponent.d.ts +3 -3
  72. package/types/components/FEAASComponent.d.ts.map +1 -1
  73. package/types/components/FEAASElement.d.ts +292 -23
  74. package/types/components/FEAASElement.d.ts.map +1 -1
  75. package/types/components/FEAASLoader.d.ts +2 -2
  76. package/types/components/FEAASLoader.d.ts.map +1 -1
  77. package/types/components/FEAASReactElement.d.ts +30 -0
  78. package/types/components/FEAASReactElement.d.ts.map +1 -0
  79. package/types/components/FEAASStylesheet.d.ts +3 -3
  80. package/types/components/FEAASStylesheet.d.ts.map +1 -1
  81. package/types/headless.d.ts +4 -3
  82. package/types/headless.d.ts.map +1 -1
  83. package/types/tsbuildinfo +1 -1
  84. package/types/ui/FEAASContext.d.ts +8 -7
  85. package/types/ui/FEAASContext.d.ts.map +1 -1
  86. package/types/ui/FEAASEditor.d.ts +6 -6
  87. package/types/ui/FEAASEditor.d.ts.map +1 -1
  88. package/types/ui/FEAASExternal.d.ts +8 -10
  89. package/types/ui/FEAASExternal.d.ts.map +1 -1
  90. package/types/ui/FEAASPicker.d.ts +7 -6
  91. package/types/ui/FEAASPicker.d.ts.map +1 -1
  92. package/types/ui/tsbuildinfo +1 -0
  93. package/build/components/FEAASBase.js +0 -416
  94. package/build/components/FEAASBase.js.map +0 -1
  95. package/src/components/FEAASBase.tsx +0 -485
  96. package/types/components/FEAASBase.d.ts +0 -299
  97. package/types/components/FEAASBase.d.ts.map +0 -1
  98. package/types/tsbuildinfo_ui +0 -1
package/README.md CHANGED
@@ -7,7 +7,7 @@ data.
7
7
 
8
8
  - Renders component content and returns React/DOM element
9
9
  - Populates attributes and text valeus with mapped data
10
- - Repeats nodes mapped to collections
10
+ - Repeats nodes mapped to collections
11
11
  - Updates previously rendered component for new data
12
12
  - Provides both react and javascript revisions of Clientside
13
13
  - (optional) Fetches of component from the cloud
@@ -19,16 +19,27 @@ data.
19
19
 
20
20
  ## Usage
21
21
 
22
- ### React:
22
+ ### React
23
+
24
+ ```jsx
25
+ import * as FEAAS from '@sitecore-feaas/clientside/react'
26
+
27
+ // fetch component from the cloud
28
+ return (
29
+ <FEAAS.Component component='...' version='...' revision='published' cdn='...' data={{ user: { name: 'John' } }} />
30
+ )
31
+ ```
32
+
33
+ ### Web component
23
34
 
24
35
  ```javascript
25
36
  import * as FEAAS '@sitecore-feaas/clientside';
26
37
 
27
38
  // provide html template directly
28
- <feaas-component template={`<p>Hello <var data-path="user.name" /></p>`} data={JSON.stringify({user: {name: "World"})}} />
39
+ <feaas-component template={`<p>Hello <var data-path="user.name" /></p>`} data={JSON.stringify({user: {name: "John"}})} />
29
40
 
30
41
  // fetch component from the cloud
31
- <feaas-component component="..." version="..." revision="production" cdn="..." data={JSON.stringify({user: {name: "World"}})} />
42
+ <feaas-component component="..." version="..." revision="published" cdn="..." data={JSON.stringify({user: {name: "John"}})} />
32
43
  ```
33
44
 
34
45
  ### JS Dom
@@ -47,7 +58,7 @@ const element = FEAAS.renderComponent({
47
58
  version: '...',
48
59
  revision: 'production',
49
60
  cdn: '...',
50
- data: { user: { name: 'World' } }
61
+ data: { user: { name: 'John' } }
51
62
  })
52
63
 
53
64
  // inject element into DOM
@@ -57,7 +68,7 @@ document.body.appendChild(element)
57
68
  // update element with new data
58
69
  FEAAS.renderComponent(
59
70
  {
60
- data: { user: { name: 'Universe' } }
71
+ data: { user: { name: 'Bill' } }
61
72
  },
62
73
  element
63
74
  )
@@ -66,7 +77,7 @@ FEAAS.renderComponent(
66
77
  const element = FEAAS.renderComponent(
67
78
  {
68
79
  template: `<p>Hello <var data-path="user.name" /></p>`,
69
- data: { user: { name: 'World' } }
80
+ data: { user: { name: 'Bill' } }
70
81
  }
71
82
  //, element // optionally provide target element here a
72
83
  )
@@ -77,7 +88,7 @@ document.body.appendChild(element)
77
88
  // update data in the element
78
89
  FEAAS.renderComponent(
79
90
  {
80
- data: { user: { name: 'Universe' } }
91
+ data: { user: { name: 'Sarah' } }
81
92
  },
82
93
  element
83
94
  )
@@ -97,9 +108,9 @@ before it has finished loading, parsing and executing js.
97
108
 
98
109
  ```HTML
99
110
  <!-- Use id=`feaas-stylesheet` for Clientside to deal with invalidation -->
100
- <link rel='stylesheet' id='feaas-stylesheet' href='https://components.sitecore.cloud/styles/:tenant_id/published.css' />
111
+ <link rel='stylesheet' id='feaas-stylesheet' href='https://feaas.blob.core.windows.net.cloud/styles/:tenant_id/published.css' />
101
112
  <!-- Include Clientside on the page OR as npm import inside your own code -->
102
- <script src="//feaas-components.sitecore.cloud/clientside/latest.min.js"></script>
113
+ <script type="module" src="https://feaasstatic.blob.core.windows.net/packages/clientside/latest/browser/index.esm.js"></script>
103
114
  ```
104
115
 
105
116
  ### Linking stylesheet in Clientside app
@@ -117,38 +128,50 @@ import * as FEAAS from '@sitecore-feaas/clientside'
117
128
  ### Entrypoints
118
129
 
119
130
  There are three different entrypoints for clientside: UI, React and Headless
120
- 1. The main entrypoint `@sitecore-feaas/clientside` targets the UI package which references frontend
121
- from components monorepo. This includes both the core functionality and some ui components like
122
- the pickers and the embedded editor
131
+
132
+ 1. The main entrypoint `@sitecore-feaas/clientside` targets the UI package which references frontend from components
133
+ monorepo. This includes both the core functionality and some ui components like the pickers and the embedded editor
123
134
  2. The `@sitecore-feaas/clientside/react` entrypoint targets the React package which is similar to the main entrypoint
124
- but also includes some components that use React as a dependency like external react components.
125
- 3. The `@sitecore-feaas/clientside/headless` entrypoint targets the Headless package which includes just the
126
- core functionality of clientside without any dependencies on frontend or react.
135
+ but also includes some components that use React as a dependency like external react components.
136
+ 3. The `@sitecore-feaas/clientside/headless` entrypoint targets the Headless package which includes just the core
137
+ functionality of clientside without any dependencies on frontend or react.
138
+
127
139
  ---
128
- **NOTE 1:** React library is not included in any clientside package, we assume that it is already installed in the container that uses the `@sitecore-feaas/clientside/react` entrypoint. We mark React library as external in scripts/build.js
129
140
 
130
- **NOTE 2:** UI has its own tsconfig that includes references to both `/frontend` and `/clientside`. Clientside main tsconfig excludes `/ui` avoiding circular imports
141
+ **NOTE 1:** React library is not included in any clientside package, we assume that it is already installed in the
142
+ container that uses the `@sitecore-feaas/clientside/react` entrypoint. We mark React library as external in
143
+ scripts/build.js
144
+
145
+ **NOTE 2:** UI has its own tsconfig that includes references to both `/frontend` and `/clientside`. Clientside main
146
+ tsconfig excludes `/ui` avoiding circular imports
131
147
 
132
148
  ---
133
149
 
134
150
  ### Bring your own code components
135
151
 
136
152
  You can use Components clientside SDK to register and render your own code components to your FEAAS components.
137
- Registration steps:
153
+ Registration steps:
154
+
138
155
  - Install and import the Components React SDK to your App
139
- ```bash
156
+
157
+ ```bash
140
158
  npm install @sitecore-feaas/clientside
141
159
  ```
160
+
142
161
  ```typescript
143
- import * as FEAAS from "@sitecore-feaas/clientside/react"
162
+ import * as FEAAS from '@sitecore-feaas/clientside/react'
144
163
  ```
145
- - Register your component via
164
+
165
+ - Register your component via
166
+
146
167
  ```typescript
147
168
  registerComponent(component, options)
148
169
  ```
149
- `component` is the actual react component, `options` (optional) is a JSON Schema representation
150
- of your component options containing the components props and other options. If not provided, the component will be registered as a prop-less component.
151
- An example of `schema` is provided below:
170
+
171
+ `component` is the actual react component, `options` (optional) is a JSON Schema representation of your component
172
+ options containing the components props and other options. If not provided, the component will be registered as a
173
+ prop-less component. An example of `schema` is provided below:
174
+
152
175
  ```typescript
153
176
  const options = {
154
177
  name: 'My example component',
@@ -170,6 +193,24 @@ const options = {
170
193
  type: 'string',
171
194
  title: 'Telephone',
172
195
  minLength: 10
196
+ },
197
+ bold: {
198
+ type: 'boolean',
199
+ title: 'Show text in bold weight'
200
+ }
201
+ },
202
+ ui: {
203
+ firstName: {
204
+ 'ui:autofocus': true,
205
+ 'ui:placeholder': 'Write your first name'
206
+ },
207
+ telephone: {
208
+ 'ui:options': {
209
+ inputType: 'tel'
210
+ }
211
+ },
212
+ bold: {
213
+ 'ui:widget': 'radio'
173
214
  }
174
215
  }
175
216
  }
@@ -177,34 +218,496 @@ const options = {
177
218
 
178
219
  Options may contain any of the bellow items:
179
220
 
180
- **Name**<br/>
181
- Type: string<br/>
182
- Required: no<br/>
183
- Description: Name of your Component as it will be shown to the user. If not provided, will be function name in title case.
184
-
185
- **Description**<br/>
186
- Type: string<br/>
187
- Required: no<br/>
188
- Description: Describe your Component and anything a user should know when using it.
189
-
190
- **Thumbnail**<br/>
191
- Type: url<br/>
192
- Required: no<br/>
193
- Description: A URL of a thumbnail image to be displayed in the Builder. Should have some dimension guidelines.
194
-
195
- **Group**<br/>
196
- Type: string<br/>
197
- Required: no<br/>
198
- Description: Used to group related Components together in the UI. E.g. Typography
199
-
200
- **Properties**<br/>
201
- Type: JSONSchema object<br/>
202
- Required: no<br/>
203
- Description: Inputs (Props) to be provided by the user when embedding this Component.
204
-
205
- **Required**<br/>
206
- Type: String Array<br/>
207
- Required: no<br/>
208
- Description: Array of keys from Inputs (Props) that should be required
209
-
210
- _We use React JSONSchema Form to generate a form for the component properties. You can read more about React JSONSchema Form here:_ https://react-jsonschema-form.readthedocs.io
221
+ **Name**<br/> Type: string<br/> Required: no<br/> Description: Name of your Component as it will be shown to the user.
222
+ If not provided, will be function name in title case.
223
+
224
+ **Description**<br/> Type: string<br/> Required: no<br/> Description: Describe your Component and anything a user should
225
+ know when using it.
226
+
227
+ **Thumbnail**<br/> Type: url<br/> Required: no<br/> Description: A URL of a thumbnail image to be displayed in the
228
+ Builder. Should have some dimension guidelines.
229
+
230
+ **Group**<br/> Type: string<br/> Required: no<br/> Description: Used to group related Components together in the UI.
231
+ E.g. Typography
232
+
233
+ **Properties**<br/> Type: JSONSchema object<br/> Required: no<br/> Description: Inputs (Props) to be provided by the
234
+ user when embedding this Component.
235
+
236
+ **Required**<br/> Type: String Array<br/> Required: no<br/> Description: Array of keys from Inputs (Props) that should
237
+ be required
238
+
239
+ **UI**<br/> Type: JSONSchema object<br/> Required: no<br/> Description: Any UI specific configuration for the inputs form rendering in the builder
240
+
241
+ _We use React JSONSchema Form to generate a form for the component properties. You can read more about React JSONSchema
242
+ Form here:_ https://react-jsonschema-form.readthedocs.io
243
+
244
+ # Component anatomy
245
+
246
+ - It’s possible to edit/swap component without changing embedding HTML code (everything happens on CDN)
247
+ - User does not need to decide upfront if component will ever need to be edited in line, the only requirement is to
248
+ provide a unique id in embedding code
249
+ - Editing disables component FEAAS updates, but it’s possible to unfork component to return to original state/behavior
250
+
251
+ ##Embedding
252
+
253
+ Components/versions are designed to be embedded on external pages. FEAAS approach allows then components to be updated
254
+ without changing the pages. There're multiple pathways for editing component:
255
+
256
+ - Editing component inside Builder
257
+ - Editing component externally (Pages or on the website)
258
+
259
+ In all of these cases the main requirement, is that no code is updated in place of embedding. The only time Components
260
+ is able to influence the embed site is initially by providing the code to copy and paste for the user. In case user
261
+ writes their embedding code by hand, there's no control at all. The system is designed to not require any changes.
262
+
263
+ ```HTML
264
+ <feaas-component library="..." component="..." version="..." revision="production" data="{}" />
265
+ ```
266
+
267
+ ## Generated HTML
268
+
269
+ Components builder allows designer to create HTML templates and then style them. The elements inside components are the
270
+ usual suspects one can find in any web design editor - headings, paragraphs, pictures, containers. In addition to those,
271
+ the data model offers embedding of raw HTML islands and nesting components into each other. That last feature can be
272
+ used by designers to split big components into small, but it is also used internally to implement responsive/forked
273
+ components.
274
+
275
+ ```HTML
276
+ <!-- A component with a single element is wrapped into a root element -->
277
+ <div class="-feaas">
278
+ <section>
279
+ <h1>Hello world</h1>
280
+ </section>
281
+ </div>
282
+
283
+ <!-- A component embedding another component version explicitly -->
284
+ <div class="-feaas">
285
+ <section>
286
+ <feaas-component component="component-id" version="version-id"></feaas-component>
287
+ </section>
288
+ </div>
289
+ ```
290
+
291
+ ## Responsive components
292
+
293
+ Each component has multiple versions, which make up a set of mutually exclusive respresentations of the same data.
294
+ Versions can be handily used to create a set of designs to be used for different screen sizes. In addition to embedding
295
+ a specific version of a component to the page, it is possible to embed a set of responsive components instead that
296
+ choose one of the versions based on window or container size.
297
+
298
+ Resposive component is a special aggregated version that analyzes all component versions and their breakpoints, and
299
+ ensure that for every breakpoint there's a fitting version. Responsive component version bundles all its versions into
300
+ one HTML file which hides its parts based on current css driven by the stylesheet. This approach allows weak binding to
301
+ definition of breakpoints, so breakpoint definitions can be changed after components are embedded.
302
+
303
+ Every time any of the versions in component is updated, responsive version is regenerated automatically.
304
+
305
+ ```HTML
306
+ <!-- A responsive component that embeds version based on window or container size -->
307
+ <div class="-feaas">
308
+ <div class="-breakpoint--xs -breakpoint--sm">
309
+ <section>
310
+ <h1>Small version</h1>
311
+ </section>
312
+ </div>
313
+ <div class="-breakpoint--md -breakpoint--lg -breakpoint--xl">
314
+ <section>
315
+ <h1>Large version</h1>
316
+ </section>
317
+ </div>
318
+ </div>
319
+ ```
320
+
321
+ ## Component CDN storage
322
+
323
+ ### Editing in builder
324
+
325
+ The simpliest case is when component was changed inside the builder. The backend simply republishes the file on CDN, so
326
+ the changes are visible the next time page is reloaded. If the previous version of the component file was cached in the
327
+ browser, the Clientside code will check if version of CDN file is more recent than the cached one, and will forcefully
328
+ reload the file and re-render it. The caching is implemented using a custom variation of stale-while-invalidate strategy
329
+ found in service workers. The difference is that the rendered cached component gets swapped upon recieving update
330
+ ensuring that there's no latency penalty to be paid for cache busting.
331
+
332
+ In case of builder publishing the changed component, all instances of that component on all sites and pages will see the
333
+ change, with exception of "forked" components (see below).
334
+
335
+ ### Editing in place
336
+
337
+ At the time of embedding a component may be assigned a special instance attribute which determines unique identifier of
338
+ embedded component instance. That allows that component to be editable in place. Initially it will share its version
339
+ content, styles and settings with all the other instances of the same component. However after embedding user may decide
340
+ to edit the contents, styles or datasources of the component instance using an inline version of Component Builder
341
+ (inside Pages or on the website).
342
+
343
+ Further changes to the original component (staged or published) will stop affecting such edited component instance.
344
+ Change history of a that component instance becomes divergent from the history of the original, creating a metaphorical
345
+ fork in the road for the component. Editing component instance inline "forks" it.
346
+
347
+ A forked version of a component has simplified publishing flow: Changes to the forked component automatically become
348
+ visible in Pages and on the website (as if they were both staged and published). After initial integration, this will be
349
+ improved to make forked component a subject to Pages publishing lifecycle, acting exactly as other XM/SXA component
350
+ would.
351
+
352
+ It is possible to "unfork" component, resetting its changes and reverting to the shared state. It will both reset the
353
+ state, and will re-enable component receieve updates when the original is updated.
354
+
355
+ Technical difficulty of forking components lies in the hard requirement of being able to do forking and unforking
356
+ without the need for changing the embed code/configuration. Which makes the most intuitive sense in the use case of
357
+ editing component on the final HTML page, that lacks the mechanisms to communicate with backend to save the changes. It
358
+ could be that the component is even used in the context of static HTML that does not have any underlying CMS, so
359
+ changing the embedding code would require updating the remote file or template (perhaps even requiring a full release of
360
+ the app).
361
+
362
+ When the component is displayed on the page, it needs to fetch its HTML contents fron CDN. HTML files are put on the CDN
363
+ using predictable name, like: /components/:component_id/:version_id/:status.html. If a component has instance attribute
364
+ set, the clientside code will fetch a second url from CDN in parallel: /instances/:instance.html, thus determining if
365
+ that instance of a component was forked or not.
366
+
367
+ If the second request had 404 Not Found status, the original component definition returned by the first request would be
368
+ displayed. In that case the instance is considered not forked, so any staged/published changes to that component will be
369
+ reflected as usual.
370
+
371
+ If the second request was successful, then that forked version of a component will be displayed instead of the shared
372
+ one. Further updates to shared state will be shadowed by the customization until the component is unforked. But the
373
+ forked component remains editable.
374
+
375
+ ### Versioning in UI
376
+
377
+ Bringing up the Editor on the forked component, displays Fork status instead of Draft. Staged and Published statuses can
378
+ be still previewed, showing the current upstream version of the component, allowing to visualize the changes that
379
+ happened to the original since forking. It will allow merging upstream changes to a fork, using CKEditor's operational
380
+ transformations feature. That requires computing diff of a fork against its original version, and then resolving it
381
+ against diff of upstream changes. OT ensures conflict-free merging of changes.
382
+
383
+ In addition to that, this same UI allows unforking, by reverting to either staged or published version.
384
+
385
+ ### Swapping component
386
+
387
+ The most tricky case of in-line editing comes in case of swapping a component or version to another. Reference to the
388
+ component and the version is a part of embed code. In Pages we can simply update the component rendering parameters. But
389
+ for static HTML pages updating the embedding code is not an option.
390
+
391
+ Swapping a component in this case works as if instance of a component was forked, and its whole contents was replaced
392
+ with the contents of another component. The forked component HTML file on CDN, just like all other HTML files contains
393
+ metadata that indicate which component and version it relates to, thus allowing the UI to properly visualize upstream
394
+ staged/published states of the new component.
395
+
396
+ The limitation of this approach is that a swapped content will not reflect updates made to its definition. It could be
397
+ alleviated in the future by making yet another request to CDN to check for changes, but in the first implementation of
398
+ in-place editing this is not going to be addressed
399
+
400
+ # Component styling
401
+
402
+ Style guides is a tool for editing css stylesheets. It offers designers the ability to predefine reusable chunks of
403
+ style for individual elements and their compositions. The resulting styles are then packaged as a static CSS file
404
+ available for Component Builder, Page Builder, or regular HTML webpages.
405
+
406
+ Style guide can be invoked from within component builder too, allowing the builders to create one-off "instance" styles.
407
+ In that case the resulting style that is only applicable to a specific element, is placed directly into HTML document.
408
+
409
+ It is possible to use the styles as a part of BYOC component as well.
410
+
411
+ ## Using elements and rules
412
+
413
+ Each element type like button, card, section has a dedicated class making it recieve the style. Designers can create
414
+ their own element types, but some are built in. FEAAS class name starts with dash.
415
+
416
+ ### Text elements
417
+
418
+ - `-paragraph` or `<p>`
419
+ - `-heading1` or `<h1>`
420
+ - `-heading2` or `<h2>`
421
+ - `-heading3` or `<h3>`
422
+ - `-heading4` or `<h4>`
423
+ - `-heading5` or `<h5>`
424
+ - `-heading6` or `<h6>`
425
+
426
+ ###Block elements
427
+
428
+ - `-card`
429
+ - `-section` or `<section>`
430
+ - `-blockquote` or `<blockquote>`
431
+ - `-block--media`
432
+ - `-block--my-custom-type` - custom block type
433
+
434
+ ### Inline elements
435
+
436
+ - `-button` or `<button>`
437
+ - `-link` or `<a>`
438
+ - `-inline--badge`
439
+ - `-inline--my-custom-type` - custom inline type
440
+
441
+ Applying the above classes inside an container with `-feaas -theme--name` classes will apply default theme styles for
442
+ each. It is possible to use specific element styles defined in style guides overriding theme defaults with extra
443
+ `--name` at the end:
444
+
445
+ `-button--primary` will apply `Primary` style of a button, and `-inline--badge--important` will apply `Important` style
446
+ of the badge
447
+
448
+ ````HTML
449
+
450
+ <section class="-feaas -theme--default">
451
+ <!-- Button element with "Primary" style, overriding theme styles -->
452
+ <button class="-button--primary">
453
+ Default primary button
454
+ </button>
455
+
456
+ <!-- "Primary" button with "chunky-typography" override -->
457
+ <button class="-button--primary -typography--chunky">
458
+ Chunky primary button
459
+ </button>
460
+
461
+ <!--
462
+ "Primary" button with "instance" style created in builder. Style is bundled inline as a part of the html output.
463
+ User can choose to start with reusable rule and "customize it". In that case the instance style is linked with
464
+ the original. Removing the className belonging to instance style clears up the instance style from the document.
465
+ In this case, only the *typography* rule of the button was altered, so others (like spacing or decoration) still
466
+ retain the link to shared styles.
467
+ -->
468
+ <style>
469
+ .-typography--chunky[data-instance-id="unique"][class][class][class] {
470
+ font-size: 32px;
471
+ line-height: inherit;
472
+ /* ...goes on, lists all properties exhaustively
473
+ to completely override button's own default typography */
474
+ }
475
+ </style>
476
+ <button data-instance-id="unique" class="-button--primary -typography--chunky">
477
+ Customized chunky primary button
478
+ </button>
479
+
480
+ </section>
481
+
482
+ ```
483
+
484
+ ## Using themes
485
+
486
+ Style guides embraces controlled style cascade to allow parent elements to provide default styles for its children
487
+ elements. Children have flexibility to redefine any aspect of those inherited styles. [#Specificity-Layers] is used to
488
+ ensure styles do not clash.
489
+
490
+ Besides convenience of editing, this approach is essential to handle rich data mapping. HTML content coming from the CMS
491
+ needs to be styled "implicitly" through applying a theme to its parent element. This way paragraphs, headings, links and
492
+ pictures will have predictable styled look.
493
+
494
+ NOTE: composites feature is not yet exposed in the style guides UI.
495
+
496
+ It is also possible to specify theme styles. Supposed there's a theme button style with id `deadbeef`:
497
+
498
+ * `-feaas -theme--default -use--deadbeef` will make all buttons use that style inside the elementg
499
+ * `-button -deadbeef` - will make specific button use this style
500
+
501
+ ```HTML
502
+
503
+ <section class="-feaas -theme--dark">
504
+ <div class="-section">
505
+ <!-- Card will pick up dark style from its theme -->
506
+ <div class="-card">
507
+ <div>
508
+ <!-- div element with default button styles as prescribed by theme -->
509
+ <div class="-button">
510
+ Yes
511
+ </div>
512
+ <!-- button with default styles as prescribed by theme -->
513
+ <button>
514
+ Yes
515
+ </button>
516
+ <!-- dark style button with only typography rule overriden -->
517
+ <button class="-typography--chunky">
518
+ No
519
+ </button>
520
+ </div>
521
+
522
+ <!-- static elements potentially coming from CMS via data mapping -->
523
+ <h2>Test<h2>
524
+ <p>Test<p>
525
+ <ul>
526
+ <li>Hey</li>
527
+ <li>Yo</li>
528
+ </ul>
529
+ <img src="..." />
530
+ <p>Test<p>
531
+ </div>
532
+
533
+ <!-- dark theme style for a card is overriden by buttons own style -->
534
+ <div class="-card--promo">
535
+ <!-- button is dark: not affected by card parent style override -->
536
+ <button></button>
537
+ </div>
538
+
539
+
540
+ <!-- FUTURE: theme applied to card, overriding dark theme of section -->
541
+ <div class="-card -theme--light -subtheme">
542
+ <!-- button is light: affected by card parent style override -->
543
+ <button></button>
544
+ </div>
545
+
546
+ <!-- composite elements have fully resolved class names -->
547
+ <div class="-block--accordion">
548
+ <!-- composite elements part are marked with
549
+ data-role attribute for easier handling of bubbled events -->
550
+ <button data-role="next">Forward</button>
551
+ <div data-role="list">
552
+ <div class="-card">
553
+ <img>
554
+ </div>
555
+ <div class="-card">
556
+ <img>
557
+ </div>
558
+ </div>
559
+ <button data-role="prev">Back</button>
560
+ </div>
561
+ </div>
562
+ </div>
563
+
564
+ ````
565
+
566
+ ## Advanced: Specificity layers
567
+
568
+ Style guides use limited cascading, and five levels of style hierarchy of styles (Resets, Themes, Elements, Rules and
569
+ Instance styles). In addition styles have to be order-independent to ensure the easiest integration with pages or apps.
570
+ These requirements call for very particular approach to selectors, in order for all styles to co-exist predictably.
571
+
572
+ Ideally this problem has to be solved through the use of Layers feature of CSS Level 4, but it's barely supported
573
+ anywhere. It is possible to emulate it for the needs of style guides, by spreading out each layers in specificity
574
+ values. To increase specificity of a selector, we employ repetition of `[class]` attribute selector. Below you can find
575
+ specs for all of the layers and the expected specificity values.
576
+
577
+ - Calculator: https://specificity.keegan.st/
578
+ - More info: https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
579
+
580
+ ### CSS resets
581
+
582
+ Components need some basic styles reset in order to establish style baseline.
583
+
584
+ ```CSS
585
+ /*
586
+ Resets: (0.1.0)
587
+ lowest priority
588
+ */
589
+ [class*="-theme--"] * {
590
+
591
+ }
592
+ ```
593
+
594
+ ### Themes
595
+
596
+ Themes are composite styles that descend to the children. Children can then completely override them if necessary.
597
+ Themes are applied to the component root, or to a card if theme allows pairing
598
+
599
+ ```CSS
600
+ /* Default styles for elements within a theme (1.1.1)(1.1.2)/(1.2.0)/(1.2.1)/(1.3.0) */
601
+ .-theme--cool:not(#_) h1 {}
602
+ .-theme--cool:not(#_) h1 a {}
603
+ .-theme--cool:not(#_) .-card {}
604
+ .-theme--cool:not(#_) .-block--accordion h1 {}
605
+ .-theme--cool:not(#_) .-block--accordion [role="accordion-button"] {}
606
+
607
+ /* Customized styles for elements within a theme (1.1.3)(1.1.4)/(1.2.2)/(1.2.3)/(1.3.2) */
608
+ .-use--deadbeef:not(#_):not(x):not(x) h1 {}
609
+ .-use--deadbeef:not(#_):not(x):not(x) h1 a{}
610
+ .-use--deadbeef:not(#_):not(x):not(x) .-card {}
611
+ .-use--deadbeef:not(#_):not(x):not(x) .-card h1 {}
612
+ .-use--deadbeef:not(#_):not(x):not(x):not(x):not(x) .-block--accordion [role="accordion-button"] {}
613
+
614
+ /* FUTURE: Nested theme override (1.2.4)/(1.2.5)/(1.3.3)/(1.3.4)/(1.4.3) */
615
+ .-theme--nested.-subtheme:not(x#_):not(x):not(x):not(x) h1 {}
616
+ .-theme--nested.-subtheme:not(x#_):not(x):not(x):not(x) h1 a {}
617
+ .-theme--nested.-subtheme:not(x#_):not(x):not(x):not(x) .-button {}
618
+ .-theme--nested.-subtheme:not(x#_):not(x):not(x):not(x) .-button h1 {}
619
+ .-theme--nested.-subtheme:not(x#_):not(x):not(x):not(x) .-block--accordion [role="accordion-button"] {}
620
+ ```
621
+
622
+ ### Elements
623
+
624
+ Elements are created with a choice of default reusable rules (typography, decoration, spacing, etc.). All styles are
625
+ merged together into a single definition of element class, allowing other reusable rules applied on top to override the
626
+ defaults. So only a single class needs to be applied for all default styles to take effect.
627
+
628
+ One benefit of that approach is that the designers may change the defaults for elements retroactively. For example, they
629
+ may change "Primary button" to have "Bold typography" by default. This take effect in all places where that button style
630
+ is used and which dont have typography rule override.
631
+
632
+ Some elements consist of parts (carousel has buttons, accordion has title & details, etc). Creating a style for
633
+ composite element is similar to theme, it adds default choice of buttons and styles. Later user can change an element
634
+ style, or only an aspect of it.
635
+
636
+ ```CSS
637
+
638
+ /* Explicit element styles (1.5.0)/(1.6.0) */
639
+ .-card--cool:not(#_._._._._) {}
640
+ .-card--cool:not(#_._._._._) [data-role="prev"] {}
641
+ /* Explicit combo styles (1.5.1)/(1.6.1) */
642
+ .-theme--dark .-card--cool.--deadbeef:not(x#_._._) {}
643
+ .-theme--dark .-card--cool.--deadbeef:not(x#_._._) [role="accordion-button"] {}
644
+ /* Reusable rules need to override theme & element styles (1.7.0) */
645
+ .-typography--rule:not(#_._._._._._._) {}
646
+ .-typography--rule:not(#_._._._._._._)[data-instance-id="unique-element"] {}
647
+ ```
648
+
649
+ #### Reusable rules
650
+
651
+ Reusable rules represent different aspects of styling: Typography, decoration, fill, etc. Creating element consists of
652
+ choosing applicable and default rules. Allowing more than one rule per category for an element, makes it possible for
653
+ designer to choose alternatives when placing that element on a page or component.
654
+
655
+ ```CSS
656
+ /* Reusable rules need to override theme & element styles (1.7.0)/(1.8.0) */
657
+ .-typography--rule:not(#_._._._._._._) {}
658
+ .-typography--rule:not(#_._._._._._._)[data-instance-id="unique-element"] {}
659
+ ```
660
+
661
+ ## Properties
662
+
663
+ Style guides are meant to simplify the CSS creation, instead of being simply visual way to edit css. To remove
664
+ redundancy or complexity certain changes or additions had to be done:
665
+
666
+ ### Spacing
667
+
668
+ Margins are pretty tricky in CSS (issues like margin-collapsing or auto value, and redundancy with padding can be
669
+ confusing). Style guides offer no direct manipilation of margin, and instead offer simplier options, either layout gap,
670
+ or paragraph spacing. To achieve that, the system uses a shared
671
+ [https://css-tricks.com/using-custom-property-stacks-to-tame-the-cascade/](variable stack) to ensure that value
672
+ customizations and redefinitions do not rely on specificity.
673
+
674
+ ```CSS
675
+ /* Specificity does not matter for these definitions */
676
+ .element {
677
+ marign-top: var(---typography--paragraph-spacing, var(---self--row-gap, 0px));
678
+ marign-left: var(---self--column-gap, 0px);
679
+ }
680
+ ```
681
+
682
+ - **Gap** - Space between elements in layout (columns, block elements), defined on the parent to control spacing between
683
+ its children.
684
+
685
+ ```CSS
686
+ /* Specificity increase only affects variable assignment */
687
+ .-layout--horizontal:not(#_._._._._._._) > :nth-child(1n+3) {
688
+ ---spacing--row-gap: 10px;
689
+ }
690
+ ```
691
+
692
+ - **Gap override** (codename) - Child element can override the gap set by its parent. Used in builder. Similar to _
693
+ align-self_ and _justify-self_ logic of flexbox. Independent from direction of layout.
694
+
695
+ ```CSS
696
+ /* Even though element style has lower priority than layout rule,
697
+ the ---self-- family of variables can be redefined on element itself */
698
+ .-card--my-element:not(x#_._._._._) {
699
+ ---self--row-gap: 10px;
700
+ ---self--column-gap: 10px;
701
+ }
702
+ ```
703
+
704
+ - **Paragraph spacing** - like gap, but for text elements. Takes precedence over vertical gap. Because text elements can
705
+ not be direct children inside horizontal layouts, does not care about direction.
706
+
707
+ ```CSS
708
+ /* Specificity is not important here, as the variable is not inherited*/
709
+ .element {
710
+ ---typography--paragraph-spacing: 10px;
711
+ }
712
+
713
+ ```