@cratis/scene.blueprint.default 4.31.0 → 4.33.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 (226) hide show
  1. package/ComponentName.ts +24 -0
  2. package/defaultBlueprint.ts +2 -1
  3. package/defaultBlueprintComponentMetadata.ts +2 -0
  4. package/defaultBlueprintComponents.ts +9 -0
  5. package/dist/cjs/ComponentName.js +8 -0
  6. package/dist/cjs/ComponentName.js.map +1 -1
  7. package/dist/cjs/defaultBlueprint.js +9 -5
  8. package/dist/cjs/defaultBlueprint.js.map +1 -1
  9. package/dist/cjs/defaultBlueprintComponentMetadata.js +8 -0
  10. package/dist/cjs/defaultBlueprintComponentMetadata.js.map +1 -1
  11. package/dist/cjs/defaultBlueprintComponents.js +21 -1
  12. package/dist/cjs/defaultBlueprintComponents.js.map +1 -1
  13. package/dist/cjs/foundation/ActionButton.js +33 -0
  14. package/dist/cjs/foundation/ActionButton.js.map +1 -0
  15. package/dist/cjs/foundation/ChartWrapper.js +520 -0
  16. package/dist/cjs/foundation/ChartWrapper.js.map +1 -0
  17. package/dist/cjs/foundation/ColumnChooser.js +156 -0
  18. package/dist/cjs/foundation/ColumnChooser.js.map +1 -0
  19. package/dist/cjs/foundation/ComponentState.js +42 -0
  20. package/dist/cjs/foundation/ComponentState.js.map +1 -0
  21. package/dist/cjs/foundation/EmptyState.js +31 -0
  22. package/dist/cjs/foundation/EmptyState.js.map +1 -0
  23. package/dist/cjs/foundation/FilterBuilder.js +307 -0
  24. package/dist/cjs/foundation/FilterBuilder.js.map +1 -0
  25. package/dist/cjs/foundation/FoundationIcon.js +58 -0
  26. package/dist/cjs/foundation/FoundationIcon.js.map +1 -0
  27. package/dist/cjs/foundation/FoundationStates.js +62 -0
  28. package/dist/cjs/foundation/FoundationStates.js.map +1 -0
  29. package/dist/cjs/foundation/PermissionRule.js +22 -0
  30. package/dist/cjs/foundation/PermissionRule.js.map +1 -0
  31. package/dist/cjs/foundation/SavedViewsMenu.js +199 -0
  32. package/dist/cjs/foundation/SavedViewsMenu.js.map +1 -0
  33. package/dist/cjs/foundation/StatCard.js +61 -0
  34. package/dist/cjs/foundation/StatCard.js.map +1 -0
  35. package/dist/cjs/foundation/StateFrame.js +200 -0
  36. package/dist/cjs/foundation/StateFrame.js.map +1 -0
  37. package/dist/cjs/foundation/StatusChip.js +64 -0
  38. package/dist/cjs/foundation/StatusChip.js.map +1 -0
  39. package/dist/cjs/foundation/TrendChip.js +93 -0
  40. package/dist/cjs/foundation/TrendChip.js.map +1 -0
  41. package/dist/cjs/foundation/chartGeometry.js +101 -0
  42. package/dist/cjs/foundation/chartGeometry.js.map +1 -0
  43. package/dist/cjs/foundation/columnModel.js +43 -0
  44. package/dist/cjs/foundation/columnModel.js.map +1 -0
  45. package/dist/cjs/foundation/filterModel.js +123 -0
  46. package/dist/cjs/foundation/filterModel.js.map +1 -0
  47. package/dist/cjs/foundation/formatting.js +85 -0
  48. package/dist/cjs/foundation/formatting.js.map +1 -0
  49. package/dist/cjs/foundation/foundationComponentMetadata.js +69 -0
  50. package/dist/cjs/foundation/foundationComponentMetadata.js.map +1 -0
  51. package/dist/cjs/foundation/foundationDescriptors.js +385 -0
  52. package/dist/cjs/foundation/foundationDescriptors.js.map +1 -0
  53. package/dist/cjs/foundation/foundationSamples.js +201 -0
  54. package/dist/cjs/foundation/foundationSamples.js.map +1 -0
  55. package/dist/cjs/foundation/foundationStrings.js +130 -0
  56. package/dist/cjs/foundation/foundationStrings.js.map +1 -0
  57. package/dist/cjs/foundation/useElementWidth.js +31 -0
  58. package/dist/cjs/foundation/useElementWidth.js.map +1 -0
  59. package/dist/cjs/foundation/viewModel.js +24 -0
  60. package/dist/cjs/foundation/viewModel.js.map +1 -0
  61. package/dist/cjs/index.js +90 -0
  62. package/dist/cjs/index.js.map +1 -1
  63. package/dist/cjs/themes/dark.js +9 -1
  64. package/dist/cjs/themes/dark.js.map +1 -1
  65. package/dist/cjs/themes/light.js +10 -2
  66. package/dist/cjs/themes/light.js.map +1 -1
  67. package/dist/esm/ComponentName.d.ts +9 -1
  68. package/dist/esm/ComponentName.d.ts.map +1 -1
  69. package/dist/esm/ComponentName.js +8 -0
  70. package/dist/esm/ComponentName.js.map +1 -1
  71. package/dist/esm/defaultBlueprint.d.ts.map +1 -1
  72. package/dist/esm/defaultBlueprint.js +9 -5
  73. package/dist/esm/defaultBlueprint.js.map +1 -1
  74. package/dist/esm/defaultBlueprintComponentMetadata.d.ts.map +1 -1
  75. package/dist/esm/defaultBlueprintComponentMetadata.js +8 -0
  76. package/dist/esm/defaultBlueprintComponentMetadata.js.map +1 -1
  77. package/dist/esm/defaultBlueprintComponents.d.ts.map +1 -1
  78. package/dist/esm/defaultBlueprintComponents.js +21 -1
  79. package/dist/esm/defaultBlueprintComponents.js.map +1 -1
  80. package/dist/esm/foundation/ActionButton.d.ts +13 -0
  81. package/dist/esm/foundation/ActionButton.d.ts.map +1 -0
  82. package/dist/esm/foundation/ActionButton.js +31 -0
  83. package/dist/esm/foundation/ActionButton.js.map +1 -0
  84. package/dist/esm/foundation/ChartWrapper.d.ts +5 -0
  85. package/dist/esm/foundation/ChartWrapper.d.ts.map +1 -0
  86. package/dist/esm/foundation/ChartWrapper.js +517 -0
  87. package/dist/esm/foundation/ChartWrapper.js.map +1 -0
  88. package/dist/esm/foundation/ColumnChooser.d.ts +3 -0
  89. package/dist/esm/foundation/ColumnChooser.d.ts.map +1 -0
  90. package/dist/esm/foundation/ColumnChooser.js +154 -0
  91. package/dist/esm/foundation/ColumnChooser.js.map +1 -0
  92. package/dist/esm/foundation/ComponentState.d.ts +12 -0
  93. package/dist/esm/foundation/ComponentState.d.ts.map +1 -0
  94. package/dist/esm/foundation/ComponentState.js +38 -0
  95. package/dist/esm/foundation/ComponentState.js.map +1 -0
  96. package/dist/esm/foundation/EmptyState.d.ts +3 -0
  97. package/dist/esm/foundation/EmptyState.d.ts.map +1 -0
  98. package/dist/esm/foundation/EmptyState.js +29 -0
  99. package/dist/esm/foundation/EmptyState.js.map +1 -0
  100. package/dist/esm/foundation/FilterBuilder.d.ts +3 -0
  101. package/dist/esm/foundation/FilterBuilder.d.ts.map +1 -0
  102. package/dist/esm/foundation/FilterBuilder.js +305 -0
  103. package/dist/esm/foundation/FilterBuilder.js.map +1 -0
  104. package/dist/esm/foundation/Foundation.stories.d.ts +37 -0
  105. package/dist/esm/foundation/Foundation.stories.d.ts.map +1 -0
  106. package/dist/esm/foundation/Foundation.stories.js +34 -0
  107. package/dist/esm/foundation/Foundation.stories.js.map +1 -0
  108. package/dist/esm/foundation/FoundationIcon.d.ts +7 -0
  109. package/dist/esm/foundation/FoundationIcon.d.ts.map +1 -0
  110. package/dist/esm/foundation/FoundationIcon.js +55 -0
  111. package/dist/esm/foundation/FoundationIcon.js.map +1 -0
  112. package/dist/esm/foundation/FoundationStates.d.ts +8 -0
  113. package/dist/esm/foundation/FoundationStates.d.ts.map +1 -0
  114. package/dist/esm/foundation/FoundationStates.js +60 -0
  115. package/dist/esm/foundation/FoundationStates.js.map +1 -0
  116. package/dist/esm/foundation/PermissionRule.d.ts +8 -0
  117. package/dist/esm/foundation/PermissionRule.d.ts.map +1 -0
  118. package/dist/esm/foundation/PermissionRule.js +19 -0
  119. package/dist/esm/foundation/PermissionRule.js.map +1 -0
  120. package/dist/esm/foundation/SavedViewsMenu.d.ts +4 -0
  121. package/dist/esm/foundation/SavedViewsMenu.d.ts.map +1 -0
  122. package/dist/esm/foundation/SavedViewsMenu.js +196 -0
  123. package/dist/esm/foundation/SavedViewsMenu.js.map +1 -0
  124. package/dist/esm/foundation/StatCard.d.ts +3 -0
  125. package/dist/esm/foundation/StatCard.d.ts.map +1 -0
  126. package/dist/esm/foundation/StatCard.js +59 -0
  127. package/dist/esm/foundation/StatCard.js.map +1 -0
  128. package/dist/esm/foundation/StateFrame.d.ts +15 -0
  129. package/dist/esm/foundation/StateFrame.d.ts.map +1 -0
  130. package/dist/esm/foundation/StateFrame.js +197 -0
  131. package/dist/esm/foundation/StateFrame.js.map +1 -0
  132. package/dist/esm/foundation/StatusChip.d.ts +13 -0
  133. package/dist/esm/foundation/StatusChip.d.ts.map +1 -0
  134. package/dist/esm/foundation/StatusChip.js +59 -0
  135. package/dist/esm/foundation/StatusChip.js.map +1 -0
  136. package/dist/esm/foundation/TrendChip.d.ts +18 -0
  137. package/dist/esm/foundation/TrendChip.d.ts.map +1 -0
  138. package/dist/esm/foundation/TrendChip.js +88 -0
  139. package/dist/esm/foundation/TrendChip.js.map +1 -0
  140. package/dist/esm/foundation/chartGeometry.d.ts +34 -0
  141. package/dist/esm/foundation/chartGeometry.d.ts.map +1 -0
  142. package/dist/esm/foundation/chartGeometry.js +93 -0
  143. package/dist/esm/foundation/chartGeometry.js.map +1 -0
  144. package/dist/esm/foundation/columnModel.d.ts +11 -0
  145. package/dist/esm/foundation/columnModel.d.ts.map +1 -0
  146. package/dist/esm/foundation/columnModel.js +38 -0
  147. package/dist/esm/foundation/columnModel.js.map +1 -0
  148. package/dist/esm/foundation/filterModel.d.ts +33 -0
  149. package/dist/esm/foundation/filterModel.d.ts.map +1 -0
  150. package/dist/esm/foundation/filterModel.js +112 -0
  151. package/dist/esm/foundation/filterModel.js.map +1 -0
  152. package/dist/esm/foundation/formatting.d.ts +13 -0
  153. package/dist/esm/foundation/formatting.d.ts.map +1 -0
  154. package/dist/esm/foundation/formatting.js +78 -0
  155. package/dist/esm/foundation/formatting.js.map +1 -0
  156. package/dist/esm/foundation/foundationComponentMetadata.d.ts +3 -0
  157. package/dist/esm/foundation/foundationComponentMetadata.d.ts.map +1 -0
  158. package/dist/esm/foundation/foundationComponentMetadata.js +67 -0
  159. package/dist/esm/foundation/foundationComponentMetadata.js.map +1 -0
  160. package/dist/esm/foundation/foundationDescriptors.d.ts +6 -0
  161. package/dist/esm/foundation/foundationDescriptors.d.ts.map +1 -0
  162. package/dist/esm/foundation/foundationDescriptors.js +380 -0
  163. package/dist/esm/foundation/foundationDescriptors.js.map +1 -0
  164. package/dist/esm/foundation/foundationSamples.d.ts +10 -0
  165. package/dist/esm/foundation/foundationSamples.d.ts.map +1 -0
  166. package/dist/esm/foundation/foundationSamples.js +198 -0
  167. package/dist/esm/foundation/foundationSamples.js.map +1 -0
  168. package/dist/esm/foundation/foundationStrings.d.ts +103 -0
  169. package/dist/esm/foundation/foundationStrings.d.ts.map +1 -0
  170. package/dist/esm/foundation/foundationStrings.js +126 -0
  171. package/dist/esm/foundation/foundationStrings.js.map +1 -0
  172. package/dist/esm/foundation/index.d.ts +25 -0
  173. package/dist/esm/foundation/index.d.ts.map +1 -0
  174. package/dist/esm/foundation/index.js +25 -0
  175. package/dist/esm/foundation/index.js.map +1 -0
  176. package/dist/esm/foundation/useElementWidth.d.ts +3 -0
  177. package/dist/esm/foundation/useElementWidth.d.ts.map +1 -0
  178. package/dist/esm/foundation/useElementWidth.js +29 -0
  179. package/dist/esm/foundation/useElementWidth.js.map +1 -0
  180. package/dist/esm/foundation/viewModel.d.ts +7 -0
  181. package/dist/esm/foundation/viewModel.d.ts.map +1 -0
  182. package/dist/esm/foundation/viewModel.js +22 -0
  183. package/dist/esm/foundation/viewModel.js.map +1 -0
  184. package/dist/esm/gallery/widgets.js +1 -1
  185. package/dist/esm/index.d.ts +1 -0
  186. package/dist/esm/index.d.ts.map +1 -1
  187. package/dist/esm/index.js +24 -0
  188. package/dist/esm/index.js.map +1 -1
  189. package/dist/esm/themes/dark.d.ts.map +1 -1
  190. package/dist/esm/themes/dark.js +9 -1
  191. package/dist/esm/themes/dark.js.map +1 -1
  192. package/dist/esm/themes/light.d.ts.map +1 -1
  193. package/dist/esm/themes/light.js +10 -2
  194. package/dist/esm/themes/light.js.map +1 -1
  195. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  196. package/foundation/ActionButton.tsx +39 -0
  197. package/foundation/ChartWrapper.tsx +252 -0
  198. package/foundation/ColumnChooser.tsx +73 -0
  199. package/foundation/ComponentState.ts +53 -0
  200. package/foundation/EmptyState.tsx +22 -0
  201. package/foundation/FilterBuilder.tsx +144 -0
  202. package/foundation/Foundation.stories.tsx +46 -0
  203. package/foundation/FoundationIcon.tsx +49 -0
  204. package/foundation/FoundationStates.tsx +46 -0
  205. package/foundation/PermissionRule.ts +26 -0
  206. package/foundation/SavedViewsMenu.tsx +94 -0
  207. package/foundation/StatCard.tsx +44 -0
  208. package/foundation/StateFrame.tsx +126 -0
  209. package/foundation/StatusChip.tsx +51 -0
  210. package/foundation/TrendChip.tsx +78 -0
  211. package/foundation/chartGeometry.ts +108 -0
  212. package/foundation/columnModel.ts +39 -0
  213. package/foundation/filterModel.ts +111 -0
  214. package/foundation/formatting.ts +69 -0
  215. package/foundation/foundationComponentMetadata.ts +21 -0
  216. package/foundation/foundationDescriptors.ts +204 -0
  217. package/foundation/foundationSamples.ts +63 -0
  218. package/foundation/foundationStrings.ts +137 -0
  219. package/foundation/index.ts +27 -0
  220. package/foundation/useElementWidth.ts +31 -0
  221. package/foundation/viewModel.ts +21 -0
  222. package/index.ts +1 -0
  223. package/package.json +9 -8
  224. package/shell/layout.css +526 -0
  225. package/themes/dark.ts +8 -0
  226. package/themes/light.ts +9 -1
