@stack-spot/portal-layout 0.0.65 → 1.0.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.
Files changed (185) hide show
  1. package/dist/Layout.d.ts +58 -6
  2. package/dist/Layout.d.ts.map +1 -1
  3. package/dist/Layout.js +14 -7
  4. package/dist/Layout.js.map +1 -1
  5. package/dist/LayoutOverlayManager.d.ts +173 -6
  6. package/dist/LayoutOverlayManager.d.ts.map +1 -1
  7. package/dist/LayoutOverlayManager.js +118 -9
  8. package/dist/LayoutOverlayManager.js.map +1 -1
  9. package/dist/components/Dialog.d.ts +48 -5
  10. package/dist/components/Dialog.d.ts.map +1 -1
  11. package/dist/components/Dialog.js +7 -2
  12. package/dist/components/Dialog.js.map +1 -1
  13. package/dist/components/Header.d.ts +29 -1
  14. package/dist/components/Header.d.ts.map +1 -1
  15. package/dist/components/Header.js +6 -2
  16. package/dist/components/Header.js.map +1 -1
  17. package/dist/components/OverlayContent.d.ts +22 -0
  18. package/dist/components/OverlayContent.d.ts.map +1 -1
  19. package/dist/components/OverlayContent.js +4 -0
  20. package/dist/components/OverlayContent.js.map +1 -1
  21. package/dist/components/PortalSwitcher.d.ts +14 -0
  22. package/dist/components/PortalSwitcher.d.ts.map +1 -1
  23. package/dist/components/PortalSwitcher.js +9 -6
  24. package/dist/components/PortalSwitcher.js.map +1 -1
  25. package/dist/components/Toaster.d.ts +4 -0
  26. package/dist/components/Toaster.d.ts.map +1 -1
  27. package/dist/components/Toaster.js +5 -1
  28. package/dist/components/Toaster.js.map +1 -1
  29. package/dist/components/UserMenu.d.ts +14 -1
  30. package/dist/components/UserMenu.d.ts.map +1 -1
  31. package/dist/components/UserMenu.js +5 -1
  32. package/dist/components/UserMenu.js.map +1 -1
  33. package/dist/components/error/ErrorBoundary.d.ts +10 -1
  34. package/dist/components/error/ErrorBoundary.d.ts.map +1 -1
  35. package/dist/components/error/ErrorBoundary.js +10 -1
  36. package/dist/components/error/ErrorBoundary.js.map +1 -1
  37. package/dist/components/error/ErrorManager.d.ts +22 -6
  38. package/dist/components/error/ErrorManager.d.ts.map +1 -1
  39. package/dist/components/error/ErrorManager.js +21 -1
  40. package/dist/components/error/ErrorManager.js.map +1 -1
  41. package/dist/components/error/SilentErrorBoundary.d.ts +11 -2
  42. package/dist/components/error/SilentErrorBoundary.d.ts.map +1 -1
  43. package/dist/components/error/SilentErrorBoundary.js +10 -0
  44. package/dist/components/error/SilentErrorBoundary.js.map +1 -1
  45. package/dist/components/menu/MenuContent.d.ts +19 -2
  46. package/dist/components/menu/MenuContent.d.ts.map +1 -1
  47. package/dist/components/menu/MenuContent.js +33 -35
  48. package/dist/components/menu/MenuContent.js.map +1 -1
  49. package/dist/components/menu/MenuSections.d.ts +10 -0
  50. package/dist/components/menu/MenuSections.d.ts.map +1 -1
  51. package/dist/components/menu/MenuSections.js +70 -16
  52. package/dist/components/menu/MenuSections.js.map +1 -1
  53. package/dist/components/menu/PageSelector.d.ts +5 -0
  54. package/dist/components/menu/PageSelector.d.ts.map +1 -1
  55. package/dist/components/menu/PageSelector.js +8 -3
  56. package/dist/components/menu/PageSelector.js.map +1 -1
  57. package/dist/components/menu/types.d.ts +100 -7
  58. package/dist/components/menu/types.d.ts.map +1 -1
  59. package/dist/components/tour/PortalSwitcherStep.d.ts +6 -1
  60. package/dist/components/tour/PortalSwitcherStep.d.ts.map +1 -1
  61. package/dist/components/tour/PortalSwitcherStep.js +6 -1
  62. package/dist/components/tour/PortalSwitcherStep.js.map +1 -1
  63. package/dist/components/types.d.ts +0 -13
  64. package/dist/components/types.d.ts.map +1 -1
  65. package/dist/dictionary.d.ts +3 -0
  66. package/dist/dictionary.d.ts.map +1 -1
  67. package/dist/dictionary.js +3 -0
  68. package/dist/dictionary.js.map +1 -1
  69. package/dist/elements.d.ts +6 -0
  70. package/dist/elements.d.ts.map +1 -1
  71. package/dist/elements.js +6 -0
  72. package/dist/elements.js.map +1 -1
  73. package/dist/index.d.ts +0 -3
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +0 -3
  76. package/dist/index.js.map +1 -1
  77. package/dist/layout.css +1 -5
  78. package/dist/toaster.d.ts +74 -9
  79. package/dist/toaster.d.ts.map +1 -1
  80. package/dist/toaster.js +32 -6
  81. package/dist/toaster.js.map +1 -1
  82. package/dist/utils.d.ts +6 -69
  83. package/dist/utils.d.ts.map +1 -1
  84. package/dist/utils.js +9 -130
  85. package/dist/utils.js.map +1 -1
  86. package/package.json +16 -15
  87. package/readme.md +146 -0
  88. package/src/Layout.tsx +79 -30
  89. package/src/LayoutOverlayManager.tsx +184 -9
  90. package/src/components/Dialog.tsx +49 -6
  91. package/src/components/Header.tsx +31 -3
  92. package/src/components/OverlayContent.tsx +22 -0
  93. package/src/components/PortalSwitcher.tsx +22 -8
  94. package/src/components/Toaster.tsx +10 -2
  95. package/src/components/UserMenu.tsx +14 -1
  96. package/src/components/error/ErrorBoundary.tsx +11 -2
  97. package/src/components/error/ErrorManager.ts +22 -6
  98. package/src/components/error/SilentErrorBoundary.tsx +12 -2
  99. package/src/components/menu/MenuContent.tsx +33 -52
  100. package/src/components/menu/MenuSections.tsx +99 -49
  101. package/src/components/menu/PageSelector.tsx +8 -3
  102. package/src/components/menu/types.ts +100 -8
  103. package/src/components/tour/PortalSwitcherStep.tsx +7 -4
  104. package/src/components/types.ts +0 -14
  105. package/src/dictionary.ts +3 -0
  106. package/src/elements.ts +6 -0
  107. package/src/index.ts +0 -3
  108. package/src/layout.css +1 -5
  109. package/src/toaster.tsx +125 -14
  110. package/src/utils.ts +9 -142
  111. package/dist/components/BottomNotification.d.ts +0 -1
  112. package/dist/components/BottomNotification.d.ts.map +0 -1
  113. package/dist/components/BottomNotification.js +0 -2
  114. package/dist/components/BottomNotification.js.map +0 -1
  115. package/dist/components/BottomPanel.d.ts +0 -1
  116. package/dist/components/BottomPanel.d.ts.map +0 -1
  117. package/dist/components/BottomPanel.js +0 -2
  118. package/dist/components/BottomPanel.js.map +0 -1
  119. package/dist/components/SelectionList.d.ts +0 -36
  120. package/dist/components/SelectionList.d.ts.map +0 -1
  121. package/dist/components/SelectionList.js +0 -140
  122. package/dist/components/SelectionList.js.map +0 -1
  123. package/dist/components/error/ErrorFeedback.d.ts +0 -3
  124. package/dist/components/error/ErrorFeedback.d.ts.map +0 -1
  125. package/dist/components/error/ErrorFeedback.js +0 -66
  126. package/dist/components/error/ErrorFeedback.js.map +0 -1
  127. package/dist/components/menu/use-check-text-overflow.d.ts +0 -6
  128. package/dist/components/menu/use-check-text-overflow.d.ts.map +0 -1
  129. package/dist/components/menu/use-check-text-overflow.js +0 -20
  130. package/dist/components/menu/use-check-text-overflow.js.map +0 -1
  131. package/dist/components/menu/use-keyboard-controls.d.ts +0 -23
  132. package/dist/components/menu/use-keyboard-controls.d.ts.map +0 -1
  133. package/dist/components/menu/use-keyboard-controls.js +0 -49
  134. package/dist/components/menu/use-keyboard-controls.js.map +0 -1
  135. package/dist/layout-context.d.ts +0 -10
  136. package/dist/layout-context.d.ts.map +0 -1
  137. package/dist/layout-context.js +0 -11
  138. package/dist/layout-context.js.map +0 -1
  139. package/dist/svg/AI.d.ts +0 -6
  140. package/dist/svg/AI.d.ts.map +0 -1
  141. package/dist/svg/AI.js +0 -9
  142. package/dist/svg/AI.js.map +0 -1
  143. package/dist/svg/EDP.d.ts +0 -6
  144. package/dist/svg/EDP.d.ts.map +0 -1
  145. package/dist/svg/EDP.js +0 -5
  146. package/dist/svg/EDP.js.map +0 -1
  147. package/dist/svg/Forbidden.d.ts +0 -6
  148. package/dist/svg/Forbidden.d.ts.map +0 -1
  149. package/dist/svg/Forbidden.js +0 -4
  150. package/dist/svg/Forbidden.js.map +0 -1
  151. package/dist/svg/HUB.d.ts +0 -6
  152. package/dist/svg/HUB.d.ts.map +0 -1
  153. package/dist/svg/HUB.js +0 -5
  154. package/dist/svg/HUB.js.map +0 -1
  155. package/dist/svg/Logo.d.ts +0 -2
  156. package/dist/svg/Logo.d.ts.map +0 -1
  157. package/dist/svg/Logo.js +0 -4
  158. package/dist/svg/Logo.js.map +0 -1
  159. package/dist/svg/NotFound.d.ts +0 -6
  160. package/dist/svg/NotFound.d.ts.map +0 -1
  161. package/dist/svg/NotFound.js +0 -4
  162. package/dist/svg/NotFound.js.map +0 -1
  163. package/dist/svg/ServerError.d.ts +0 -6
  164. package/dist/svg/ServerError.d.ts.map +0 -1
  165. package/dist/svg/ServerError.js +0 -4
  166. package/dist/svg/ServerError.js.map +0 -1
  167. package/dist/svg/Unauthenticated.d.ts +0 -6
  168. package/dist/svg/Unauthenticated.d.ts.map +0 -1
  169. package/dist/svg/Unauthenticated.js +0 -4
  170. package/dist/svg/Unauthenticated.js.map +0 -1
  171. package/src/components/BottomNotification.tsx +0 -0
  172. package/src/components/BottomPanel.tsx +0 -0
  173. package/src/components/SelectionList.tsx +0 -272
  174. package/src/components/error/ErrorFeedback.tsx +0 -114
  175. package/src/components/menu/use-check-text-overflow.tsx +0 -26
  176. package/src/components/menu/use-keyboard-controls.tsx +0 -70
  177. package/src/layout-context.tsx +0 -22
  178. package/src/svg/AI.tsx +0 -37
  179. package/src/svg/EDP.tsx +0 -35
  180. package/src/svg/Forbidden.tsx +0 -22
  181. package/src/svg/HUB.tsx +0 -35
  182. package/src/svg/Logo.tsx +0 -35
  183. package/src/svg/NotFound.tsx +0 -16
  184. package/src/svg/ServerError.tsx +0 -33
  185. package/src/svg/Unauthenticated.tsx +0 -16
