@lion/ui 0.0.1 → 0.0.3

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 (279) hide show
  1. package/components/core/test/SlotMixin.test.js +28 -21
  2. package/components/drawer/src/LionDrawer.js +217 -0
  3. package/components/drawer/src/drawerStyle.js +59 -0
  4. package/components/drawer/test/lion-drawer.test.js +109 -0
  5. package/components/localize/src/number/parseNumber.js +15 -36
  6. package/components/localize/test/number/parseNumber.test.js +3 -12
  7. package/custom-elements.json +743 -0
  8. package/dist-types/components/drawer/src/LionDrawer.d.ts +67 -0
  9. package/dist-types/components/drawer/src/LionDrawer.d.ts.map +1 -0
  10. package/dist-types/components/drawer/src/drawerStyle.d.ts +2 -0
  11. package/dist-types/components/drawer/src/drawerStyle.d.ts.map +1 -0
  12. package/dist-types/components/drawer/test/lion-drawer.test.d.ts +3 -0
  13. package/dist-types/components/drawer/test/lion-drawer.test.d.ts.map +1 -0
  14. package/dist-types/components/localize/src/number/parseNumber.d.ts.map +1 -1
  15. package/dist-types/exports/define/lion-drawer.d.ts +2 -0
  16. package/dist-types/exports/define/lion-drawer.d.ts.map +1 -0
  17. package/dist-types/exports/drawer.d.ts +2 -0
  18. package/dist-types/exports/drawer.d.ts.map +1 -0
  19. package/dist-types/tsconfig.tsbuildinfo +1 -1
  20. package/docs/components/accordion/index.md +3 -0
  21. package/docs/components/accordion/overview.md +129 -0
  22. package/docs/components/accordion/reference.md +47 -0
  23. package/docs/components/accordion/use-cases.md +252 -0
  24. package/docs/components/button/examples.md +30 -0
  25. package/docs/components/button/index.md +3 -0
  26. package/docs/components/button/overview.md +30 -0
  27. package/docs/components/button/src/icon.svg.js +5 -0
  28. package/docs/components/button/use-cases.md +106 -0
  29. package/docs/components/calendar/index.md +3 -0
  30. package/docs/components/calendar/overview.md +49 -0
  31. package/docs/components/calendar/use-cases.md +192 -0
  32. package/docs/components/checkbox-group/index.md +3 -0
  33. package/docs/components/checkbox-group/overview.md +40 -0
  34. package/docs/components/checkbox-group/use-cases.md +256 -0
  35. package/docs/components/collapsible/assets/CustomCollapsible.js +113 -0
  36. package/docs/components/collapsible/assets/applyDemoCollapsibleStyles.js +37 -0
  37. package/docs/components/collapsible/examples.md +83 -0
  38. package/docs/components/collapsible/index.md +3 -0
  39. package/docs/components/collapsible/overview.md +39 -0
  40. package/docs/components/collapsible/use-cases.md +79 -0
  41. package/docs/components/combobox/examples.md +153 -0
  42. package/docs/components/combobox/index.md +3 -0
  43. package/docs/components/combobox/overview.md +51 -0
  44. package/docs/components/combobox/src/LinkMixin.js +60 -0
  45. package/docs/components/combobox/src/demo-selection-display.js +191 -0
  46. package/docs/components/combobox/src/gh-combobox/gh-button.js +69 -0
  47. package/docs/components/combobox/src/gh-combobox/gh-combobox.js +508 -0
  48. package/docs/components/combobox/src/google-combobox/assets/google-clear-icon.js +9 -0
  49. package/docs/components/combobox/src/google-combobox/assets/google-search-icon.js +9 -0
  50. package/docs/components/combobox/src/google-combobox/assets/google-voice-search-icon.js +19 -0
  51. package/docs/components/combobox/src/google-combobox/assets/googlelogo_color_272x92dp.png +0 -0
  52. package/docs/components/combobox/src/google-combobox/google-combobox.js +460 -0
  53. package/docs/components/combobox/src/lazyRender.js +29 -0
  54. package/docs/components/combobox/src/levenshtein.js +95 -0
  55. package/docs/components/combobox/src/md-combobox/MdFieldMixin.js +341 -0
  56. package/docs/components/combobox/src/md-combobox/md-combobox.js +89 -0
  57. package/docs/components/combobox/src/md-combobox/md-input.js +5 -0
  58. package/docs/components/combobox/src/md-combobox/style/load-roboto.js +6 -0
  59. package/docs/components/combobox/src/md-combobox/style/md-ripple.js +81 -0
  60. package/docs/components/combobox/src/wa-combobox/wa-combobox.js +368 -0
  61. package/docs/components/combobox/use-cases.md +377 -0
  62. package/docs/components/dialog/index.md +3 -0
  63. package/docs/components/dialog/overview.md +63 -0
  64. package/docs/components/dialog/src/demo-dialog-style.js +3 -0
  65. package/docs/components/dialog/src/demoStyle.js +39 -0
  66. package/docs/components/dialog/src/slots-dialog-content.js +32 -0
  67. package/docs/components/dialog/src/styled-dialog-content.js +38 -0
  68. package/docs/components/dialog/use-cases.md +154 -0
  69. package/docs/components/drawer/index.md +3 -0
  70. package/docs/components/drawer/overview.md +68 -0
  71. package/docs/components/drawer/src/demoStyle.js +71 -0
  72. package/docs/components/drawer/use-cases.md +194 -0
  73. package/docs/components/fieldset/index.md +3 -0
  74. package/docs/components/fieldset/overview.md +49 -0
  75. package/docs/components/fieldset/use-cases.md +185 -0
  76. package/docs/components/form/index.md +3 -0
  77. package/docs/components/form/overview.md +43 -0
  78. package/docs/components/form/use-cases.md +72 -0
  79. package/docs/components/icon/assets/bugs/bug01.svg.js +2 -0
  80. package/docs/components/icon/assets/bugs/bug02.svg.js +2 -0
  81. package/docs/components/icon/assets/bugs/bug05.svg.js +2 -0
  82. package/docs/components/icon/assets/bugs/bug06.svg.js +2 -0
  83. package/docs/components/icon/assets/bugs/bug08.svg.js +2 -0
  84. package/docs/components/icon/assets/bugs/bug12.svg.js +2 -0
  85. package/docs/components/icon/assets/bugs/bug19.svg.js +2 -0
  86. package/docs/components/icon/assets/bugs/bug23.svg.js +2 -0
  87. package/docs/components/icon/assets/bugs/bug24.svg.js +2 -0
  88. package/docs/components/icon/assets/iconset-bugs.js +11 -0
  89. package/docs/components/icon/assets/iconset-misc.js +3 -0
  90. package/docs/components/icon/assets/iconset-space.js +31 -0
  91. package/docs/components/icon/assets/misc/arrowLeft.svg.js +6 -0
  92. package/docs/components/icon/assets/space/aliens-spaceship.svg.js +2 -0
  93. package/docs/components/icon/assets/space/meteor.svg.js +2 -0
  94. package/docs/components/icon/assets/space/moon-flag.svg.js +2 -0
  95. package/docs/components/icon/assets/space/moon.svg.js +2 -0
  96. package/docs/components/icon/assets/space/night.svg.js +2 -0
  97. package/docs/components/icon/assets/space/orbit.svg.js +2 -0
  98. package/docs/components/icon/assets/space/planet.svg.js +2 -0
  99. package/docs/components/icon/assets/space/robot.svg.js +2 -0
  100. package/docs/components/icon/assets/space/rocket.svg.js +2 -0
  101. package/docs/components/icon/assets/space/satellite.svg.js +2 -0
  102. package/docs/components/icon/assets/space/signal.svg.js +2 -0
  103. package/docs/components/icon/assets/space/space-helmet.svg.js +2 -0
  104. package/docs/components/icon/assets/space/sun.svg.js +2 -0
  105. package/docs/components/icon/assets/space/telescope.svg.js +2 -0
  106. package/docs/components/icon/index.md +3 -0
  107. package/docs/components/icon/overview.md +40 -0
  108. package/docs/components/icon/use-cases.md +93 -0
  109. package/docs/components/index.md +7 -0
  110. package/docs/components/input/index.md +3 -0
  111. package/docs/components/input/overview.md +36 -0
  112. package/docs/components/input/use-cases.md +77 -0
  113. package/docs/components/input-amount/index.md +3 -0
  114. package/docs/components/input-amount/overview.md +49 -0
  115. package/docs/components/input-amount/use-cases.md +122 -0
  116. package/docs/components/input-date/index.md +3 -0
  117. package/docs/components/input-date/overview.md +39 -0
  118. package/docs/components/input-date/use-cases.md +83 -0
  119. package/docs/components/input-datepicker/index.md +3 -0
  120. package/docs/components/input-datepicker/overview.md +42 -0
  121. package/docs/components/input-datepicker/use-cases.md +78 -0
  122. package/docs/components/input-email/index.md +3 -0
  123. package/docs/components/input-email/overview.md +32 -0
  124. package/docs/components/input-email/use-cases.md +48 -0
  125. package/docs/components/input-iban/index.md +3 -0
  126. package/docs/components/input-iban/overview.md +37 -0
  127. package/docs/components/input-iban/use-cases.md +102 -0
  128. package/docs/components/input-range/index.md +3 -0
  129. package/docs/components/input-range/overview.md +34 -0
  130. package/docs/components/input-range/use-cases.md +108 -0
  131. package/docs/components/input-stepper/index.md +3 -0
  132. package/docs/components/input-stepper/overview.md +36 -0
  133. package/docs/components/input-stepper/use-cases.md +41 -0
  134. package/docs/components/input-tel/index.md +3 -0
  135. package/docs/components/input-tel/overview.md +62 -0
  136. package/docs/components/input-tel/src/h-region-code-table.js +109 -0
  137. package/docs/components/input-tel/use-cases.md +307 -0
  138. package/docs/components/input-tel-dropdown/examples.md +32 -0
  139. package/docs/components/input-tel-dropdown/index.md +3 -0
  140. package/docs/components/input-tel-dropdown/overview.md +38 -0
  141. package/docs/components/input-tel-dropdown/src/intl-input-tel-dropdown.js +127 -0
  142. package/docs/components/input-tel-dropdown/use-cases.md +159 -0
  143. package/docs/components/listbox/index.md +3 -0
  144. package/docs/components/listbox/overview.md +42 -0
  145. package/docs/components/listbox/src/listboxData.js +65 -0
  146. package/docs/components/listbox/use-cases.md +147 -0
  147. package/docs/components/pagination/index.md +3 -0
  148. package/docs/components/pagination/overview.md +29 -0
  149. package/docs/components/pagination/use-cases.md +99 -0
  150. package/docs/components/progress-indicator/assets/my-determinate-progress-bar.js +30 -0
  151. package/docs/components/progress-indicator/assets/my-indeterminate-progress-spinner.js +55 -0
  152. package/docs/components/progress-indicator/examples.md +125 -0
  153. package/docs/components/progress-indicator/index.md +3 -0
  154. package/docs/components/progress-indicator/overview.md +36 -0
  155. package/docs/components/radio-group/index.md +3 -0
  156. package/docs/components/radio-group/overview.md +46 -0
  157. package/docs/components/radio-group/use-cases.md +140 -0
  158. package/docs/components/select/index.md +3 -0
  159. package/docs/components/select/overview.md +44 -0
  160. package/docs/components/select/use-cases.md +55 -0
  161. package/docs/components/select-rich/examples.md +31 -0
  162. package/docs/components/select-rich/index.md +3 -0
  163. package/docs/components/select-rich/overview.md +46 -0
  164. package/docs/components/select-rich/src/flagStyles.js +1250 -0
  165. package/docs/components/select-rich/src/flags.png +0 -0
  166. package/docs/components/select-rich/src/flags@2x.png +0 -0
  167. package/docs/components/select-rich/src/intl-select-rich.js +194 -0
  168. package/docs/components/select-rich/src/regionMetaList.js +1717 -0
  169. package/docs/components/select-rich/use-cases.md +370 -0
  170. package/docs/components/steps/index.md +3 -0
  171. package/docs/components/steps/overview.md +63 -0
  172. package/docs/components/steps/use-cases.md +163 -0
  173. package/docs/components/switch/index.md +3 -0
  174. package/docs/components/switch/overview.md +75 -0
  175. package/docs/components/switch/reference.md +39 -0
  176. package/docs/components/switch/use-cases.md +76 -0
  177. package/docs/components/tabs/examples.md +23 -0
  178. package/docs/components/tabs/index.md +3 -0
  179. package/docs/components/tabs/overview.md +48 -0
  180. package/docs/components/tabs/src/lea-tab-panel.js +24 -0
  181. package/docs/components/tabs/src/lea-tab.js +45 -0
  182. package/docs/components/tabs/src/lea-tabs.js +28 -0
  183. package/docs/components/tabs/use-cases.md +219 -0
  184. package/docs/components/textarea/index.md +3 -0
  185. package/docs/components/textarea/overview.md +35 -0
  186. package/docs/components/textarea/use-cases.md +95 -0
  187. package/docs/components/tooltip/examples.md +39 -0
  188. package/docs/components/tooltip/index.md +3 -0
  189. package/docs/components/tooltip/overview.md +44 -0
  190. package/docs/components/tooltip/use-cases.md +208 -0
  191. package/docs/fundamentals/index.md +19 -0
  192. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/index.md +1 -0
  193. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/overview.md +233 -0
  194. package/docs/fundamentals/node-tools/index.md +1 -0
  195. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +68 -0
  196. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +111 -0
  197. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +69 -0
  198. package/docs/fundamentals/node-tools/providence-analytics/assets/_mermaid.svg.js +1202 -0
  199. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +22 -0
  200. package/docs/fundamentals/node-tools/providence-analytics/index.md +1 -0
  201. package/docs/fundamentals/node-tools/providence-analytics/overview.md +192 -0
  202. package/docs/fundamentals/node-tools/publish-docs/index.md +1 -0
  203. package/docs/fundamentals/node-tools/publish-docs/overview.md +136 -0
  204. package/docs/fundamentals/node-tools/remark-extend/index.md +1 -0
  205. package/docs/fundamentals/node-tools/remark-extend/overview.md +274 -0
  206. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/index.md +1 -0
  207. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +285 -0
  208. package/docs/fundamentals/rationales/TypeScript.md +18 -0
  209. package/docs/fundamentals/rationales/index.md +1 -0
  210. package/docs/fundamentals/rationales/side-effects.md +203 -0
  211. package/docs/fundamentals/rationales/versioning.md +35 -0
  212. package/docs/fundamentals/systems/core/index.md +3 -0
  213. package/docs/fundamentals/systems/core/overview.md +85 -0
  214. package/docs/fundamentals/systems/form/assets/FormatMixinDiagram-1.svg +1 -0
  215. package/docs/fundamentals/systems/form/assets/FormatMixinDiagram-2.svg +1 -0
  216. package/docs/fundamentals/systems/form/assets/FormatMixinDiagram-3.svg +84 -0
  217. package/docs/fundamentals/systems/form/assets/h-output.js +155 -0
  218. package/docs/fundamentals/systems/form/formatting-and-parsing.md +245 -0
  219. package/docs/fundamentals/systems/form/index.md +3 -0
  220. package/docs/fundamentals/systems/form/interaction-states.md +177 -0
  221. package/docs/fundamentals/systems/form/model-value.md +35 -0
  222. package/docs/fundamentals/systems/form/overview.md +82 -0
  223. package/docs/fundamentals/systems/form/styling.md +101 -0
  224. package/docs/fundamentals/systems/form/use-cases.md +156 -0
  225. package/docs/fundamentals/systems/form/validate.md +929 -0
  226. package/docs/fundamentals/systems/icon/index.md +3 -0
  227. package/docs/fundamentals/systems/icon/overview.md +124 -0
  228. package/docs/fundamentals/systems/index.md +1 -0
  229. package/docs/fundamentals/systems/localize/assets/all-locales.js +437 -0
  230. package/docs/fundamentals/systems/localize/assets/en-AU.js +6 -0
  231. package/docs/fundamentals/systems/localize/assets/en-GB.js +6 -0
  232. package/docs/fundamentals/systems/localize/assets/en-US.js +6 -0
  233. package/docs/fundamentals/systems/localize/assets/en.js +4 -0
  234. package/docs/fundamentals/systems/localize/assets/nl-BE.js +6 -0
  235. package/docs/fundamentals/systems/localize/assets/nl-NL.js +6 -0
  236. package/docs/fundamentals/systems/localize/assets/nl.js +4 -0
  237. package/docs/fundamentals/systems/localize/dates.md +195 -0
  238. package/docs/fundamentals/systems/localize/index.md +3 -0
  239. package/docs/fundamentals/systems/localize/numbers.md +217 -0
  240. package/docs/fundamentals/systems/localize/overview.md +48 -0
  241. package/docs/fundamentals/systems/localize/rationale.md +62 -0
  242. package/docs/fundamentals/systems/localize/text.md +125 -0
  243. package/docs/fundamentals/systems/localize/use-cases.md +319 -0
  244. package/docs/fundamentals/systems/overlays/assets/applyDemoOverlayStyles.js +22 -0
  245. package/docs/fundamentals/systems/overlays/assets/demo-overlay-backdrop.js +48 -0
  246. package/docs/fundamentals/systems/overlays/assets/demo-overlay-system.js +42 -0
  247. package/docs/fundamentals/systems/overlays/assets/umbrella-form.js +133 -0
  248. package/docs/fundamentals/systems/overlays/configuration.md +453 -0
  249. package/docs/fundamentals/systems/overlays/form-integration.md +65 -0
  250. package/docs/fundamentals/systems/overlays/index.md +3 -0
  251. package/docs/fundamentals/systems/overlays/overview.md +118 -0
  252. package/docs/fundamentals/systems/overlays/rationale.md +232 -0
  253. package/docs/fundamentals/systems/overlays/scope.md +176 -0
  254. package/docs/fundamentals/systems/overlays/use-cases.md +699 -0
  255. package/docs/fundamentals/tools/ajax/assets/naga.json +9 -0
  256. package/docs/fundamentals/tools/ajax/assets/pabu.json +9 -0
  257. package/docs/fundamentals/tools/ajax/index.md +3 -0
  258. package/docs/fundamentals/tools/ajax/overview.md +128 -0
  259. package/docs/fundamentals/tools/ajax/use-cases.md +456 -0
  260. package/docs/fundamentals/tools/helpers/action-logger.md +165 -0
  261. package/docs/fundamentals/tools/helpers/index.md +3 -0
  262. package/docs/fundamentals/tools/helpers/overview.md +30 -0
  263. package/docs/fundamentals/tools/index.md +1 -0
  264. package/docs/fundamentals/tools/singleton-manager/index.md +3 -0
  265. package/docs/fundamentals/tools/singleton-manager/overview.md +304 -0
  266. package/docs/guides/how-to/create-a-custom-field.md +200 -0
  267. package/docs/guides/how-to/extend-a-native-input.md +66 -0
  268. package/docs/guides/how-to/get-started.md +77 -0
  269. package/docs/guides/how-to/index.md +1 -0
  270. package/docs/guides/index.md +34 -0
  271. package/docs/guides/principles/definitions-and-terms.md +41 -0
  272. package/docs/guides/principles/index.md +26 -0
  273. package/docs/guides/principles/scoped-elements.md +103 -0
  274. package/docs/guides/principles/styling.md +32 -0
  275. package/docs/guides/principles/subclasser-apis.md +28 -0
  276. package/docs/override.js +15 -0
  277. package/exports/define/lion-drawer.js +3 -0
  278. package/exports/drawer.js +1 -0
  279. package/package.json +2 -2