@@ -0,0 +1,200 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var elementProperties = require('../shell/elementProperties.js');
5
+ var ActionButton = require('./ActionButton.js');
6
+ var ComponentState = require('./ComponentState.js');
7
+ var FoundationIcon = require('./FoundationIcon.js');
8
+ var foundationStrings = require('./foundationStrings.js');
9
+ var PermissionRule = require('./PermissionRule.js');
10
+ var formatting = require('./formatting.js');
11
+
12
+ // Copyright (c) Cratis. All rights reserved.
13
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
14
+ /** The accessible name of a region, from the element's `label` property. */ function regionLabel(element) {
15
+ return elementProperties.readOptionalString(element, 'label') ?? elementProperties.readOptionalString(element, 'title');
16
+ }
17
+ /**
18
+ * The root every foundation component renders, and the five standard states of spec Part B 1.4 in one place:
19
+ * a skeleton while loading (never a spinner alone), an explanation with the primary action when empty, a message with a
20
+ * retry on error, what is missing - and nothing of the data - when the user is not allowed, and the loaded part with a
21
+ * note naming what failed when only some regions did.
22
+ *
23
+ * The region carries an ARIA landmark role when it has a label, a `dir` is left to the document so right-to-left is
24
+ * inherited, and every piece of text comes from the strings table.
25
+ */ function FoundationFrame({ element, interactions, name, state, skeleton = [
26
+ 60,
27
+ 100,
28
+ 80
29
+ ], children }) {
30
+ const strings = foundationStrings.readFoundationStrings(element);
31
+ const label = regionLabel(element);
32
+ const density = element.properties.density === 'compact' ? 'compact' : 'comfortable';
33
+ return /*#__PURE__*/ jsxRuntime.jsx("section", {
34
+ className: `foundation foundation-${name}`,
35
+ "data-scene-id": element.id,
36
+ "data-state": state,
37
+ "data-density": density,
38
+ lang: formatting.readLocale(element),
39
+ role: label ? 'region' : undefined,
40
+ "aria-label": label,
41
+ "aria-busy": state === ComponentState.ComponentState.Loading || undefined,
42
+ children: renderState(element, interactions, strings, state, skeleton, children)
43
+ });
44
+ }
45
+ function renderState(element, interactions, strings, state, skeleton, children) {
46
+ switch(state){
47
+ case ComponentState.ComponentState.Loading:
48
+ return /*#__PURE__*/ jsxRuntime.jsxs("div", {
49
+ className: "foundation-skeleton",
50
+ role: "status",
51
+ children: [
52
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
53
+ className: "foundation-visually-hidden",
54
+ children: strings.loading
55
+ }),
56
+ skeleton.map((width, index)=>/*#__PURE__*/ jsxRuntime.jsx("span", {
57
+ className: "foundation-skeleton-block",
58
+ style: {
59
+ width: `${width}%`
60
+ },
61
+ "aria-hidden": "true"
62
+ }, index))
63
+ ]
64
+ });
65
+ case ComponentState.ComponentState.Empty:
66
+ return /*#__PURE__*/ jsxRuntime.jsx(EmptyStateView, {
67
+ element: element,
68
+ interactions: interactions,
69
+ strings: strings
70
+ });
71
+ case ComponentState.ComponentState.Error:
72
+ return /*#__PURE__*/ jsxRuntime.jsxs("div", {
73
+ className: "foundation-message",
74
+ "data-tone": "danger",
75
+ role: "alert",
76
+ children: [
77
+ /*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
78
+ name: "alert"
79
+ }),
80
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
81
+ className: "foundation-message-text",
82
+ children: [
83
+ /*#__PURE__*/ jsxRuntime.jsx("strong", {
84
+ children: strings.errorHeadline
85
+ }),
86
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
87
+ children: typeof element.properties.error === 'string' && element.properties.error.length > 0 ? element.properties.error : strings.errorHint
88
+ })
89
+ ]
90
+ }),
91
+ /*#__PURE__*/ jsxRuntime.jsx(ActionButton.ActionButton, {
92
+ emphasis: "secondary",
93
+ disabledReason: strings.disabledNoPermission,
94
+ onClick: interactions?.onClick,
95
+ children: strings.retry
96
+ })
97
+ ]
98
+ });
99
+ case ComponentState.ComponentState.NoPermission:
100
+ {
101
+ const subject = elementProperties.readOptionalString(element, 'permissionSubject') ?? strings.noPermissionSubject;
102
+ return /*#__PURE__*/ jsxRuntime.jsxs("div", {
103
+ className: "foundation-message",
104
+ "data-tone": "neutral",
105
+ role: "status",
106
+ children: [
107
+ /*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
108
+ name: "lock"
109
+ }),
110
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
111
+ className: "foundation-message-text",
112
+ children: [
113
+ /*#__PURE__*/ jsxRuntime.jsx("strong", {
114
+ children: strings.noPermissionHeadline
115
+ }),
116
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
117
+ children: foundationStrings.formatText(strings.noPermissionHint, {
118
+ subject
119
+ })
120
+ })
121
+ ]
122
+ })
123
+ ]
124
+ });
125
+ }
126
+ case ComponentState.ComponentState.Partial:
127
+ return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
128
+ children: [
129
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
130
+ className: "foundation-message",
131
+ "data-tone": "warning",
132
+ role: "status",
133
+ children: [
134
+ /*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
135
+ name: "alert"
136
+ }),
137
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
138
+ className: "foundation-message-text",
139
+ children: [
140
+ /*#__PURE__*/ jsxRuntime.jsx("strong", {
141
+ children: strings.partialHeadline
142
+ }),
143
+ elementProperties.readStrings(element, 'failedRegions').length > 0 && /*#__PURE__*/ jsxRuntime.jsx("span", {
144
+ children: foundationStrings.formatText(strings.partialHint, {
145
+ regions: elementProperties.readStrings(element, 'failedRegions').join(', ')
146
+ })
147
+ })
148
+ ]
149
+ }),
150
+ /*#__PURE__*/ jsxRuntime.jsx(ActionButton.ActionButton, {
151
+ emphasis: "secondary",
152
+ disabledReason: strings.disabledNoPermission,
153
+ onClick: interactions?.onClick,
154
+ children: strings.retry
155
+ })
156
+ ]
157
+ }),
158
+ children
159
+ ]
160
+ });
161
+ default:
162
+ return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
163
+ children: children
164
+ });
165
+ }
166
+ }
167
+ /** What an empty region says: an icon, a headline, a hint and the primary action, with the action's permission rule applied. */ function EmptyStateView({ element, interactions, strings }) {
168
+ const icon = elementProperties.readOptionalString(element, 'emptyIcon') ?? elementProperties.readOptionalString(element, 'icon');
169
+ const actionLabel = elementProperties.readOptionalString(element, 'emptyActionLabel') ?? elementProperties.readOptionalString(element, 'actionLabel');
170
+ return /*#__PURE__*/ jsxRuntime.jsxs("div", {
171
+ className: "foundation-empty",
172
+ role: "status",
173
+ children: [
174
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
175
+ className: "foundation-empty-icon",
176
+ children: /*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
177
+ name: icon ?? 'inbox'
178
+ })
179
+ }),
180
+ /*#__PURE__*/ jsxRuntime.jsx("strong", {
181
+ className: "foundation-empty-headline",
182
+ children: elementProperties.readOptionalString(element, 'emptyHeadline') ?? elementProperties.readOptionalString(element, 'headline') ?? strings.emptyHeadline
183
+ }),
184
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
185
+ className: "foundation-empty-hint",
186
+ children: elementProperties.readOptionalString(element, 'emptyHint') ?? elementProperties.readOptionalString(element, 'hint') ?? strings.emptyHint
187
+ }),
188
+ actionLabel && /*#__PURE__*/ jsxRuntime.jsx(ActionButton.ActionButton, {
189
+ rule: PermissionRule.readPermissionRule(element, 'actionPermission'),
190
+ disabledReason: strings.disabledNoPermission,
191
+ onClick: interactions?.onClick,
192
+ children: actionLabel
193
+ })
194
+ ]
195
+ });
196
+ }
197
+
198
+ exports.EmptyStateView = EmptyStateView;
199
+ exports.FoundationFrame = FoundationFrame;
200
+ //# sourceMappingURL=StateFrame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StateFrame.js","sources":["../../../foundation/StateFrame.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ReactNode } from 'react';\nimport { ExternalComponent } from '@cratis/scene.model';\nimport { RegisteredComponentProps } from '@cratis/scene.react';\nimport { readOptionalString, readStrings } from '../shell/elementProperties';\nimport { ActionButton } from './ActionButton';\nimport { ComponentState } from './ComponentState';\nimport { FoundationIcon, FoundationIconName } from './FoundationIcon';\nimport { FoundationStrings, formatText, readFoundationStrings } from './foundationStrings';\nimport { readPermissionRule } from './PermissionRule';\nimport { readLocale } from './formatting';\n\nexport interface FoundationFrameProps extends Pick<RegisteredComponentProps, 'element' | 'interactions'> {\n /** The component's own class, added after `foundation`. */\n name: string;\n\n /** The state the component is in; compute it with `readComponentState`. */\n state: ComponentState;\n\n /** The shape of the skeleton, as the width of each block in percent; the skeleton keeps the footprint of the content. */\n skeleton?: number[];\n\n /** What the component draws when it is ready or partial. */\n children?: ReactNode;\n}\n\n/** The accessible name of a region, from the element's `label` property. */\nfunction regionLabel(element: ExternalComponent): string | undefined {\n return readOptionalString(element, 'label') ?? readOptionalString(element, 'title');\n}\n\n/**\n * The root every foundation component renders, and the five standard states of spec Part B 1.4 in one place:\n * a skeleton while loading (never a spinner alone), an explanation with the primary action when empty, a message with a\n * retry on error, what is missing - and nothing of the data - when the user is not allowed, and the loaded part with a\n * note naming what failed when only some regions did.\n *\n * The region carries an ARIA landmark role when it has a label, a `dir` is left to the document so right-to-left is\n * inherited, and every piece of text comes from the strings table.\n */\nexport function FoundationFrame({ element, interactions, name, state, skeleton = [60, 100, 80], children }: FoundationFrameProps) {\n const strings = readFoundationStrings(element);\n const label = regionLabel(element);\n const density = element.properties.density === 'compact' ? 'compact' : 'comfortable';\n\n return (\n <section className={`foundation foundation-${name}`} data-scene-id={element.id} data-state={state} data-density={density}\n lang={readLocale(element)} role={label ? 'region' : undefined} aria-label={label} aria-busy={state === ComponentState.Loading || undefined}>\n {renderState(element, interactions, strings, state, skeleton, children)}\n </section>\n );\n}\n\nfunction renderState(element: ExternalComponent, interactions: RegisteredComponentProps['interactions'], strings: FoundationStrings, state: ComponentState, skeleton: number[], children: ReactNode) {\n switch (state) {\n case ComponentState.Loading:\n return (\n <div className='foundation-skeleton' role='status'>\n <span className='foundation-visually-hidden'>{strings.loading}</span>\n {skeleton.map((width, index) => <span key={index} className='foundation-skeleton-block' style={{ width: `${width}%` }} aria-hidden='true' />)}\n </div>\n );\n case ComponentState.Empty:\n return <EmptyStateView element={element} interactions={interactions} strings={strings} />;\n case ComponentState.Error:\n return (\n <div className='foundation-message' data-tone='danger' role='alert'>\n <FoundationIcon name='alert' />\n <div className='foundation-message-text'>\n <strong>{strings.errorHeadline}</strong>\n <span>{typeof element.properties.error === 'string' && element.properties.error.length > 0 ? element.properties.error : strings.errorHint}</span>\n </div>\n <ActionButton emphasis='secondary' disabledReason={strings.disabledNoPermission} onClick={interactions?.onClick}>{strings.retry}</ActionButton>\n </div>\n );\n case ComponentState.NoPermission: {\n const subject = readOptionalString(element, 'permissionSubject') ?? strings.noPermissionSubject;\n return (\n <div className='foundation-message' data-tone='neutral' role='status'>\n <FoundationIcon name='lock' />\n <div className='foundation-message-text'>\n <strong>{strings.noPermissionHeadline}</strong>\n <span>{formatText(strings.noPermissionHint, { subject })}</span>\n </div>\n </div>\n );\n }\n\n case ComponentState.Partial:\n return (\n <>\n <div className='foundation-message' data-tone='warning' role='status'>\n <FoundationIcon name='alert' />\n <div className='foundation-message-text'>\n <strong>{strings.partialHeadline}</strong>\n {readStrings(element, 'failedRegions').length > 0 && <span>{formatText(strings.partialHint, { regions: readStrings(element, 'failedRegions').join(', ') })}</span>}\n </div>\n <ActionButton emphasis='secondary' disabledReason={strings.disabledNoPermission} onClick={interactions?.onClick}>{strings.retry}</ActionButton>\n </div>\n {children}\n </>\n );\n default:\n return <>{children}</>;\n }\n}\n\n/** What an empty region says: an icon, a headline, a hint and the primary action, with the action's permission rule applied. */\nexport function EmptyStateView({ element, interactions, strings }: Pick<FoundationFrameProps, 'element' | 'interactions'> & { strings: FoundationStrings }) {\n const icon = (readOptionalString(element, 'emptyIcon') ?? readOptionalString(element, 'icon')) as FoundationIconName | undefined;\n const actionLabel = readOptionalString(element, 'emptyActionLabel') ?? readOptionalString(element, 'actionLabel');\n\n return (\n <div className='foundation-empty' role='status'>\n <span className='foundation-empty-icon'><FoundationIcon name={icon ?? 'inbox'} /></span>\n <strong className='foundation-empty-headline'>{readOptionalString(element, 'emptyHeadline') ?? readOptionalString(element, 'headline') ?? strings.emptyHeadline}</strong>\n <span className='foundation-empty-hint'>{readOptionalString(element, 'emptyHint') ?? readOptionalString(element, 'hint') ?? strings.emptyHint}</span>\n {actionLabel && (\n <ActionButton rule={readPermissionRule(element, 'actionPermission')} disabledReason={strings.disabledNoPermission} onClick={interactions?.onClick}>{actionLabel}</ActionButton>\n )}\n </div>\n );\n}\n\n"],"names":["regionLabel","element","readOptionalString","FoundationFrame","interactions","name","state","skeleton","children","strings","readFoundationStrings","label","density","properties","_jsx","section","className","data-scene-id","id","data-state","data-density","lang","readLocale","role","undefined","aria-label","aria-busy","ComponentState","Loading","renderState","_jsxs","div","span","loading","map","width","index","style","aria-hidden","Empty","EmptyStateView","Error","data-tone","FoundationIcon","strong","errorHeadline","error","length","errorHint","ActionButton","emphasis","disabledReason","disabledNoPermission","onClick","retry","NoPermission","subject","noPermissionSubject","noPermissionHeadline","formatText","noPermissionHint","Partial","_Fragment","partialHeadline","readStrings","partialHint","regions","join","icon","actionLabel","emptyHeadline","emptyHint","rule","readPermissionRule"],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var foundationStrings = require('./foundationStrings.js');
5
+ var FoundationIcon = require('./FoundationIcon.js');
6
+ var elementProperties = require('../shell/elementProperties.js');
7
+
8
+ // Copyright (c) Cratis. All rights reserved.
9
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
10
+ /** The semantic tone of a status. */ var StatusTone = /*#__PURE__*/ function(StatusTone) {
11
+ StatusTone["Success"] = "success";
12
+ StatusTone["Warning"] = "warning";
13
+ StatusTone["Danger"] = "danger";
14
+ StatusTone["Info"] = "info";
15
+ StatusTone["Neutral"] = "neutral";
16
+ return StatusTone;
17
+ }({});
18
+ /** The icon each tone gets, so a status is told by shape as well as color (WCAG 1.4.1). */ const statusToneIcons = {
19
+ ["success"]: 'check',
20
+ ["warning"]: 'alert',
21
+ ["danger"]: 'close',
22
+ ["info"]: 'info',
23
+ ["neutral"]: 'circle'
24
+ };
25
+ /** Reads a tone, defaulting to Neutral. */ function readStatusTone(value) {
26
+ return Object.values(StatusTone).includes(value) ? value : "neutral";
27
+ }
28
+ /**
29
+ * The `statusChip` component: a status as a semantic color, an icon and its text.
30
+ *
31
+ * The text is always shown - the status of a record is never only a colored dot - and the tone picks the icon and the color from
32
+ * the theme's status tokens. A status the application names ("Awaiting approval") is its own `status` text; `tone` maps it onto
33
+ * one of the five tones.
34
+ */ function StatusChip({ element }) {
35
+ const tone = readStatusTone(element.properties.tone);
36
+ const strings = foundationStrings.readFoundationStrings(element);
37
+ const fallback = {
38
+ success: strings.statusSuccess,
39
+ warning: strings.statusWarning,
40
+ danger: strings.statusDanger,
41
+ info: strings.statusInfo,
42
+ neutral: strings.statusNeutral
43
+ }[tone];
44
+ const text = elementProperties.readString(element, 'status', elementProperties.readOptionalString(element, 'label') ?? fallback);
45
+ return /*#__PURE__*/ jsxRuntime.jsxs("span", {
46
+ className: "foundation foundation-chip foundation-status-chip",
47
+ "data-scene-id": element.id,
48
+ "data-tone": tone,
49
+ children: [
50
+ /*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
51
+ name: statusToneIcons[tone]
52
+ }),
53
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
54
+ children: text
55
+ })
56
+ ]
57
+ });
58
+ }
59
+
60
+ exports.StatusChip = StatusChip;
61
+ exports.StatusTone = StatusTone;
62
+ exports.readStatusTone = readStatusTone;
63
+ exports.statusToneIcons = statusToneIcons;
64
+ //# sourceMappingURL=StatusChip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusChip.js","sources":["../../../foundation/StatusChip.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { RegisteredComponentProps } from '@cratis/scene.react';\nimport { readFoundationStrings } from './foundationStrings';\nimport { FoundationIcon, FoundationIconName } from './FoundationIcon';\nimport { readOptionalString, readString } from '../shell/elementProperties';\n\n/** The semantic tone of a status. */\nexport enum StatusTone {\n Success = 'success',\n Warning = 'warning',\n Danger = 'danger',\n Info = 'info',\n Neutral = 'neutral',\n}\n\n/** The icon each tone gets, so a status is told by shape as well as color (WCAG 1.4.1). */\nexport const statusToneIcons: Record<StatusTone, FoundationIconName> = {\n [StatusTone.Success]: 'check',\n [StatusTone.Warning]: 'alert',\n [StatusTone.Danger]: 'close',\n [StatusTone.Info]: 'info',\n [StatusTone.Neutral]: 'circle',\n};\n\n/** Reads a tone, defaulting to Neutral. */\nexport function readStatusTone(value: unknown): StatusTone {\n return (Object.values(StatusTone) as string[]).includes(value as string) ? (value as StatusTone) : StatusTone.Neutral;\n}\n\n/**\n * The `statusChip` component: a status as a semantic color, an icon and its text.\n *\n * The text is always shown - the status of a record is never only a colored dot - and the tone picks the icon and the color from\n * the theme's status tokens. A status the application names (\"Awaiting approval\") is its own `status` text; `tone` maps it onto\n * one of the five tones.\n */\nexport function StatusChip({ element }: RegisteredComponentProps) {\n const tone = readStatusTone(element.properties.tone);\n const strings = readFoundationStrings(element);\n const fallback = { success: strings.statusSuccess, warning: strings.statusWarning, danger: strings.statusDanger, info: strings.statusInfo, neutral: strings.statusNeutral }[tone];\n const text = readString(element, 'status', readOptionalString(element, 'label') ?? fallback);\n\n return (\n <span className='foundation foundation-chip foundation-status-chip' data-scene-id={element.id} data-tone={tone}>\n <FoundationIcon name={statusToneIcons[tone]} />\n <span>{text}</span>\n </span>\n );\n}\n"],"names":["StatusTone","statusToneIcons","readStatusTone","value","Object","values","includes","StatusChip","element","tone","properties","strings","readFoundationStrings","fallback","success","statusSuccess","warning","statusWarning","danger","statusDanger","info","statusInfo","neutral","statusNeutral","text","readString","readOptionalString","_jsxs","span","className","data-scene-id","id","data-tone","_jsx","FoundationIcon","name"],"mappings":";;;;;;;AAAA;AACA;AAOA,sCACO,IAAKA,UAAAA,iBAAAA,SAAAA,UAAAA,EAAAA;;;;;;AAAAA,IAAAA,OAAAA,UAAAA;AAMX,CAAA,CAAA,EAAA;AAED,4FACO,MAAMC,eAAAA,GAA0D;AACnE,IAAA,CAAA,SAAA,GAAsB,OAAA;AACtB,IAAA,CAAA,SAAA,GAAsB,OAAA;AACtB,IAAA,CAAA,QAAA,GAAqB,OAAA;AACrB,IAAA,CAAA,MAAA,GAAmB,MAAA;AACnB,IAAA,CAAA,SAAA,GAAsB;AAC1B;AAEA,4CACO,SAASC,cAAAA,CAAeC,KAAc,EAAA;AACzC,IAAA,OAAO,MAACC,CAAOC,MAAM,CAACL,UAAAA,CAAAA,CAAyBM,QAAQ,CAACH,KAAAA,CAAAA,GAAoBA,KAAAA,GAAAA,SAAAA;AAChF;AAEA;;;;;;AAMC,IACM,SAASI,UAAAA,CAAW,EAAEC,OAAO,EAA4B,EAAA;AAC5D,IAAA,MAAMC,IAAAA,GAAOP,cAAAA,CAAeM,OAAAA,CAAQE,UAAU,CAACD,IAAI,CAAA;AACnD,IAAA,MAAME,UAAUC,uCAAAA,CAAsBJ,OAAAA,CAAAA;AACtC,IAAA,MAAMK,QAAAA,GAAW;AAAEC,QAAAA,OAAAA,EAASH,QAAQI,aAAa;AAAEC,QAAAA,OAAAA,EAASL,QAAQM,aAAa;AAAEC,QAAAA,MAAAA,EAAQP,QAAQQ,YAAY;AAAEC,QAAAA,IAAAA,EAAMT,QAAQU,UAAU;AAAEC,QAAAA,OAAAA,EAASX,QAAQY;AAAc,KAAC,CAACd,IAAAA,CAAK;AACjL,IAAA,MAAMe,OAAOC,4BAAAA,CAAWjB,OAAAA,EAAS,QAAA,EAAUkB,oCAAAA,CAAmBlB,SAAS,OAAA,CAAA,IAAYK,QAAAA,CAAAA;AAEnF,IAAA,qBACIc,eAAA,CAACC,MAAAA,EAAAA;QAAKC,SAAAA,EAAU,mDAAA;AAAoDC,QAAAA,eAAAA,EAAetB,QAAQuB,EAAE;QAAEC,WAAAA,EAAWvB,IAAAA;;0BACtGwB,cAAA,CAACC,6BAAAA,EAAAA;gBAAeC,IAAAA,EAAMlC,eAAe,CAACQ,IAAAA;;0BACtCwB,cAAA,CAACL,MAAAA,EAAAA;AAAMJ,gBAAAA,QAAAA,EAAAA;;;;AAGnB;;;;;"}
@@ -0,0 +1,93 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var FoundationIcon = require('./FoundationIcon.js');
5
+ var formatting = require('./formatting.js');
6
+ var foundationStrings = require('./foundationStrings.js');
7
+ var elementProperties = require('../shell/elementProperties.js');
8
+
9
+ // Copyright (c) Cratis. All rights reserved.
10
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
11
+ /** The direction a change moved in. */ function trendDirection(change) {
12
+ return change > 0 ? 'up' : change < 0 ? 'down' : 'flat';
13
+ }
14
+ /** Whether a movement is good for a measure, given which direction is the good one. */ function trendOutcome(direction, goodDirection) {
15
+ return direction === 'flat' ? 'neutral' : direction === goodDirection ? 'good' : 'bad';
16
+ }
17
+ /** The tone each outcome is drawn in. */ const tones = {
18
+ good: 'success',
19
+ bad: 'danger',
20
+ neutral: 'neutral'
21
+ };
22
+ /**
23
+ * A change, drawn as an arrow, the change and what it is compared to.
24
+ *
25
+ * Color says whether the movement is good, but never alone: the arrow gives direction and a visually hidden sentence
26
+ * says all of it ("up 12.5% compared to last month"), so the chip reads the same without color.
27
+ */ function TrendChipView({ change, locale, goodDirection = 'up', comparison, format = formatting.NumberFormat.Percent, strings }) {
28
+ const direction = trendDirection(change);
29
+ const outcome = trendOutcome(direction, goodDirection);
30
+ const magnitude = formatting.formatNumber(Math.abs(change), locale, format);
31
+ const spoken = direction === 'flat' ? strings.trendFlat : foundationStrings.formatText(direction === 'up' ? strings.trendUp : strings.trendDown, {
32
+ value: magnitude
33
+ });
34
+ return /*#__PURE__*/ jsxRuntime.jsxs("span", {
35
+ className: "foundation-chip foundation-trend",
36
+ "data-tone": tones[outcome],
37
+ "data-direction": direction,
38
+ children: [
39
+ /*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
40
+ name: direction === 'up' ? 'arrow-up' : direction === 'down' ? 'arrow-down' : 'minus'
41
+ }),
42
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
43
+ "aria-hidden": "true",
44
+ children: direction === 'flat' ? magnitude : magnitude
45
+ }),
46
+ /*#__PURE__*/ jsxRuntime.jsxs("span", {
47
+ className: "foundation-visually-hidden",
48
+ children: [
49
+ spoken,
50
+ comparison ? ` ${foundationStrings.formatText(strings.trendComparison, {
51
+ period: comparison
52
+ })}` : ''
53
+ ]
54
+ }),
55
+ comparison && /*#__PURE__*/ jsxRuntime.jsx("span", {
56
+ className: "foundation-trend-comparison",
57
+ "aria-hidden": "true",
58
+ children: foundationStrings.formatText(strings.trendComparison, {
59
+ period: comparison
60
+ })
61
+ })
62
+ ]
63
+ });
64
+ }
65
+ /**
66
+ * The `trendChip` component: a change with its direction, whether that is good, and what it is compared to.
67
+ *
68
+ * `change` is the movement as a number (a percentage by default), `goodDirection` says which way is good, and `comparison` names
69
+ * the period. Without a number the chip is empty, and then it draws nothing rather than an invented zero.
70
+ */ function TrendChip({ element }) {
71
+ const change = element.properties.change;
72
+ if (typeof change !== 'number') return undefined;
73
+ return /*#__PURE__*/ jsxRuntime.jsx("span", {
74
+ className: "foundation foundation-trend-chip",
75
+ "data-scene-id": element.id,
76
+ children: /*#__PURE__*/ jsxRuntime.jsx(TrendChipView, {
77
+ change: change,
78
+ locale: formatting.readLocale(element),
79
+ goodDirection: element.properties.goodDirection === 'down' ? 'down' : 'up',
80
+ comparison: elementProperties.readOptionalString(element, 'comparison'),
81
+ strings: foundationStrings.readFoundationStrings(element),
82
+ ...typeof element.properties.format === 'string' && Object.values(formatting.NumberFormat).includes(element.properties.format) ? {
83
+ format: element.properties.format
84
+ } : {}
85
+ })
86
+ });
87
+ }
88
+
89
+ exports.TrendChip = TrendChip;
90
+ exports.TrendChipView = TrendChipView;
91
+ exports.trendDirection = trendDirection;
92
+ exports.trendOutcome = trendOutcome;
93
+ //# sourceMappingURL=TrendChip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TrendChip.js","sources":["../../../foundation/TrendChip.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { RegisteredComponentProps } from '@cratis/scene.react';\nimport { FoundationIcon } from './FoundationIcon';\nimport { formatNumber, NumberFormat, readLocale } from './formatting';\nimport { formatText, readFoundationStrings } from './foundationStrings';\nimport { readOptionalString } from '../shell/elementProperties';\n\n/** The direction a measure moved. */\nexport type TrendDirection = 'up' | 'down' | 'flat';\n\n/** Whether a movement is good, bad or neither, which is independent of whether the number rose: falling response time is good. */\nexport type TrendOutcome = 'good' | 'bad' | 'neutral';\n\n/** The direction a change moved in. */\nexport function trendDirection(change: number): TrendDirection {\n return change > 0 ? 'up' : change < 0 ? 'down' : 'flat';\n}\n\n/** Whether a movement is good for a measure, given which direction is the good one. */\nexport function trendOutcome(direction: TrendDirection, goodDirection: 'up' | 'down'): TrendOutcome {\n return direction === 'flat' ? 'neutral' : direction === goodDirection ? 'good' : 'bad';\n}\n\n/** The tone each outcome is drawn in. */\nconst tones: Record<TrendOutcome, string> = { good: 'success', bad: 'danger', neutral: 'neutral' };\n\n/** The props of a trend chip drawn directly, as the stat card does. */\nexport interface TrendChipViewProps {\n change: number;\n locale: string;\n goodDirection?: 'up' | 'down';\n comparison?: string;\n format?: NumberFormat;\n strings: ReturnType<typeof readFoundationStrings>;\n}\n\n/**\n * A change, drawn as an arrow, the change and what it is compared to.\n *\n * Color says whether the movement is good, but never alone: the arrow gives direction and a visually hidden sentence\n * says all of it (\"up 12.5% compared to last month\"), so the chip reads the same without color.\n */\nexport function TrendChipView({ change, locale, goodDirection = 'up', comparison, format = NumberFormat.Percent, strings }: TrendChipViewProps) {\n const direction = trendDirection(change);\n const outcome = trendOutcome(direction, goodDirection);\n const magnitude = formatNumber(Math.abs(change), locale, format);\n const spoken = direction === 'flat' ? strings.trendFlat : formatText(direction === 'up' ? strings.trendUp : strings.trendDown, { value: magnitude });\n\n return (\n <span className='foundation-chip foundation-trend' data-tone={tones[outcome]} data-direction={direction}>\n <FoundationIcon name={direction === 'up' ? 'arrow-up' : direction === 'down' ? 'arrow-down' : 'minus'} />\n <span aria-hidden='true'>{direction === 'flat' ? magnitude : magnitude}</span>\n <span className='foundation-visually-hidden'>{spoken}{comparison ? ` ${formatText(strings.trendComparison, { period: comparison })}` : ''}</span>\n {comparison && <span className='foundation-trend-comparison' aria-hidden='true'>{formatText(strings.trendComparison, { period: comparison })}</span>}\n </span>\n );\n}\n\n/**\n * The `trendChip` component: a change with its direction, whether that is good, and what it is compared to.\n *\n * `change` is the movement as a number (a percentage by default), `goodDirection` says which way is good, and `comparison` names\n * the period. Without a number the chip is empty, and then it draws nothing rather than an invented zero.\n */\nexport function TrendChip({ element }: RegisteredComponentProps) {\n const change = element.properties.change;\n if (typeof change !== 'number') return undefined;\n\n return (\n <span className='foundation foundation-trend-chip' data-scene-id={element.id}>\n <TrendChipView change={change} locale={readLocale(element)} goodDirection={element.properties.goodDirection === 'down' ? 'down' : 'up'}\n comparison={readOptionalString(element, 'comparison')} strings={readFoundationStrings(element)}\n {...(typeof element.properties.format === 'string' && (Object.values(NumberFormat) as string[]).includes(element.properties.format) ? { format: element.properties.format as NumberFormat } : {})} />\n </span>\n );\n}\n"],"names":["trendDirection","change","trendOutcome","direction","goodDirection","tones","good","bad","neutral","TrendChipView","locale","comparison","format","NumberFormat","Percent","strings","outcome","magnitude","formatNumber","Math","abs","spoken","trendFlat","formatText","trendUp","trendDown","value","_jsxs","span","className","data-tone","data-direction","_jsx","FoundationIcon","name","aria-hidden","trendComparison","period","TrendChip","element","properties","undefined","data-scene-id","id","readLocale","readOptionalString","readFoundationStrings","Object","values","includes"],"mappings":";;;;;;;;AAAA;AACA;AAcA,wCACO,SAASA,cAAAA,CAAeC,MAAc,EAAA;AACzC,IAAA,OAAOA,MAAAA,GAAS,CAAA,GAAI,IAAA,GAAOA,MAAAA,GAAS,IAAI,MAAA,GAAS,MAAA;AACrD;AAEA,wFACO,SAASC,YAAAA,CAAaC,SAAyB,EAAEC,aAA4B,EAAA;AAChF,IAAA,OAAOD,SAAAA,KAAc,MAAA,GAAS,SAAA,GAAYA,SAAAA,KAAcC,gBAAgB,MAAA,GAAS,KAAA;AACrF;AAEA,0CACA,MAAMC,KAAAA,GAAsC;IAAEC,IAAAA,EAAM,SAAA;IAAWC,GAAAA,EAAK,QAAA;IAAUC,OAAAA,EAAS;AAAU,CAAA;AAYjG;;;;;AAKC,IACM,SAASC,aAAAA,CAAc,EAAER,MAAM,EAAES,MAAM,EAAEN,aAAAA,GAAgB,IAAI,EAAEO,UAAU,EAAEC,MAAAA,GAASC,wBAAaC,OAAO,EAAEC,OAAO,EAAsB,EAAA;AAC1I,IAAA,MAAMZ,YAAYH,cAAAA,CAAeC,MAAAA,CAAAA;IACjC,MAAMe,OAAAA,GAAUd,aAAaC,SAAAA,EAAWC,aAAAA,CAAAA;AACxC,IAAA,MAAMa,YAAYC,uBAAAA,CAAaC,IAAAA,CAAKC,GAAG,CAACnB,SAASS,MAAAA,EAAQE,MAAAA,CAAAA;AACzD,IAAA,MAAMS,MAAAA,GAASlB,SAAAA,KAAc,MAAA,GAASY,OAAAA,CAAQO,SAAS,GAAGC,4BAAAA,CAAWpB,SAAAA,KAAc,IAAA,GAAOY,OAAAA,CAAQS,OAAO,GAAGT,OAAAA,CAAQU,SAAS,EAAE;QAAEC,KAAAA,EAAOT;AAAU,KAAA,CAAA;AAElJ,IAAA,qBACIU,eAAA,CAACC,MAAAA,EAAAA;QAAKC,SAAAA,EAAU,kCAAA;QAAmCC,WAAAA,EAAWzB,KAAK,CAACW,OAAAA,CAAQ;QAAEe,gBAAAA,EAAgB5B,SAAAA;;0BAC1F6B,cAAA,CAACC,6BAAAA,EAAAA;AAAeC,gBAAAA,IAAAA,EAAM/B,SAAAA,KAAc,IAAA,GAAO,UAAA,GAAaA,SAAAA,KAAc,SAAS,YAAA,GAAe;;0BAC9F6B,cAAA,CAACJ,MAAAA,EAAAA;gBAAKO,aAAAA,EAAY,MAAA;AAAQhC,gBAAAA,QAAAA,EAAAA,SAAAA,KAAc,SAASc,SAAAA,GAAYA;;0BAC7DU,eAAA,CAACC,MAAAA,EAAAA;gBAAKC,SAAAA,EAAU,4BAAA;;AAA8BR,oBAAAA,MAAAA;AAAQV,oBAAAA,UAAAA,GAAa,CAAC,CAAC,EAAEY,4BAAAA,CAAWR,OAAAA,CAAQqB,eAAe,EAAE;wBAAEC,MAAAA,EAAQ1B;AAAW,qBAAA,CAAA,CAAA,CAAI,GAAG;;;AACtIA,YAAAA,UAAAA,kBAAcqB,cAAA,CAACJ,MAAAA,EAAAA;gBAAKC,SAAAA,EAAU,6BAAA;gBAA8BM,aAAAA,EAAY,MAAA;0BAAQZ,4BAAAA,CAAWR,OAAAA,CAAQqB,eAAe,EAAE;oBAAEC,MAAAA,EAAQ1B;AAAW,iBAAA;;;;AAGtJ;AAEA;;;;;AAKC,IACM,SAAS2B,SAAAA,CAAU,EAAEC,OAAO,EAA4B,EAAA;AAC3D,IAAA,MAAMtC,MAAAA,GAASsC,OAAAA,CAAQC,UAAU,CAACvC,MAAM;IACxC,IAAI,OAAOA,MAAAA,KAAW,QAAA,EAAU,OAAOwC,SAAAA;AAEvC,IAAA,qBACIT,cAAA,CAACJ,MAAAA,EAAAA;QAAKC,SAAAA,EAAU,kCAAA;AAAmCa,QAAAA,eAAAA,EAAeH,QAAQI,EAAE;AACxE,QAAA,QAAA,gBAAAX,cAAA,CAACvB,aAAAA,EAAAA;YAAcR,MAAAA,EAAQA,MAAAA;AAAQS,YAAAA,MAAAA,EAAQkC,qBAAAA,CAAWL,OAAAA,CAAAA;AAAUnC,YAAAA,aAAAA,EAAemC,QAAQC,UAAU,CAACpC,aAAa,KAAK,SAAS,MAAA,GAAS,IAAA;AAC9HO,YAAAA,UAAAA,EAAYkC,qCAAmBN,OAAAA,EAAS,YAAA,CAAA;AAAexB,YAAAA,OAAAA,EAAS+B,uCAAAA,CAAsBP,OAAAA,CAAAA;AACrF,YAAA,GAAI,OAAOA,OAAAA,CAAQC,UAAU,CAAC5B,MAAM,KAAK,YAAY,MAACmC,CAAOC,MAAM,CAACnC,yBAA2BoC,QAAQ,CAACV,QAAQC,UAAU,CAAC5B,MAAM,CAAA,GAAI;gBAAEA,MAAAA,EAAQ2B,OAAAA,CAAQC,UAAU,CAAC5B;AAAuB,aAAA,GAAI;;;AAG9M;;;;;"}
@@ -0,0 +1,101 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /** The kinds of chart the wrapper draws (spec Part B 2.3: line, bar, stacked, donut, funnel). */ var ChartKind = /*#__PURE__*/ function(ChartKind) {
6
+ ChartKind["Line"] = "line";
7
+ ChartKind["Bar"] = "bar";
8
+ ChartKind["Stacked"] = "stacked";
9
+ ChartKind["Donut"] = "donut";
10
+ ChartKind["Funnel"] = "funnel";
11
+ return ChartKind;
12
+ }({});
13
+ /** Builds a scale from zero to a rounded-up maximum of the values, in about `target` steps. */ function niceScale(maximum, target = 4) {
14
+ if (!Number.isFinite(maximum) || maximum <= 0) return {
15
+ maximum: 1,
16
+ ticks: [
17
+ 0,
18
+ 1
19
+ ]
20
+ };
21
+ const rough = maximum / target;
22
+ const magnitude = 10 ** Math.floor(Math.log10(rough));
23
+ const residual = rough / magnitude;
24
+ const step = (residual <= 1 ? 1 : residual <= 2 ? 2 : residual <= 5 ? 5 : 10) * magnitude;
25
+ const top = Math.ceil(maximum / step) * step;
26
+ const ticks = [];
27
+ for(let tick = 0; tick <= top + step / 2; tick += step)ticks.push(Number(tick.toFixed(10)));
28
+ return {
29
+ maximum: top,
30
+ ticks
31
+ };
32
+ }
33
+ /** Reads series out of a property value, dropping anything that is not a named list of numbers, so a half-bound chart draws what it has. */ function readSeries(value) {
34
+ if (!Array.isArray(value)) return [];
35
+ return value.flatMap((entry)=>{
36
+ if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) return [];
37
+ const { name, values } = entry;
38
+ if (typeof name !== 'string' || !Array.isArray(values)) return [];
39
+ return [
40
+ {
41
+ name,
42
+ values: values.map((item)=>typeof item === 'number' && Number.isFinite(item) ? item : 0)
43
+ }
44
+ ];
45
+ });
46
+ }
47
+ /** The extent of the values a chart of this kind has to fit: stacked series add up, the others are compared one by one. */ function dataMaximum(kind, series, categoryCount) {
48
+ if (kind === "stacked") {
49
+ return Math.max(0, ...Array.from({
50
+ length: categoryCount
51
+ }, (_, index)=>series.reduce((sum, item)=>sum + Math.max(0, item.values[index] ?? 0), 0)));
52
+ }
53
+ return Math.max(0, ...series.flatMap((item)=>item.values));
54
+ }
55
+ /** Divides the positive values into slices that together make one turn. */ function donutSlices(values) {
56
+ const positive = values.map((value)=>Math.max(0, value));
57
+ const total = positive.reduce((sum, value)=>sum + value, 0);
58
+ if (total === 0) return [];
59
+ let angle = 0;
60
+ return positive.flatMap((value, index)=>{
61
+ if (value === 0) return [];
62
+ const share = value / total;
63
+ const slice = {
64
+ index,
65
+ value,
66
+ share,
67
+ start: angle,
68
+ end: angle + share * Math.PI * 2
69
+ };
70
+ angle = slice.end;
71
+ return [
72
+ slice
73
+ ];
74
+ });
75
+ }
76
+ /** The SVG path of a ring segment between two radii; a full turn is drawn as two halves, because one arc cannot start and end on the same point. */ function ringPath(centerX, centerY, outer, inner, start, end) {
77
+ const point = (radius, angle)=>`${(centerX + radius * Math.sin(angle)).toFixed(2)} ${(centerY - radius * Math.cos(angle)).toFixed(2)}`;
78
+ if (end - start >= Math.PI * 2 - 1e-6) {
79
+ const middle = start + Math.PI;
80
+ return `${ringPath(centerX, centerY, outer, inner, start, middle)} ${ringPath(centerX, centerY, outer, inner, middle, end)}`;
81
+ }
82
+ const large = end - start > Math.PI ? 1 : 0;
83
+ return `M ${point(outer, start)} A ${outer} ${outer} 0 ${large} 1 ${point(outer, end)} L ${point(inner, end)} A ${inner} ${inner} 0 ${large} 0 ${point(inner, start)} Z`;
84
+ }
85
+ /** Sizes the stages of a funnel against the largest value. */ function funnelStages(values) {
86
+ const maximum = Math.max(0, ...values);
87
+ return values.map((value, index)=>({
88
+ index,
89
+ value,
90
+ widthRatio: maximum === 0 ? 0 : Math.max(0, value) / maximum
91
+ }));
92
+ }
93
+
94
+ exports.ChartKind = ChartKind;
95
+ exports.dataMaximum = dataMaximum;
96
+ exports.donutSlices = donutSlices;
97
+ exports.funnelStages = funnelStages;
98
+ exports.niceScale = niceScale;
99
+ exports.readSeries = readSeries;
100
+ exports.ringPath = ringPath;
101
+ //# sourceMappingURL=chartGeometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chartGeometry.js","sources":["../../../foundation/chartGeometry.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/** The kinds of chart the wrapper draws (spec Part B 2.3: line, bar, stacked, donut, funnel). */\nexport enum ChartKind {\n Line = 'line',\n Bar = 'bar',\n Stacked = 'stacked',\n Donut = 'donut',\n Funnel = 'funnel',\n}\n\n/** One named series of values, one per category. */\nexport interface ChartSeries {\n name: string;\n values: number[];\n}\n\n/** A rounded-up axis maximum and the tick values below it, so an axis reads 0, 25, 50, 75, 100 and not 0, 23.4, 46.8. */\nexport interface ChartScale {\n maximum: number;\n ticks: number[];\n}\n\n/** Builds a scale from zero to a rounded-up maximum of the values, in about `target` steps. */\nexport function niceScale(maximum: number, target = 4): ChartScale {\n if (!Number.isFinite(maximum) || maximum <= 0) return { maximum: 1, ticks: [0, 1] };\n\n const rough = maximum / target;\n const magnitude = 10 ** Math.floor(Math.log10(rough));\n const residual = rough / magnitude;\n const step = (residual <= 1 ? 1 : residual <= 2 ? 2 : residual <= 5 ? 5 : 10) * magnitude;\n const top = Math.ceil(maximum / step) * step;\n const ticks: number[] = [];\n for (let tick = 0; tick <= top + step / 2; tick += step) ticks.push(Number(tick.toFixed(10)));\n return { maximum: top, ticks };\n}\n\n/** Reads series out of a property value, dropping anything that is not a named list of numbers, so a half-bound chart draws what it has. */\nexport function readSeries(value: unknown): ChartSeries[] {\n if (!Array.isArray(value)) return [];\n\n return value.flatMap((entry): ChartSeries[] => {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) return [];\n const { name, values } = entry as Record<string, unknown>;\n if (typeof name !== 'string' || !Array.isArray(values)) return [];\n return [{ name, values: values.map(item => (typeof item === 'number' && Number.isFinite(item) ? item : 0)) }];\n });\n}\n\n/** The extent of the values a chart of this kind has to fit: stacked series add up, the others are compared one by one. */\nexport function dataMaximum(kind: ChartKind, series: ChartSeries[], categoryCount: number): number {\n if (kind === ChartKind.Stacked) {\n return Math.max(0, ...Array.from({ length: categoryCount }, (_, index) => series.reduce((sum, item) => sum + Math.max(0, item.values[index] ?? 0), 0)));\n }\n\n return Math.max(0, ...series.flatMap(item => item.values));\n}\n\n/** A slice of a donut, in radians clockwise from the top. */\nexport interface DonutSlice {\n index: number;\n value: number;\n share: number;\n start: number;\n end: number;\n}\n\n/** Divides the positive values into slices that together make one turn. */\nexport function donutSlices(values: number[]): DonutSlice[] {\n const positive = values.map(value => Math.max(0, value));\n const total = positive.reduce((sum, value) => sum + value, 0);\n if (total === 0) return [];\n\n let angle = 0;\n return positive.flatMap((value, index) => {\n if (value === 0) return [];\n const share = value / total;\n const slice = { index, value, share, start: angle, end: angle + share * Math.PI * 2 };\n angle = slice.end;\n return [slice];\n });\n}\n\n/** The SVG path of a ring segment between two radii; a full turn is drawn as two halves, because one arc cannot start and end on the same point. */\nexport function ringPath(centerX: number, centerY: number, outer: number, inner: number, start: number, end: number): string {\n const point = (radius: number, angle: number) => `${(centerX + radius * Math.sin(angle)).toFixed(2)} ${(centerY - radius * Math.cos(angle)).toFixed(2)}`;\n if (end - start >= Math.PI * 2 - 1e-6) {\n const middle = start + Math.PI;\n return `${ringPath(centerX, centerY, outer, inner, start, middle)} ${ringPath(centerX, centerY, outer, inner, middle, end)}`;\n }\n\n const large = end - start > Math.PI ? 1 : 0;\n return `M ${point(outer, start)} A ${outer} ${outer} 0 ${large} 1 ${point(outer, end)} L ${point(inner, end)} A ${inner} ${inner} 0 ${large} 0 ${point(inner, start)} Z`;\n}\n\n/** One stage of a funnel: a centered bar whose width is its share of the widest stage. */\nexport interface FunnelStage {\n index: number;\n value: number;\n widthRatio: number;\n}\n\n/** Sizes the stages of a funnel against the largest value. */\nexport function funnelStages(values: number[]): FunnelStage[] {\n const maximum = Math.max(0, ...values);\n return values.map((value, index) => ({ index, value, widthRatio: maximum === 0 ? 0 : Math.max(0, value) / maximum }));\n}\n"],"names":["ChartKind","niceScale","maximum","target","Number","isFinite","ticks","rough","magnitude","Math","floor","log10","residual","step","top","ceil","tick","push","toFixed","readSeries","value","Array","isArray","flatMap","entry","name","values","map","item","dataMaximum","kind","series","categoryCount","max","from","length","_","index","reduce","sum","donutSlices","positive","total","angle","share","slice","start","end","PI","ringPath","centerX","centerY","outer","inner","point","radius","sin","cos","middle","large","funnelStages","widthRatio"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /** One column a table could show. */ /** Reads columns out of a property value; a column is visible unless it says otherwise, and a locked column is always visible. */ function readColumns(value) {
6
+ if (!Array.isArray(value)) return [];
7
+ return value.flatMap((entry)=>{
8
+ if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) return [];
9
+ const { id, label, visible, locked } = entry;
10
+ if (typeof id !== 'string' || id.length === 0) return [];
11
+ return [
12
+ {
13
+ id,
14
+ label: typeof label === 'string' && label.length > 0 ? label : id,
15
+ visible: locked === true || visible !== false,
16
+ locked: locked === true
17
+ }
18
+ ];
19
+ });
20
+ }
21
+ /** The ids of the visible columns, in order: what the chooser publishes and a table binds its columns to. */ const visibleColumnIds = (columns)=>columns.filter((column)=>column.visible).map((column)=>column.id);
22
+ /** Moves a column one place up or down, staying where it is at either end. */ function moveColumn(columns, index, direction) {
23
+ const target = index + direction;
24
+ if (target < 0 || target >= columns.length) return columns;
25
+ const result = [
26
+ ...columns
27
+ ];
28
+ [result[index], result[target]] = [
29
+ result[target],
30
+ result[index]
31
+ ];
32
+ return result;
33
+ }
34
+ /** Shows or hides a column; a locked column cannot be hidden. */ const toggleColumn = (columns, index)=>columns.map((column, position)=>position === index && !column.locked ? {
35
+ ...column,
36
+ visible: !column.visible
37
+ } : column);
38
+
39
+ exports.moveColumn = moveColumn;
40
+ exports.readColumns = readColumns;
41
+ exports.toggleColumn = toggleColumn;
42
+ exports.visibleColumnIds = visibleColumnIds;
43
+ //# sourceMappingURL=columnModel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"columnModel.js","sources":["../../../foundation/columnModel.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/** One column a table could show. */\nexport interface ChooserColumn {\n id: string;\n label: string;\n visible: boolean;\n locked: boolean;\n}\n\n/** Reads columns out of a property value; a column is visible unless it says otherwise, and a locked column is always visible. */\nexport function readColumns(value: unknown): ChooserColumn[] {\n if (!Array.isArray(value)) return [];\n\n return value.flatMap((entry): ChooserColumn[] => {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) return [];\n const { id, label, visible, locked } = entry as Record<string, unknown>;\n if (typeof id !== 'string' || id.length === 0) return [];\n return [{ id, label: typeof label === 'string' && label.length > 0 ? label : id, visible: locked === true || visible !== false, locked: locked === true }];\n });\n}\n\n/** The ids of the visible columns, in order: what the chooser publishes and a table binds its columns to. */\nexport const visibleColumnIds = (columns: ChooserColumn[]): string[] => columns.filter(column => column.visible).map(column => column.id);\n\n/** Moves a column one place up or down, staying where it is at either end. */\nexport function moveColumn(columns: ChooserColumn[], index: number, direction: -1 | 1): ChooserColumn[] {\n const target = index + direction;\n if (target < 0 || target >= columns.length) return columns;\n\n const result = [...columns];\n [result[index], result[target]] = [result[target], result[index]];\n return result;\n}\n\n/** Shows or hides a column; a locked column cannot be hidden. */\nexport const toggleColumn = (columns: ChooserColumn[], index: number): ChooserColumn[] =>\n columns.map((column, position) => (position === index && !column.locked ? { ...column, visible: !column.visible } : column));\n"],"names":["readColumns","value","Array","isArray","flatMap","entry","id","label","visible","locked","length","visibleColumnIds","columns","filter","column","map","moveColumn","index","direction","target","result","toggleColumn","position"],"mappings":";;AAAA;AACA;AAEA,yKASO,SAASA,YAAYC,KAAc,EAAA;AACtC,IAAA,IAAI,CAACC,KAAAA,CAAMC,OAAO,CAACF,KAAAA,CAAAA,EAAQ,OAAO,EAAE;IAEpC,OAAOA,KAAAA,CAAMG,OAAO,CAAC,CAACC,KAAAA,GAAAA;QAClB,IAAI,OAAOA,KAAAA,KAAU,QAAA,IAAYA,KAAAA,KAAU,IAAA,IAAQH,MAAMC,OAAO,CAACE,KAAAA,CAAAA,EAAQ,OAAO,EAAE;QAClF,MAAM,EAAEC,EAAE,EAAEC,KAAK,EAAEC,OAAO,EAAEC,MAAM,EAAE,GAAGJ,KAAAA;QACvC,IAAI,OAAOC,OAAO,QAAA,IAAYA,EAAAA,CAAGI,MAAM,KAAK,CAAA,EAAG,OAAO,EAAE;QACxD,OAAO;AAAC,YAAA;AAAEJ,gBAAAA,EAAAA;AAAIC,gBAAAA,KAAAA,EAAO,OAAOA,KAAAA,KAAU,QAAA,IAAYA,MAAMG,MAAM,GAAG,IAAIH,KAAAA,GAAQD,EAAAA;gBAAIE,OAAAA,EAASC,MAAAA,KAAW,QAAQD,OAAAA,KAAY,KAAA;AAAOC,gBAAAA,MAAAA,EAAQA,MAAAA,KAAW;AAAK;AAAE,SAAA;AAC9J,IAAA,CAAA,CAAA;AACJ;AAEA,8GACO,MAAME,gBAAAA,GAAmB,CAACC,OAAAA,GAAuCA,OAAAA,CAAQC,MAAM,CAACC,CAAAA,SAAUA,MAAAA,CAAON,OAAO,EAAEO,GAAG,CAACD,CAAAA,MAAAA,GAAUA,MAAAA,CAAOR,EAAE;AAExI,+EACO,SAASU,UAAAA,CAAWJ,OAAwB,EAAEK,KAAa,EAAEC,SAAiB,EAAA;AACjF,IAAA,MAAMC,SAASF,KAAAA,GAAQC,SAAAA;AACvB,IAAA,IAAIC,SAAS,CAAA,IAAKA,MAAAA,IAAUP,OAAAA,CAAQF,MAAM,EAAE,OAAOE,OAAAA;AAEnD,IAAA,MAAMQ,MAAAA,GAAS;AAAIR,QAAAA,GAAAA;AAAQ,KAAA;IAC3B,CAACQ,MAAM,CAACH,KAAAA,CAAM,EAAEG,MAAM,CAACD,MAAAA,CAAO,CAAC,GAAG;AAACC,QAAAA,MAAM,CAACD,MAAAA,CAAO;AAAEC,QAAAA,MAAM,CAACH,KAAAA;AAAO,KAAA;IACjE,OAAOG,MAAAA;AACX;AAEA,kEACO,MAAMC,eAAe,CAACT,OAAAA,EAA0BK,QACnDL,OAAAA,CAAQG,GAAG,CAAC,CAACD,QAAQQ,QAAAA,GAAcA,QAAAA,KAAaL,SAAS,CAACH,MAAAA,CAAOL,MAAM,GAAG;AAAE,YAAA,GAAGK,MAAM;YAAEN,OAAAA,EAAS,CAACM,OAAON;AAAQ,SAAA,GAAIM,MAAAA;;;;;"}