package/dist/utils.d.ts CHANGED
@@ -1,80 +1,17 @@
1
- export declare function valueOfLayoutVar(varname: string): string;
2
- /**
3
- * Important for accessibility.
4
- *
5
- * Makes it so we focus the next focusable element in the DOM hierarchy, disregarding the element passed as parameter and its children.
6
- *
7
- * If there's no next focusable element, the first focusable of the page will be focused. If the page doesn't contain any focusable
8
- * element, nothing happens.
9
- *
10
- * @param current the reference element to focus the next. If not provided, will be the currently active element.
11
- */
12
- export declare function focusNextIgnoringChildren(current?: HTMLElement | null): void;
13
- type TagPriority = 'a' | 'button' | 'input' | 'textarea' | 'select' | 'other';
14
- type TagPriorityElement = TagPriority | TagPriority[];
15
- interface FocusOptions {
16
- /**
17
- * Instead of focusing the first element overall, focus the first according to this list of priorities.
18
- */
19
- priority?: TagPriorityElement[];
20
- /**
21
- * Ignores any element that matches this query selector.
22
- */
23
- ignore?: string;
24
- }
25
- /**
26
- * Checks if an element can receive focus.
27
- *
28
- * Elements can receive focus only if:
29
- * - they exist;
30
- * - they're visible;
31
- * - they're not disabled;
32
- * - they are a focusable tag name or have a positive tab index;
33
- * - they don't have a negative tab index.
34
- * @param element the element to check.
35
- * @returns true if the element is focusable, false otherwise.
36
- */
37
- export declare function isFocusable(element?: Element | null): boolean;
38
- /**
39
- * Focus the element passed as parameter if it can receive focus. Otherwise, decides on another element to focus based on the HTML tree
40
- * and accessibility attributes.
41
- *
42
- * Decision making:
43
- * - If the element is focusable, focus it.
44
- * - If the element is not focusable, check if it has an id and if another element controls it (aria-controls).
45
- * - If the element is controlled by another, try to focus the controller, based in this same algorithm.
46
- * - Otherwise, try to focus its parent.
47
- *
48
- * If no focusable element is found. Nothing happens.
49
- * @param element the element to focus.
50
- */
51
- export declare function focusAccessibleElement(element?: Element | null): void;
52
1
  /**
53
- * Focus the first focusable child of the element provided. If the element has no focusable child, nothing happens.
54
- *
55
- * A priority list can be passed in the second parameter, as an option. If it's provided, it will focus the first element according to the
56
- * list.
2
+ * Gets the value for a css variable of the layout.
57
3
  *
58
- * An ignore query selector can also be passed in the options parameter. If the first focusable element matches the query selector, the
59
- * next element is focused instead.
4
+ * Supposing the actual name of the variable is name-of-variable, the value passed to the first parameter (varname) may be: name-of-variable
5
+ * or --name-of-variable or var(--name-of-variable). All these formats work.
60
6
  *
61
- * @example
62
- * Suppose the children of element are: h1, button, p, input, select.
63
- * 1. We don't pass a priority list. The focused element will be the button.
64
- * 2. Our priority list is ['button']. The focused element will be the button.
65
- * 3. Our priority list is ['input', 'button']. The focused element will be the input.
66
- * 4. Our priority list is ['select', 'input']. The focused element will be the select.
67
- * 5. Our priority list is [['select', 'input'], 'button']. The focused element will be the input.
68
- *
69
- * @param element the element to search a child to focus.
70
- * @param options optional.
7
+ * @param varname the name of css variable.
8
+ * @returns the value of `varname`.
71
9
  */