@@ -0,0 +1,9 @@
1
+ {
2
+ "id": "4",
3
+ "type": "Fire Ferret",
4
+ "name": "Pabu",
5
+ "skin": {
6
+ "type": "fur",
7
+ "color": "red"
8
+ }
9
+ }
@@ -0,0 +1,3 @@
1
+ # Tools >> Ajax ||20
2
+
3
+ -> go to Overview
@@ -0,0 +1,128 @@
1
+ # Tools >> Ajax >> Overview ||10
2
+
3
+ `Ajax` is a small wrapper around `fetch` which:
4
+
5
+ - Allows globally registering request and response interceptors
6
+ - Throws on 4xx and 5xx status codes
7
+ - Supports caching, so a request can be prevented from reaching to network, by returning the cached response.
8
+ - Supports JSON with `ajax.fetchJSON` by automatically serializing request body and deserializing response payload as JSON, and adding the correct Content-Type and Accept headers.
9
+ - Adds accept-language header to requests based on application language
10
+ - Adds XSRF header to request if the cookie is present
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm i --save @lion/ajax
16
+ ```
17
+
18
+ ### Relation to fetch
19
+
20
+ `Ajax` delegates all requests to fetch. `ajax.fetch` and `ajax.fetchJson` have the same function signature as `window.fetch`, you can use any online resource to learn more about fetch. [MDN](http://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) is a great start.
21
+
22
+ ## Ajax class options
23
+
24
+ | Property | Type | Default Value | Description |
25
+ | -------------------------------- | -------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
26
+ | addAcceptLanguage | boolean | `true` | Whether to add the Accept-Language header from the `data-localize-lang` document property |
27
+ | addCaching | boolean | `false` | Whether to add the cache interceptor and start storing responses in the cache, even if `cacheOptions.useCache` is `false` |
28
+ | xsrfCookieName | string | `"XSRF-TOKEN"` | The name for the Cross Site Request Forgery cookie |
29
+ | xsrfHeaderName | string | `"X-XSRF-TOKEN"` | The name for the Cross Site Request Forgery header |
30
+ | jsonPrefix | string | `""` | The prefix to add to add to responses for the `.fetchJson` functions |
31
+ | cacheOptions.useCache | boolean | `false` | Whether to use the default cache interceptors to cache requests |
32
+ | cacheOptions.getCacheIdentifier | function | a function returning the string `_default` | A function to determine the cache that should be used for each request; used to make sure responses for one session are not used in the next |
33
+ | cacheOptions.methods | string[] | `["get"]` | The HTTP methods to cache reponses for. Any other method will invalidate the cache for this request, see "Invalidating cache", below |
34
+ | cacheOptions.maxAge | number | `360000` | The time to keep a response in the cache before invalidating it automatically |
35
+ | cacheOptions.invalidateUrls | string[] | `undefined` | Urls to invalidate each time a method not in `cacheOptions.methods` is encountered, see "Invalidating cache", below |
36
+ | cacheOptions.invalidateUrlsRegex | regex | `undefined` | Regular expression matching urls to invalidate each time a method not in `cacheOptions.methods` is encountered, see "Invalidating cache", below |
37
+ | cacheOptions.requestIdFunction | function | a function returning the base url and serialized search parameters | Function to determine what defines a unique URL |
38
+ | cacheOptions.contentTypes | string[] | `undefined` | Whitelist of content types that will be stored to or retrieved from the cache |
39
+ | cacheOptions.maxResponseSize | number | `undefined` | The maximum response size in bytes that will be stored to or retrieved from the cache |
40
+ | cacheOptions.maxCacheSize | number | `undefined` | The maxiumum total size in bytes of the cache; when the cache gets larger it is truncated |
41
+
42
+ ## Usage
43
+
44
+ ```js script
45
+ import { ajax, createCacheInterceptors } from '@lion/ajax';
46
+
47
+ const getCacheIdentifier = () => {
48
+ let userId = localStorage.getItem('lion-ajax-cache-demo-user-id');
49
+ if (!userId) {
50
+ localStorage.setItem('lion-ajax-cache-demo-user-id', '1');
51
+ userId = '1';
52
+ }
53
+ return userId;
54
+ };
55
+
56
+ const TEN_MINUTES = 1000 * 60 * 10; // in milliseconds
57
+
58
+ const cacheOptions = {
59
+ useCache: true,
60
+ maxAge: TEN_MINUTES,
61
+ };
62
+
63
+ const [cacheRequestInterceptor, cacheResponseInterceptor] = createCacheInterceptors(
64
+ getCacheIdentifier,
65
+ cacheOptions,
66
+ );
67
+
68
+ ajax.addRequestInterceptor(cacheRequestInterceptor);
69
+ ajax.addResponseInterceptor(cacheResponseInterceptor);
70
+ ```
71
+
72
+ Or use a custom cache object and add the cache config to the constructor:
73
+
74
+ ```js
75
+ import { Ajax } from '@lion/ajax';
76
+
77
+ const storeButDontRetrieveByDefaultConfig = {
78
+ addCaching: true,
79
+ cacheOptions: {
80
+ getCacheIdentifier,
81
+ useCache: false,
82
+ maxAge: TEN_MINUTES,
83
+ },
84
+ };
85
+
86
+ const customAjax = new Ajax(storeButDontRetrieveByDefaultConfig);
87
+ ```
88
+
89
+ ### Invalidating the cache
90
+
91
+ Invalidating the cache, or cache busting, can be done in multiple ways:
92
+
93
+ - Going past the `maxAge` of the cache object
94
+ - Changing cache identifier (e.g. user session or active profile changes)
95
+ - Doing a non GET request to the cached endpoint
96
+ - Invalidates the cache of that endpoint
97
+ - Invalidates the cache of all other endpoints matching `invalidatesUrls` and `invalidateUrlsRegex`
98
+
99
+ ### Restricting what to cache
100
+
101
+ The library has a number of options available to restrict what should be cached. They include:
102
+
103
+ #### By content type
104
+
105
+ `cacheOptions.contentTypes`
106
+
107
+ If this option is set, it is interpreted as a whitelist for which content types to cache. The content types of a given
108
+ response is derived from its `Content-Type` header. If this option is set, responses that do not have a `Content-Type`
109
+ header are never added to or retrieved from the cache.
110
+
111
+ #### By response size
112
+
113
+ `cacheOptions.maxResponseSize`
114
+
115
+ This option sets a maximum size (in bytes) for a single response to be cached. The size of the response is determined first by looking
116
+ at the `Content-Length` header; if this header is not available, the response is inspected (through the `blob()` function)
117
+ and its size retrieved.
118
+
119
+ ### Limiting the cache size
120
+
121
+ `cacheOptions.maxCacheSize`
122
+
123
+ This option sets a maximum size (in bytes) for the whole cache. The size of a response is determined first by looking
124
+ at the `Content-Length` header; if this header is not available, the response is inspected (through the `blob()` function)
125
+ and its size retrieved.
126
+
127
+ If the cache grows larger than the `maxCacheSize` option, the cache is truncated according to a First-In-First-Out
128
+ (FIFO) algorithm that simply removes the oldest entries until the cache is smaller than `options.maxCacheSize`.
@@ -0,0 +1,456 @@
1
+ # Tools >> Ajax >> Use Cases ||20
2
+
3
+ ```js script
4
+ import { html } from '@mdjs/mdjs-preview';
5
+ import { renderLitAsNode } from '@lion/ui/helpers.js';
6
+ import { ajax, createCacheInterceptors } from '@lion/ajax';
7
+ import '@lion/ui/define-helpers/sb-action-logger.js';
8
+
9
+ const getCacheIdentifier = () => {
10
+ let userId = localStorage.getItem('lion-ajax-cache-demo-user-id');
11
+ if (!userId) {
12
+ localStorage.setItem('lion-ajax-cache-demo-user-id', '1');
13
+ userId = '1';
14
+ }
15
+ return userId;
16
+ };
17
+
18
+ const TEN_MINUTES = 1000 * 60 * 10; // in milliseconds
19
+
20
+ const cacheOptions = {
21
+ useCache: true,
22
+ maxAge: TEN_MINUTES,
23
+ };
24
+
25
+ const [cacheRequestInterceptor, cacheResponseInterceptor] = createCacheInterceptors(
26
+ getCacheIdentifier,
27
+ cacheOptions,
28
+ );
29
+
30
+ ajax.addRequestInterceptor(cacheRequestInterceptor);
31
+ ajax.addResponseInterceptor(cacheResponseInterceptor);
32
+ ```
33
+
34
+ ## GET request
35
+
36
+ ```js preview-story
37
+ export const getRequest = () => {
38
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
39
+
40
+ const fetchHandler = name => {
41
+ ajax
42
+ .fetch(`../assets/${name}.json`)
43
+ .then(response => response.json())
44
+ .then(result => {
45
+ actionLogger.log(JSON.stringify(result, null, 2));
46
+ });
47
+ };
48
+
49
+ return html`
50
+ <style>
51
+ sb-action-logger {
52
+ --sb-action-logger-max-height: 300px;
53
+ }
54
+ </style>
55
+ <button @click=${() => fetchHandler('pabu')}>Fetch Pabu</button>
56
+ <button @click=${() => fetchHandler('naga')}>Fetch Naga</button>
57
+ ${actionLogger}
58
+ `;
59
+ };
60
+ ```
61
+
62
+ ## POST request
63
+
64
+ ```js
65
+ import { ajax } from '@lion/ajax';
66
+
67
+ const response = await ajax.fetch('/api/users', {
68
+ method: 'POST',
69
+ body: JSON.stringify({ username: 'steve' }),
70
+ });
71
+
72
+ const newUser = await response.json();
73
+ ```
74
+
75
+ ### JSON requests
76
+
77
+ We usually deal with JSON requests and responses. `ajax.fetchJson` supports JSON by:
78
+
79
+ - Serializing request body as JSON
80
+ - Deserializing response payload as JSON
81
+ - Adding the correct Content-Type and Accept headers
82
+
83
+ > Note that, the result will have the Response object on `.response` property, and the parsed JSON will be available on `.body`.
84
+
85
+ ## GET JSON request
86
+
87
+ ```js preview-story
88
+ export const getJsonRequest = () => {
89
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
90
+
91
+ const fetchHandler = name => {
92
+ ajax.fetchJson(`../assets/${name}.json`).then(result => {
93
+ console.log(result.response);
94
+ actionLogger.log(JSON.stringify(result.body, null, 2));
95
+ });
96
+ };
97
+
98
+ return html`
99
+ <style>
100
+ sb-action-logger {
101
+ --sb-action-logger-max-height: 300px;
102
+ }
103
+ </style>
104
+ <button @click=${() => fetchHandler('pabu')}>Fetch Pabu</button>
105
+ <button @click=${() => fetchHandler('naga')}>Fetch Naga</button>
106
+ ${actionLogger}
107
+ `;
108
+ };
109
+ ```
110
+
111
+ ## POST JSON request
112
+
113
+ ```js
114
+ import { ajax } from '@lion/ajax';
115
+
116
+ const { response, body } = await ajax.fetchJson('/api/users', {
117
+ method: 'POST',
118
+ body: { username: 'steve' },
119
+ });
120
+ ```
121
+
122
+ ### Error handling
123
+
124
+ Different from fetch, `Ajax` throws when the server returns a 4xx or 5xx, returning the request and response:
125
+
126
+ ```js preview-story
127
+ export const errorHandling = () => {
128
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
129
+
130
+ const fetchHandler = async () => {
131
+ try {
132
+ const users = await ajax.fetchJson('/api/users');
133
+ } catch (error) {
134
+ if (error.response) {
135
+ if (error.response.status === 400) {
136
+ // handle a specific status code, for example 400 bad request
137
+ } else {
138
+ actionLogger.log(error);
139
+ }
140
+ } else {
141
+ // an error happened before receiving a response,
142
+ // Example: an incorrect request or network error
143
+ actionLogger.log(error);
144
+ }
145
+ }
146
+ };
147
+
148
+ return html`
149
+ <style>
150
+ sb-action-logger {
151
+ --sb-action-logger-max-height: 300px;
152
+ }
153
+ </style>
154
+ <button @click=${fetchHandler}>Fetch</button>
155
+ ${actionLogger}
156
+ `;
157
+ };
158
+ ```
159
+
160
+ ## Fetch Polyfill
161
+
162
+ For IE11 you will need a polyfill for fetch. You should add this on your top level layer, e.g. your application.
163
+
164
+ [This is the polyfill we recommend](https://github.com/github/fetch). It also has a [section for polyfilling AbortController](https://github.com/github/fetch#aborting-requests)
165
+
166
+ ## Ajax Caching Support
167
+
168
+ Ajax package provides in-memory cache support through interceptors. And cache interceptors can be added manually or by configuring the Ajax instance.
169
+
170
+ The cache request interceptor and cache response interceptor are designed to work together to support caching of network requests/responses.
171
+
172
+ > The **request interceptor** checks whether the response for this particular request is cached, and if so returns the cached response.
173
+ > And the **response interceptor** caches the response for this particular request.
174
+
175
+ ### Getting started
176
+
177
+ Consume the global `ajax` instance and add interceptors to it, using a cache configuration which is applied on application level. If a developer wants to add specifics to cache behaviour they have to provide a cache config per action (`get`, `post`, etc.) via `cacheOptions` field of local ajax config,
178
+ see examples below.
179
+
180
+ > **Note**: make sure to add the **interceptors** only **once**. This is usually done on app-level
181
+
182
+ ```js
183
+ import { ajax, createCacheInterceptors } from '@lion-web/ajax';
184
+
185
+ const globalCacheOptions = {
186
+ useCache: true,
187
+ maxAge: 1000 * 60 * 5, // 5 minutes
188
+ };
189
+
190
+ // Cache is removed each time an identifier changes,
191
+ // for instance when a current user is logged out
192
+ const getCacheIdentifier = () => getActiveProfile().profileId;
193
+
194
+ const [cacheRequestInterceptor, cacheResponseInterceptor] = createCacheInterceptors(
195
+ getCacheIdentifier,
196
+ globalCacheOptions,
197
+ );
198
+
199
+ ajax.addRequestInterceptor(cacheRequestInterceptor);
200
+ ajax.addResponseInterceptor(cacheResponseInterceptor);
201
+
202
+ const { response, body } = await ajax.fetchJson('/my-url');
203
+ ```
204
+
205
+ Alternatively, most often for sub-classers, you can extend or import `Ajax` yourself, and pass cacheOptions when instantiating the ajax.
206
+
207
+ ```js
208
+ import { Ajax } from '@lion/ajax';
209
+
210
+ export const ajax = new Ajax({
211
+ cacheOptions: {
212
+ useCache: true,
213
+ maxAge: 1000 * 60 * 5, // 5 minutes
214
+ getCacheIdentifier: () => getActiveProfile().profileId,
215
+ },
216
+ });
217
+ ```
218
+
219
+ ### Ajax cache example
220
+
221
+ > Let's assume that we have a user session, for this demo purposes we already created an identifier function for this and set the cache interceptors.
222
+
223
+ We can see if a response is served from the cache by checking the `response.fromCache` property, which is either undefined for normal requests, or set to true for responses that were served from cache.
224
+
225
+ ```js preview-story
226
+ export const cache = () => {
227
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
228
+
229
+ const fetchHandler = name => {
230
+ ajax.fetchJson(`../assets/${name}.json`).then(result => {
231
+ actionLogger.log(`From cache: ${result.response.fromCache || false}`);
232
+ actionLogger.log(JSON.stringify(result.body, null, 2));
233
+ });
234
+ };
235
+
236
+ return html`
237
+ <style>
238
+ sb-action-logger {
239
+ --sb-action-logger-max-height: 300px;
240
+ }
241
+ </style>
242
+ <button @click=${() => fetchHandler('pabu')}>Fetch Pabu</button>
243
+ <button @click=${() => fetchHandler('naga')}>Fetch Naga</button>
244
+ ${actionLogger}
245
+ `;
246
+ };
247
+ ```
248
+
249
+ You can also change the cache options per request, which is handy if you don't want to remove and re-add the interceptors for a simple configuration change.
250
+
251
+ In this demo, when we fetch naga, we always pass `useCache: false` so the Response is never a cached one.
252
+
253
+ ```js preview-story
254
+ export const cacheActionOptions = () => {
255
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
256
+
257
+ const fetchHandler = name => {
258
+ let actionCacheOptions;
259
+ if (name === 'naga') {
260
+ actionCacheOptions = {
261
+ useCache: false,
262
+ };
263
+ }
264
+
265
+ ajax.fetchJson(`../assets/${name}.json`, { cacheOptions: actionCacheOptions }).then(result => {
266
+ actionLogger.log(`From cache: ${result.response.fromCache || false}`);
267
+ actionLogger.log(JSON.stringify(result.body, null, 2));
268
+ });
269
+ };
270
+
271
+ return html`
272
+ <style>
273
+ sb-action-logger {
274
+ --sb-action-logger-max-height: 300px;
275
+ }
276
+ </style>
277
+ <button @click=${() => fetchHandler('pabu')}>Fetch Pabu</button>
278
+ <button @click=${() => fetchHandler('naga')}>Fetch Naga</button>
279
+ ${actionLogger}
280
+ `;
281
+ };
282
+ ```
283
+
284
+ ### Invalidating cache
285
+
286
+ Invalidating the cache, or cache busting, can be done in multiple ways:
287
+
288
+ - Going past the `maxAge` of the cache object
289
+ - Changing cache identifier (e.g. user session or active profile changes)
290
+ - Doing a non GET request to the cached endpoint
291
+ - Invalidates the cache of that endpoint
292
+ - Invalidates the cache of all other endpoints matching `invalidatesUrls` and `invalidateUrlsRegex`
293
+
294
+ ## maxAge
295
+
296
+ In this demo we pass a maxAge of three seconds.
297
+ Try clicking the fetch button and watch fromCache change whenever maxAge expires.
298
+
299
+ After maxAge expires, the next request will set the cache again, and for the next 3 seconds you will get cached responses for subsequent requests.
300
+
301
+ ```js preview-story
302
+ export const cacheMaxAge = () => {
303
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
304
+
305
+ const fetchHandler = () => {
306
+ ajax
307
+ .fetchJson(`../assets/pabu.json`, {
308
+ cacheOptions: {
309
+ maxAge: 1000 * 3, // 3 seconds
310
+ },
311
+ })
312
+ .then(result => {
313
+ actionLogger.log(`From cache: ${result.response.fromCache || false}`);
314
+ actionLogger.log(JSON.stringify(result.body, null, 2));
315
+ });
316
+ };
317
+
318
+ return html`
319
+ <style>
320
+ sb-action-logger {
321
+ --sb-action-logger-max-height: 300px;
322
+ }
323
+ </style>
324
+ <button @click=${fetchHandler}>Fetch Pabu</button>
325
+ ${actionLogger}
326
+ `;
327
+ };
328
+ ```
329
+
330
+ ## Changing cache identifier
331
+
332
+ For this demo we use localStorage to set a user id to `'1'`.
333
+
334
+ Now we will allow you to change this identifier to invalidate the cache.
335
+
336
+ ```js preview-story
337
+ export const changeCacheIdentifier = () => {
338
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
339
+
340
+ const fetchHandler = () => {
341
+ ajax.fetchJson(`../assets/pabu.json`).then(result => {
342
+ actionLogger.log(`From cache: ${result.response.fromCache || false}`);
343
+ actionLogger.log(JSON.stringify(result.body, null, 2));
344
+ });
345
+ };
346
+
347
+ const changeUserHandler = () => {
348
+ const currentUser = parseInt(localStorage.getItem('lion-ajax-cache-demo-user-id'), 10);
349
+ localStorage.setItem('lion-ajax-cache-demo-user-id', `${currentUser + 1}`);
350
+ };
351
+
352
+ return html`
353
+ <style>
354
+ sb-action-logger {
355
+ --sb-action-logger-max-height: 300px;
356
+ }
357
+ </style>
358
+ <button @click=${fetchHandler}>Fetch Pabu</button>
359
+ <button @click=${changeUserHandler}>Change user</button>
360
+ ${actionLogger}
361
+ `;
362
+ };
363
+ ```
364
+
365
+ ## Non-GET request
366
+
367
+ In this demo we show that by doing a PATCH request, you invalidate the cache of the endpoint for subsequent GET requests.
368
+
369
+ Try clicking the GET pabu button twice so you see a cached response.
370
+ Then click the PATCH pabu button, followed by another GET, and you will see that this one is not served from cache, because the PATCH invalidated it.
371
+
372
+ The rationale is that if a user does a non-GET request to an endpoint, it will make the client-side caching of this endpoint outdated.
373
+ This is because non-GET requests usually in some way mutate the state of the database through interacting with this endpoint.
374
+ Therefore, we invalidate the cache, so the user gets the latest state from the database on the next GET request.
375
+
376
+ > Ignore the browser errors when clicking PATCH buttons, JSON files (our mock database) don't accept PATCH requests.
377
+
378
+ ```js preview-story
379
+ export const nonGETRequest = () => {
380
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
381
+
382
+ const fetchHandler = (name, method) => {
383
+ ajax.fetchJson(`../assets/${name}.json`, { method }).then(result => {
384
+ actionLogger.log(`From cache: ${result.response.fromCache || false}`);
385
+ actionLogger.log(JSON.stringify(result.body, null, 2));
386
+ });
387
+ };
388
+
389
+ return html`
390
+ <style>
391
+ sb-action-logger {
392
+ --sb-action-logger-max-height: 300px;
393
+ }
394
+ </style>
395
+ <button @click=${() => fetchHandler('pabu', 'GET')}>GET Pabu</button>
396
+ <button @click=${() => fetchHandler('pabu', 'PATCH')}>PATCH Pabu</button>
397
+ <button @click=${() => fetchHandler('naga', 'GET')}>GET Naga</button>
398
+ <button @click=${() => fetchHandler('naga', 'PATCH')}>PATCH Naga</button>
399
+ ${actionLogger}
400
+ `;
401
+ };
402
+ ```
403
+
404
+ ## Invalidate Rules
405
+
406
+ There are two kinds of invalidate rules:
407
+
408
+ - `invalidateUrls` (array of URL like strings)
409
+ - `invalidateUrlsRegex` (RegExp)
410
+
411
+ If a non-GET method is fired, by default it only invalidates its own endpoint.
412
+ Invalidating `/api/users` cache by doing a PATCH, will not invalidate `/api/accounts` cache.
413
+
414
+ However, in the case of users and accounts, they may be very interconnected, so perhaps you do want to invalidate `/api/accounts` when invalidating `/api/users`.
415
+
416
+ This is what the invalidate rules are for.
417
+
418
+ In this demo, invalidating the `pabu` endpoint will invalidate `naga`, but not the other way around.
419
+
420
+ > For invalidateUrls you need the full URL e.g. `<protocol>://<domain>:<port>/<url>` so it's often easier to use invalidateUrlsRegex
421
+
422
+ ```js preview-story
423
+ export const invalidateRules = () => {
424
+ const actionLogger = renderLitAsNode(html`<sb-action-logger></sb-action-logger>`);
425
+
426
+ const fetchHandler = (name, method) => {
427
+ const actionCacheOptions = {};
428
+ if (name === 'pabu') {
429
+ actionCacheOptions.invalidateUrlsRegex = /\/docs\/tools\/ajax\/assets\/naga.json/;
430
+ }
431
+
432
+ ajax
433
+ .fetchJson(`../assets/${name}.json`, {
434
+ method,
435
+ cacheOptions: actionCacheOptions,
436
+ })
437
+ .then(result => {
438
+ actionLogger.log(`From cache: ${result.response.fromCache || false}`);
439
+ actionLogger.log(JSON.stringify(result.body, null, 2));
440
+ });
441
+ };
442
+
443
+ return html`
444
+ <style>
445
+ sb-action-logger {
446
+ --sb-action-logger-max-height: 300px;
447
+ }
448
+ </style>
449
+ <button @click=${() => fetchHandler('pabu', 'GET')}>GET Pabu</button>
450
+ <button @click=${() => fetchHandler('pabu', 'PATCH')}>PATCH Pabu</button>
451
+ <button @click=${() => fetchHandler('naga', 'GET')}>GET Naga</button>
452
+ <button @click=${() => fetchHandler('naga', 'PATCH')}>PATCH Naga</button>
453
+ ${actionLogger}
454
+ `;
455
+ };
456
+ ```