72
- export declare function focusFirstChild(element: HTMLElement | Document | null | undefined, { priority, ignore }?: FocusOptions): void;
10
+ export declare function valueOfLayoutVar(varname: string): string;
73
11
  /**
74
12
  * Accessibility: makes the screen reader announce some text out loud.
75
13
  *
76
14
  * @param text the message for the screen reader to read.
77
15
  */
78
16
  export declare function announce(text: string): void;
79
- export {};
80
17
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,QAWrE;AAED,KAAK,WAAW,GAAG,GAAG,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAC7E,KAAK,kBAAkB,GAAG,WAAW,GAAG,WAAW,EAAE,CAAA;AAErD,UAAU,YAAY;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAChC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAWD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,WAYnD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,QAO9D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,EAAE,EAAE,QAAa,EAAE,MAAM,EAAE,GAAE,YAAiB,QA0B/H;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,QAKpC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,QAKpC"}
package/dist/utils.js CHANGED
@@ -1,141 +1,20 @@
1
1
  import { valueOf } from '@stack-spot/portal-theme';
2
2
  import { getLayoutElements } from './elements.js';
3
+ /**
4
+ * Gets the value for a css variable of the layout.
5
+ *
6
+ * Supposing the actual name of the variable is name-of-variable, the value passed to the first parameter (varname) may be: name-of-variable
7
+ * or --name-of-variable or var(--name-of-variable). All these formats work.
8
+ *
9
+ * @param varname the name of css variable.
10
+ * @returns the value of `varname`.
11
+ */
3
12
  export function valueOfLayoutVar(varname) {
4
13
  const layout = document.getElementById('layout');
5
14
  if (!layout)
6
15
  return '';
7
16
  return valueOf(varname, layout);
8
17
  }
9
- /**
10
- * Important for accessibility.
11
- *
12
- * Makes it so we focus the next focusable element in the DOM hierarchy, disregarding the element passed as parameter and its children.
13
- *
14
- * If there's no next focusable element, the first focusable of the page will be focused. If the page doesn't contain any focusable
15
- * element, nothing happens.
16
- *
17
- * @param current the reference element to focus the next. If not provided, will be the currently active element.
18
- */
19
- export function focusNextIgnoringChildren(current) {
20
- current = current ?? document.activeElement;
21
- while (current && !current.nextElementSibling) {
22
- current = current?.parentElement;
23
- }
24
- current = current?.nextElementSibling;
25
- while (current && current.tabIndex < 0) {
26
- current = (current.children.length ? current.firstChild : current.nextElementSibling);
27
- }
28
- if (current)
29
- current?.focus?.();
30
- else
31
- focusFirstChild(document);
32
- }
33
- const selectors = {
34
- a: 'a[href]:not(:disabled)',
35
- button: 'button:not(:disabled)',
36
- input: 'input:not(:disabled):not([type="hidden"])',
37
- select: 'textarea:not(:disabled)',
38
- textarea: 'select:not(:disabled)',
39
- other: '[tabindex]:not([tabindex="-1"])',
40
- };
41
- /**
42
- * Checks if an element can receive focus.
43
- *
44
- * Elements can receive focus only if:
45
- * - they exist;
46
- * - they're visible;
47
- * - they're not disabled;
48
- * - they are a focusable tag name or have a positive tab index;
49
- * - they don't have a negative tab index.
50
- * @param element the element to check.
51
- * @returns true if the element is focusable, false otherwise.
52
- */
53
- export function isFocusable(element) {
54
- if (!element)
55
- return false;
56
- // is disabled: return false
57
- if (element.ariaDisabled || element.getAttribute('disabled') !== null)
58
- return false;
59
- // is invisible: return false
60
- if (!element.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }))
61
- return false;
62
- // has tab index: return false if negative, true otherwise
63
- const tabIndexStr = element.getAttribute('tabindex');
64
- const tabIndex = tabIndexStr ? parseInt(tabIndexStr) : undefined;
65
- if (tabIndex !== undefined)
66
- return tabIndex >= 0;
67
- // check the tag name
68
- return ['a', 'button', 'input', 'iframe', 'select', 'textarea'].includes(element.tagName.toLowerCase() ?? '');
69
- }
70
- /**
71
- * Focus the element passed as parameter if it can receive focus. Otherwise, decides on another element to focus based on the HTML tree
72
- * and accessibility attributes.
73
- *
74
- * Decision making:
75
- * - If the element is focusable, focus it.
76
- * - If the element is not focusable, check if it has an id and if another element controls it (aria-controls).
77
- * - If the element is controlled by another, try to focus the controller, based in this same algorithm.
78
- * - Otherwise, try to focus its parent.
79
- *
80
- * If no focusable element is found. Nothing happens.
81
- * @param element the element to focus.
82
- */
83
- export function focusAccessibleElement(element) {
84
- let elementToFocus = element;
85
- while (elementToFocus && !isFocusable(elementToFocus)) {
86
- const controlledBy = elementToFocus.id ? document.querySelector(`[aria-controls=${elementToFocus.id}]`) : undefined;
87
- elementToFocus = (controlledBy ?? elementToFocus.parentElement);
88
- }
89
- elementToFocus?.focus?.();
90
- }
91
- /**
92
- * Focus the first focusable child of the element provided. If the element has no focusable child, nothing happens.
93
- *
94
- * A priority list can be passed in the second parameter, as an option. If it's provided, it will focus the first element according to the
95
- * list.
96
- *
97
- * An ignore query selector can also be passed in the options parameter. If the first focusable element matches the query selector, the
98
- * next element is focused instead.
99
- *
100
- * @example
101
- * Suppose the children of element are: h1, button, p, input, select.
102
- * 1. We don't pass a priority list. The focused element will be the button.
103
- * 2. Our priority list is ['button']. The focused element will be the button.
104
- * 3. Our priority list is ['input', 'button']. The focused element will be the input.
105
- * 4. Our priority list is ['select', 'input']. The focused element will be the select.
106
- * 5. Our priority list is [['select', 'input'], 'button']. The focused element will be the input.
107
- *
108
- * @param element the element to search a child to focus.
109
- * @param options optional.
110
- */
111
- export function focusFirstChild(element, { priority = [], ignore } = {}) {
112
- let focusable;
113
- let missing = ['a', 'button', 'input', 'other', 'select', 'textarea'];
114
- for (const p of priority) {
115
- const tags = Array.isArray(p) ? p : [p];
116
- const querySelectors = tags.map(t => {
117
- missing = missing.filter(tag => tag != t);
118
- return selectors[t];
119
- });
120
- focusable = element?.querySelectorAll(querySelectors.join(', '));
121
- if (focusable)
122
- break;
123
- }
124
- if (!focusable) {
125
- element?.querySelectorAll(missing.map(t => selectors[t]).join(', '));
126
- }
127
- let elementToFocus;
128
- for (const f of focusable ?? []) {
129
- if (!ignore || !f.matches(ignore)) {
130
- const styles = window.getComputedStyle(f);
131
- if (styles.display != 'none' && styles.visibility != 'hidden') {
132
- elementToFocus = f;
133
- break;
134
- }
135
- }
136
- }
137
- elementToFocus?.focus?.();
138
- }
139
18
  /**
140
19
  * Accessibility: makes the screen reader announce some text out loud.
141
20
  *
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAA;IAChD,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IACtB,OAAO,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,EAAE,sBAAsB,EAAE,GAAG,iBAAiB,EAAE,CAAA;IACtD,IAAI,CAAC,sBAAsB;QAAE,OAAM;IACnC,sBAAsB,CAAC,WAAW,GAAG,IAAI,CAAA;IACzC,UAAU,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,WAAW,GAAG,EAAE,EAAE,IAAI,CAAC,CAAA;AACjE,CAAC"}
package/package.json CHANGED
@@ -1,29 +1,26 @@
1
1
  {
2
2
  "name": "@stack-spot/portal-layout",
3
- "version": "0.0.65",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
- "scripts": {
8
- "build": "tsc && tsc-esm-fix --target='dist' && cpy src/layout.css dist --flat",
9
- "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
10
- },
11
7
  "peerDependencies": {
12
- "@citric/core": ">=6.0.0",
13
- "@citric/icons": ">=5.7.1",
14
- "@citric/ui": ">=5.7.2",
15
- "@stack-spot/portal-theme": ">=0.0.11",
16
- "@stack-spot/portal-translate": ">=0.0.6",
17
- "@stack-spot/portal-components": ">=0.0.17",
18
- "react": ">=18.2.0",
19
- "react-dom": ">=18.2.0",
20
- "styled-components": ">=6.1.1"
8
+ "@citric/core": "^6.0.0",
9
+ "@citric/icons": "^5.7.1",
10
+ "@citric/ui": "^5.7.2 || ^6.0.0",
11
+ "@stack-spot/portal-theme": "^1.0.0",
12
+ "@stack-spot/portal-translate": "^1.0.0",
13
+ "@stack-spot/portal-components": "^1.0.0",
14
+ "react": "^18.2.0",
15
+ "react-dom": "^18.2.0",
16
+ "styled-components": "^6.1.10"
21
17
  },
22
18
  "devDependencies": {
23
19
  "@types/react": "^18.2.37",
24
20
  "@types/react-dom": "^18.2.15",
25
21
  "@typescript-eslint/eslint-plugin": "^6.10.0",
26
22
  "@typescript-eslint/parser": "^6.10.0",
23
+ "agadoo": "^3.0.0",
27
24
  "cpy-cli": "^5.0.0",
28
25
  "eslint": "^8.53.0",
29
26
  "eslint-plugin-filenames": "^1.3.2",
@@ -37,6 +34,10 @@
37
34
  "typescript": "^5.2.2"
38
35
  },
39
36
  "dependencies": {
40
- "react-toastify": "^9.1.3"
37
+ "react-toastify": "^10.0.5"
38
+ },
39
+ "scripts": {
40
+ "build": "tsc && tsc-esm-fix --target='dist' && cpy src/layout.css dist --flat",
41
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
41
42
  }
42
43
  }
package/readme.md ADDED
@@ -0,0 +1,146 @@
1
+ # Layout
2
+ Implements the general layout for a Stackspot web application.
3
+
4
+ ## Components
5
+ - Header: a top bar with a logo and a user menu.
6
+ - Menu (sections): a left vertical bar with every section in the application.
7
+ - Menu (content, or contextual): a left vertical bar on the right of the menu sections that shows the menu for the current section or page.
8
+ - Page: the actual page content.
9
+ - Modal: a floating panel to show modal content.
10
+ - Right panel: a floating panel that shows like a modal, but is fixed to the right side of the window.
11
+ - Bottom dialog: a floating fixed panel fixed to the bottom of the window.
12
+ - Toaster: a floating set of cards at the top right corner used to show notifications.
13
+
14
+ The overlay components (modal, right panel, bottom dialog and toaster) are controlled imperatively through the overlay object. Example:
15
+ `overlay.showModal(options)`.
16
+
17
+ The header, menus and page are rendered by the component `<Layout>` according to its props. If you need a custom header or menu, you can use
18
+ `<RawLayout>` which accepts React elements instead of configuration objects.
19
+
20
+ You can also render the menu and header separately by importing the components `<MenuContent>`, `<MenuSections>` or `<Header>`.
21
+
22
+ ## The Layout component
23
+ To render the layout, use the component `<Layout>`, check the example below:
24
+
25
+ ```tsx
26
+ const menu = {
27
+ options: [
28
+ {
29
+ label: 'Section 1',
30
+ icon: <MyIcon />,
31
+ href: '/section-1',
32
+ active: true,
33
+ },
34
+ {
35
+ label: 'Section 2',
36
+ icon: <MyIcon2 />,
37
+ href: '/section-2',
38
+ }
39
+ ]
40
+ }
41
+
42
+ const header = {
43
+ userName: 'Test',
44
+ email: 'test@stackspot.com',
45
+ center: <SearchField />,
46
+ options: [
47
+ {
48
+ label: 'Logout',
49
+ icon: <Logout />,
50
+ onClick: () => logout(),
51
+ }
52
+ ]
53
+ }
54
+
55
+ const MyApp = () => {
56
+ return <Layout menu={menu} header={header}>Hello World!</Layout>
57
+ }
58
+ ```
59
+
60
+ The Header and Menu in a layout are highly customizable. Check the code documentation for more details!
61
+
62
+ ## Modal and right panel pitfalls
63
+ Both these elements of the layout were designed to be used as imperative/procedural calls, i.e. instead of rendering a modal based on a
64
+ React State, we just call `overlay.showModal(content)` or `await confirm({ message: '...' })`. This makes using a modal much easier, but
65
+ prevents us from using React Portals.
66
+
67
+ Without the use of React Portals, the modal content becomes isolated from the context it was called, meaning, updating a state of the
68
+ component who called it, won't update the content of the modal.
69
+
70
+ Programming a modal isolated from whatever called it is a good thing! It makes the code more maintainable and less coupled. But we need to
71
+ keep this behavior in mind. See the example below:
72
+
73
+ ```tsx
74
+ const Counter = () => {
75
+ const [current, setCurrent] = useState(0)
76
+ function showCounterModal() {
77
+ overlay.showModal({
78
+ title: 'Counter',
79
+ children: (
80
+ <div>
81
+ <p>The value is {counter}.</p>
82
+ <button onClick={setCurrent(v => v + 1)}>Increment</button>
83
+ </div>
84
+ ),
85
+ })
86
+ }
87
+ return <button onClick={showCounterModal}>Show counter modal</button>
88
+ }
89
+ ```
90
+
91
+ This won't work because the state was declared outside the modal. We may click as muck as we want to increment the value, the text will keep
92
+ saying the first value it showed. The value will only be updated once we close the modal and open it up again.
93
+
94
+ The correct way of doing this would be, instead of declaring the state outside the modal, declaring it inside, see the example below:
95
+
96
+ ```tsx
97
+ const CounterModal = () => {
98
+ const [current, setCurrent] = useState(0)
99
+
100
+ return (
101
+ <div>
102
+ <p>The value is {counter}.</p>
103
+ <button onClick={setCurrent(v => v + 1)}>Increment</button>
104
+ </div>
105
+ )
106
+ }
107
+
108
+ const Counter = () => {
109
+ function showCounterModal() {
110
+ overlay.showModal({
111
+ title: 'Counter',
112
+ children: <CounterModal />,
113
+ })
114
+ }
115
+ return <button onClick={showCounterModal}>Show counter modal</button>
116
+ }
117
+ ```
118
+
119
+ This is going to work as expected, because the modal controls its own state!
120
+
121
+ If you really need to use an external state, consider:
122
+
123
+ 1. Using a React Context declared before `<Layout>`.
124
+ 2. Calling `overlay.showModal()` again to force its UI to update with the new state value.
125
+
126
+ ### Attention: opening and closing modals are side-effects!
127
+ The operations to open or close a modal or right panel are side effects, and, because of this, they should not be called during the
128
+ rendering phase of a component!
129
+
130
+ You should open/close a modal/rightPanel on events (e.g. `onClick`) or React effects (e.g. `useEffect`).
131
+
132
+ ## Layout elements
133
+ You can easily refer to layout elements by using their ids: `elementIds` or by calling the function `getLayoutElements()`.
134
+
135
+ ## Error handling
136
+ Every part of the layout is wrapped under a React Error Boundary. If an error occurs in a part of the layout that is large enough
137
+ (e.g. Page), an error feedback is rendered. Otherwise, the content stays empty. The error is always logged to the console.
138
+
139
+ In development mode, a button shows up in the error feedback, the button allows the error message to be seen without opening the console.
140
+ For the error boundaries that don't show an error feedback, in development mode, a small error icon is rendered.
141
+
142
+ To better format errors in an error boundary, please pass `errorDescriptor` to the component `<Layout>`, this is a function that transforms
143
+ an Error into something readable to present to the user.
144
+
145
+ To intercept every error when it's catch by an Error Boundary, use the property `onError` of the component `<Layout>`. This is useful for
146
+ sending error reports to the backend.
package/src/Layout.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { TourProps, TourProvider, defaultTourConfig, isNewTourStep } from '@stack-spot/portal-components'
1
+ import { TourProps, TourProvider, defaultTourConfig, isNewTourStep } from '@stack-spot/portal-components/Tour'
2
2
  import { CSSToCitricAdapter, WithStyle, listToClass } from '@stack-spot/portal-theme'
3
3
  import '@stack-spot/portal-theme/dist/theme.css'
4
4
  import { ReactElement, ReactNode, useEffect } from 'react'
@@ -13,33 +13,81 @@ import { MenuSections } from './components/menu/MenuSections'
13
13
  import { MenuProps } from './components/menu/types'
14
14
  import { usePortalSwitcherStep } from './components/tour/PortalSwitcherStep'
15
15
  import { elementIds, getLayoutElements } from './elements'
16
- import { LayoutContext, LayoutProvider } from './layout-context'
17
16
  import './layout.css'
18
17
 
19
- interface Props extends WithStyle, LayoutContext {
18
+ interface Props extends WithStyle {
19
+ /**
20
+ * The config for the menu.
21
+ */
20
22
  menu: MenuProps,
23
+ /**
24
+ * The config for the header.
25
+ */
21
26
  header: HeaderProps,
27
+ /**
28
+ * The React node to go in the page content.
29
+ */
22
30
  children: ReactNode,
31
+ /**
32
+ * A React node to place right after the page.
33
+ */
23
34
  extra?: ReactNode,
35
+ /**
36
+ * A function to convert errors into a readable format so they're properly rendered and logged.
37
+ */
24
38
  errorDescriptor?: DescriptionFn,
39
+ /**
40
+ * A function to run whenever an error is catch by an error boundary.
41
+ */
25
42
  onError?: ErrorHandler,
43
+ /**
44
+ * The options for the React Tour's tutorial.
45
+ */
26
46
  tourProps?: TourProps,
27
47
  }
28
48
 
29
- interface RawProps extends WithStyle, LayoutContext {
49
+ interface RawProps extends WithStyle {
50
+ /**
51
+ * The React element to go in the menu sections.
52
+ */
30
53
  menuSections?: ReactElement,
54
+ /**
55
+ * The React element to go in the menu content.
56
+ */
31
57
  menuContent?: ReactElement,
58
+ /**
59
+ * The React element to go in the header.
60
+ */
32
61
  header?: ReactElement,
62
+ /**
63
+ * The React node to go in the page content.
64
+ */
33
65
  children?: ReactNode,
66
+ /**
67
+ * A React node to place right after the page.
68
+ */
34
69
  extra?: ReactNode,
70
+ /**
71
+ * A function to convert errors into a readable format so they're properly rendered and logged.
72
+ */
35
73
  errorDescriptor?: DescriptionFn,
74
+ /**
75
+ * A function to run whenever an error is catch by an error boundary.
76
+ */
36
77
  onError?: ErrorHandler,
78
+ /**
79
+ * The options for the React Tour's tutorial.
80
+ */
37
81
  tourProps?: TourProps,
38
82
  }
39
83
 
84
+ /**
85
+ * Renders the layout with the React elements passed in the props.
86
+ * @param props the component's props {@link RawProps}.
87
+ */
40
88
  export const RawLayout = (
41
89
  { menuSections, menuContent, header, children, tourProps,
42
- extra, errorDescriptor, onError, className, style, anchorTag }:
90
+ extra, errorDescriptor, onError, className, style }:
43
91
  RawProps,
44
92
  ) => {
45
93
  // @ts-ignore
@@ -68,30 +116,28 @@ export const RawLayout = (
68
116
 
69
117
  return (
70
118
  <CSSToCitricAdapter>
71
- <LayoutProvider anchorTag={anchorTag}>
72
- <TourProvider config={tourPropsWithDefaults} >
73
- <div id={elementIds.layout} className={listToClass(classes)} style={style}>
74
- {children && <div id={elementIds.page}>
75
- <article id={elementIds.content}><ErrorBoundary>{children}</ErrorBoundary></article>
76
- </div>}
77
- {extra && <SilentErrorBoundary>{extra}</SilentErrorBoundary>}
78
- <aside id={elementIds.menu}>
79
- <nav role="menu" id={elementIds.menuContent}><SilentErrorBoundary>{menuContent}</SilentErrorBoundary></nav>
80
- {menuSections &&
81
- <nav role="menu" id={elementIds.menuSections}><SilentErrorBoundary>{menuSections}</SilentErrorBoundary></nav>}
82
- </aside>
83
- {header && <header id={elementIds.header}><SilentErrorBoundary>{header}</SilentErrorBoundary></header>}
84
- <div id={elementIds.bottomDialog} role="dialog"><ErrorBoundary>{bottomDialog}</ErrorBoundary></div>
85
- <div id={elementIds.backdrop}>
86
- <div id={elementIds.rightPanel} aria-modal role="dialog"><ErrorBoundary>{rightPanel}</ErrorBoundary></div>
87
- <div id={elementIds.modal} aria-modal role="dialog"><ErrorBoundary>{modal}</ErrorBoundary></div>
88
- </div>
89
- <Toaster />
90
- <div id={elementIds.accessibilityAnnouncer} aria-atomic aria-live="assertive">
91
- </div>
119
+ <TourProvider config={tourPropsWithDefaults} >
120
+ <div id={elementIds.layout} className={listToClass(classes)} style={style}>
121
+ {children && <div id={elementIds.page}>
122
+ <article id={elementIds.content}><ErrorBoundary>{children}</ErrorBoundary></article>
123
+ </div>}
124
+ {extra && <SilentErrorBoundary>{extra}</SilentErrorBoundary>}
125
+ <aside id={elementIds.menu}>
126
+ <nav role="menu" id={elementIds.menuContent}><SilentErrorBoundary>{menuContent}</SilentErrorBoundary></nav>
127
+ {menuSections &&
128
+ <nav role="menu" id={elementIds.menuSections}><SilentErrorBoundary>{menuSections}</SilentErrorBoundary></nav>}
129
+ </aside>
130
+ {header && <header id={elementIds.header}><SilentErrorBoundary>{header}</SilentErrorBoundary></header>}
131
+ <div id={elementIds.bottomDialog} role="dialog"><ErrorBoundary>{bottomDialog}</ErrorBoundary></div>
132
+ <div id={elementIds.backdrop}>
133
+ <div id={elementIds.rightPanel} aria-modal role="dialog"><ErrorBoundary>{rightPanel}</ErrorBoundary></div>
134
+ <div id={elementIds.modal} aria-modal role="dialog"><ErrorBoundary>{modal}</ErrorBoundary></div>
92
135
  </div>
93
- </TourProvider>
94
- </LayoutProvider>
136
+ <Toaster />
137
+ <div id={elementIds.accessibilityAnnouncer} aria-atomic aria-live="assertive">
138
+ </div>
139
+ </div>
140
+ </TourProvider>
95
141
  </CSSToCitricAdapter>
96
142
  )
97
143
  }
@@ -101,7 +147,11 @@ const MenuContentRenderer = ({ content }: Required<Pick<Props['menu'], 'content'
101
147
  return <MenuContent {...menuContent} />
102
148
  }
103
149
 
104
- export const Layout = ({ menu, header, children, extra, errorDescriptor, onError, className, style, tourProps, anchorTag }: Props) => (
150
+ /**
151
+ * Renders the layout with a menu and header that follow the config objects passed as parameter.
152
+ * @param props the component's props {@link Props}.
153
+ */
154
+ export const Layout = ({ menu, header, children, extra, errorDescriptor, onError, className, style, tourProps }: Props) => (
105
155
  <RawLayout
106
156
  header={<Header {...header} />}
107
157
  menuSections={menu.sections ? <MenuSections {...menu} /> : undefined}
@@ -115,7 +165,6 @@ export const Layout = ({ menu, header, children, extra, errorDescriptor, onError
115
165
  className={className}
116
166
  style={style}
117
167
  tourProps={tourProps}
118
- anchorTag={anchorTag}
119
168
  >
120
169
  {children}
121
170
  </RawLayout>