@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,154 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useMemo, useState, useId, useRef, useEffect } from 'react';
3
+ import { useValueOutput } from '@cratis/scene.react';
4
+ import { readColumns, visibleColumnIds, toggleColumn, moveColumn } from './columnModel.js';
5
+ import { readComponentState, ComponentState } from './ComponentState.js';
6
+ import { FoundationIcon } from './FoundationIcon.js';
7
+ import { readFoundationStrings, formatText } from './foundationStrings.js';
8
+ import { FoundationFrame } from './StateFrame.js';
9
+
10
+ /**
11
+ * The `columnChooser` component: which columns a table shows, and in what order.
12
+ *
13
+ * `columns` lists what could be shown (id, label, whether it starts visible, and whether it is locked - the identifying column is). The
14
+ * chooser is a button that discloses a list of checkboxes; each row also has move up and move down buttons, so ordering needs no
15
+ * drag-and-drop. Its `value` output is the ordered list of visible ids, which the table binds its columns to. Escape closes the list and
16
+ * returns focus to the button.
17
+ */ function ColumnChooser({ element, interactions, bindingOutputs }) {
18
+ const supplied = useMemo(()=>readColumns(element.properties.columns), [
19
+ element.properties.columns
20
+ ]);
21
+ const suppliedKey = JSON.stringify(supplied);
22
+ const [columns, setColumns] = useState(supplied);
23
+ const [open, setOpen] = useState(false);
24
+ const strings = readFoundationStrings(element);
25
+ const state = readComponentState(element, supplied.length > 0);
26
+ const panelId = useId();
27
+ const button = useRef(null);
28
+ useEffect(()=>setColumns(supplied), [
29
+ suppliedKey
30
+ ]);
31
+ useValueOutput(bindingOutputs, visibleColumnIds(columns));
32
+ const apply = (next)=>{
33
+ setColumns(next);
34
+ interactions?.onChange?.();
35
+ };
36
+ const close = (event)=>{
37
+ if (event.key !== 'Escape' || !open) return;
38
+ setOpen(false);
39
+ button.current?.focus();
40
+ };
41
+ return /*#__PURE__*/ jsx(FoundationFrame, {
42
+ element: element,
43
+ interactions: interactions,
44
+ name: "column-chooser",
45
+ state: state,
46
+ skeleton: [
47
+ 50
48
+ ],
49
+ children: state !== ComponentState.Loading && /*#__PURE__*/ jsxs("div", {
50
+ className: "foundation-popover-host",
51
+ onKeyDown: close,
52
+ children: [
53
+ /*#__PURE__*/ jsxs("button", {
54
+ ref: button,
55
+ type: "button",
56
+ className: "foundation-button",
57
+ "data-emphasis": "secondary",
58
+ "aria-expanded": open,
59
+ "aria-controls": panelId,
60
+ onClick: ()=>setOpen(!open),
61
+ children: [
62
+ /*#__PURE__*/ jsx(FoundationIcon, {
63
+ name: "columns"
64
+ }),
65
+ /*#__PURE__*/ jsx("span", {
66
+ children: strings.columnsChoose
67
+ }),
68
+ /*#__PURE__*/ jsx("span", {
69
+ className: "foundation-count",
70
+ children: formatText(strings.columnsShown, {
71
+ shown: visibleColumnIds(columns).length,
72
+ total: columns.length
73
+ })
74
+ })
75
+ ]
76
+ }),
77
+ /*#__PURE__*/ jsxs("div", {
78
+ id: panelId,
79
+ className: "foundation-popover",
80
+ hidden: !open,
81
+ children: [
82
+ /*#__PURE__*/ jsx("ul", {
83
+ className: "foundation-list",
84
+ "aria-label": strings.columnsChoose,
85
+ children: columns.map((column, index)=>/*#__PURE__*/ jsxs("li", {
86
+ className: "foundation-list-row",
87
+ children: [
88
+ /*#__PURE__*/ jsxs("label", {
89
+ className: "foundation-check",
90
+ children: [
91
+ /*#__PURE__*/ jsx("input", {
92
+ type: "checkbox",
93
+ checked: column.visible,
94
+ disabled: column.locked,
95
+ onChange: ()=>apply(toggleColumn(columns, index))
96
+ }),
97
+ /*#__PURE__*/ jsx("span", {
98
+ children: column.label
99
+ }),
100
+ column.locked && /*#__PURE__*/ jsxs("span", {
101
+ className: "foundation-count",
102
+ children: [
103
+ "(",
104
+ strings.columnsLocked,
105
+ ")"
106
+ ]
107
+ })
108
+ ]
109
+ }),
110
+ /*#__PURE__*/ jsx("button", {
111
+ type: "button",
112
+ className: "foundation-icon-button",
113
+ disabled: index === 0,
114
+ "aria-label": formatText(strings.columnsMoveUp, {
115
+ name: column.label
116
+ }),
117
+ onClick: ()=>apply(moveColumn(columns, index, -1)),
118
+ children: /*#__PURE__*/ jsx(FoundationIcon, {
119
+ name: "arrow-up"
120
+ })
121
+ }),
122
+ /*#__PURE__*/ jsx("button", {
123
+ type: "button",
124
+ className: "foundation-icon-button",
125
+ disabled: index === columns.length - 1,
126
+ "aria-label": formatText(strings.columnsMoveDown, {
127
+ name: column.label
128
+ }),
129
+ onClick: ()=>apply(moveColumn(columns, index, 1)),
130
+ children: /*#__PURE__*/ jsx(FoundationIcon, {
131
+ name: "arrow-down"
132
+ })
133
+ })
134
+ ]
135
+ }, column.id))
136
+ }),
137
+ /*#__PURE__*/ jsx("button", {
138
+ type: "button",
139
+ className: "foundation-link",
140
+ onClick: ()=>apply(columns.map((column)=>({
141
+ ...column,
142
+ visible: true
143
+ }))),
144
+ children: strings.columnsReset
145
+ })
146
+ ]
147
+ })
148
+ ]
149
+ })
150
+ });
151
+ }
152
+
153
+ export { ColumnChooser };
154
+ //# sourceMappingURL=ColumnChooser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColumnChooser.js","sources":["../../../foundation/ColumnChooser.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 { KeyboardEvent, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { RegisteredComponentProps, useValueOutput } from '@cratis/scene.react';\nimport { ChooserColumn, moveColumn, readColumns, toggleColumn, visibleColumnIds } from './columnModel';\nimport { ComponentState, readComponentState } from './ComponentState';\nimport { FoundationIcon } from './FoundationIcon';\nimport { formatText, readFoundationStrings } from './foundationStrings';\nimport { FoundationFrame } from './StateFrame';\n\n/**\n * The `columnChooser` component: which columns a table shows, and in what order.\n *\n * `columns` lists what could be shown (id, label, whether it starts visible, and whether it is locked - the identifying column is). The\n * chooser is a button that discloses a list of checkboxes; each row also has move up and move down buttons, so ordering needs no\n * drag-and-drop. Its `value` output is the ordered list of visible ids, which the table binds its columns to. Escape closes the list and\n * returns focus to the button.\n */\nexport function ColumnChooser({ element, interactions, bindingOutputs }: RegisteredComponentProps) {\n const supplied = useMemo(() => readColumns(element.properties.columns), [element.properties.columns]);\n const suppliedKey = JSON.stringify(supplied);\n const [columns, setColumns] = useState<ChooserColumn[]>(supplied);\n const [open, setOpen] = useState(false);\n const strings = readFoundationStrings(element);\n const state = readComponentState(element, supplied.length > 0);\n const panelId = useId();\n const button = useRef<HTMLButtonElement>(null);\n\n useEffect(() => setColumns(supplied), [suppliedKey]);\n useValueOutput(bindingOutputs, visibleColumnIds(columns));\n\n const apply = (next: ChooserColumn[]) => { setColumns(next); interactions?.onChange?.(); };\n const close = (event: KeyboardEvent) => {\n if (event.key !== 'Escape' || !open) return;\n setOpen(false);\n button.current?.focus();\n };\n\n return (\n <FoundationFrame element={element} interactions={interactions} name='column-chooser' state={state} skeleton={[50]}>\n {state !== ComponentState.Loading && (\n <div className='foundation-popover-host' onKeyDown={close}>\n <button ref={button} type='button' className='foundation-button' data-emphasis='secondary' aria-expanded={open} aria-controls={panelId} onClick={() => setOpen(!open)}>\n <FoundationIcon name='columns' />\n <span>{strings.columnsChoose}</span>\n <span className='foundation-count'>{formatText(strings.columnsShown, { shown: visibleColumnIds(columns).length, total: columns.length })}</span>\n </button>\n <div id={panelId} className='foundation-popover' hidden={!open}>\n <ul className='foundation-list' aria-label={strings.columnsChoose}>\n {columns.map((column, index) => (\n <li key={column.id} className='foundation-list-row'>\n <label className='foundation-check'>\n <input type='checkbox' checked={column.visible} disabled={column.locked} onChange={() => apply(toggleColumn(columns, index))} />\n <span>{column.label}</span>\n {column.locked && <span className='foundation-count'>({strings.columnsLocked})</span>}\n </label>\n <button type='button' className='foundation-icon-button' disabled={index === 0} aria-label={formatText(strings.columnsMoveUp, { name: column.label })} onClick={() => apply(moveColumn(columns, index, -1))}>\n <FoundationIcon name='arrow-up' />\n </button>\n <button type='button' className='foundation-icon-button' disabled={index === columns.length - 1} aria-label={formatText(strings.columnsMoveDown, { name: column.label })} onClick={() => apply(moveColumn(columns, index, 1))}>\n <FoundationIcon name='arrow-down' />\n </button>\n </li>\n ))}\n </ul>\n <button type='button' className='foundation-link' onClick={() => apply(columns.map(column => ({ ...column, visible: true })))}>{strings.columnsReset}</button>\n </div>\n </div>\n )}\n </FoundationFrame>\n );\n}\n"],"names":["ColumnChooser","element","interactions","bindingOutputs","supplied","useMemo","readColumns","properties","columns","suppliedKey","JSON","stringify","setColumns","useState","open","setOpen","strings","readFoundationStrings","state","readComponentState","length","panelId","useId","button","useRef","useEffect","useValueOutput","visibleColumnIds","apply","next","onChange","close","event","key","current","focus","_jsx","FoundationFrame","name","skeleton","ComponentState","Loading","_jsxs","div","className","onKeyDown","ref","type","data-emphasis","aria-expanded","aria-controls","onClick","FoundationIcon","span","columnsChoose","formatText","columnsShown","shown","total","id","hidden","ul","aria-label","map","column","index","li","label","input","checked","visible","disabled","locked","toggleColumn","columnsLocked","columnsMoveUp","moveColumn","columnsMoveDown","columnsReset"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { ExternalComponent } from '@cratis/scene.model';
2
+ export declare enum ComponentState {
3
+ Ready = "ready",
4
+ Loading = "loading",
5
+ Empty = "empty",
6
+ Error = "error",
7
+ NoPermission = "noPermission",
8
+ Partial = "partial"
9
+ }
10
+ export declare const componentStates: readonly ComponentState[];
11
+ export declare function readComponentState(element: ExternalComponent, hasData: boolean): ComponentState;
12
+ //# sourceMappingURL=ComponentState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComponentState.d.ts","sourceRoot":"","sources":["../../../foundation/ComponentState.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAQxD,oBAAY,cAAc;IAEtB,KAAK,UAAU;IAGf,OAAO,YAAY;IAGnB,KAAK,UAAU;IAGf,KAAK,UAAU;IAGf,YAAY,iBAAiB;IAG7B,OAAO,YAAY;CACtB;AAGD,eAAO,MAAM,eAAe,EAAE,SAAS,cAAc,EAAkC,CAAC;AAYxF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,OAAO,GAAG,cAAc,CAQ/F"}
@@ -0,0 +1,38 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+ /**
4
+ * The visual states every data-showing foundation component defines (spec Part B 1.4).
5
+ *
6
+ * A template is only worth choosing if it looks right in all of them: an application spends real time loading, empty, failing
7
+ * and not allowed, and a component that only draws its populated self has not been finished.
8
+ */ var ComponentState = /*#__PURE__*/ function(ComponentState) {
9
+ /** The data is there and drawn. */ ComponentState["Ready"] = "ready";
10
+ /** The data has not answered yet: a skeleton in the shape of the content, never a spinner alone. */ ComponentState["Loading"] = "loading";
11
+ /** The data answered with nothing: an explanation and the primary action. */ ComponentState["Empty"] = "empty";
12
+ /** The data could not be loaded: a message and a retry. */ ComponentState["Error"] = "error";
13
+ /** The user may not see the data: what is missing, and nothing of the data. */ ComponentState["NoPermission"] = "noPermission";
14
+ /** Some regions loaded and some failed: what loaded, plus which parts did not. */ ComponentState["Partial"] = "partial";
15
+ return ComponentState;
16
+ }({});
17
+ /** Every state, in the order a preview or a story lists them. */ const componentStates = Object.values(ComponentState);
18
+ /**
19
+ * Reads the state a component is in from its properties.
20
+ *
21
+ * An explicit `state` property wins, which is how a preview forces a state. Otherwise the state follows the properties a bound
22
+ * query already publishes - the same `loading` and `error` the preview states use for tables - plus `forbidden` and
23
+ * `failedRegions`, and falls to Empty when the component has nothing to show.
24
+ *
25
+ * @param element The element being rendered.
26
+ * @param hasData Whether the component has anything to draw when it is ready.
27
+ */ function readComponentState(element, hasData) {
28
+ const { state, forbidden, error, loading, failedRegions } = element.properties;
29
+ if (typeof state === 'string' && componentStates.includes(state)) return state;
30
+ if (forbidden === true) return "noPermission";
31
+ if (typeof error === 'string' && error.length > 0) return "error";
32
+ if (loading === true) return "loading";
33
+ if (Array.isArray(failedRegions) && failedRegions.length > 0) return "partial";
34
+ return hasData ? "ready" : "empty";
35
+ }
36
+
37
+ export { ComponentState, componentStates, readComponentState };
38
+ //# sourceMappingURL=ComponentState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComponentState.js","sources":["../../../foundation/ComponentState.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\nimport { ExternalComponent } from '@cratis/scene.model';\n\n/**\n * The visual states every data-showing foundation component defines (spec Part B 1.4).\n *\n * A template is only worth choosing if it looks right in all of them: an application spends real time loading, empty, failing\n * and not allowed, and a component that only draws its populated self has not been finished.\n */\nexport enum ComponentState {\n /** The data is there and drawn. */\n Ready = 'ready',\n\n /** The data has not answered yet: a skeleton in the shape of the content, never a spinner alone. */\n Loading = 'loading',\n\n /** The data answered with nothing: an explanation and the primary action. */\n Empty = 'empty',\n\n /** The data could not be loaded: a message and a retry. */\n Error = 'error',\n\n /** The user may not see the data: what is missing, and nothing of the data. */\n NoPermission = 'noPermission',\n\n /** Some regions loaded and some failed: what loaded, plus which parts did not. */\n Partial = 'partial',\n}\n\n/** Every state, in the order a preview or a story lists them. */\nexport const componentStates: readonly ComponentState[] = Object.values(ComponentState);\n\n/**\n * Reads the state a component is in from its properties.\n *\n * An explicit `state` property wins, which is how a preview forces a state. Otherwise the state follows the properties a bound\n * query already publishes - the same `loading` and `error` the preview states use for tables - plus `forbidden` and\n * `failedRegions`, and falls to Empty when the component has nothing to show.\n *\n * @param element The element being rendered.\n * @param hasData Whether the component has anything to draw when it is ready.\n */\nexport function readComponentState(element: ExternalComponent, hasData: boolean): ComponentState {\n const { state, forbidden, error, loading, failedRegions } = element.properties;\n if (typeof state === 'string' && (componentStates as readonly string[]).includes(state)) return state as ComponentState;\n if (forbidden === true) return ComponentState.NoPermission;\n if (typeof error === 'string' && error.length > 0) return ComponentState.Error;\n if (loading === true) return ComponentState.Loading;\n if (Array.isArray(failedRegions) && failedRegions.length > 0) return ComponentState.Partial;\n return hasData ? ComponentState.Ready : ComponentState.Empty;\n}\n"],"names":["ComponentState","componentStates","Object","values","readComponentState","element","hasData","state","forbidden","error","loading","failedRegions","properties","includes","length","Array","isArray"],"mappings":"AAAA;AACA;AAIA;;;;;IAMO,IAAKA,cAAAA,iBAAAA,SAAAA,cAAAA,EAAAA;wCACyB,cAAA,CAAA,OAAA,CAAA,GAAA,OAAA;yGAGiE,cAAA,CAAA,SAAA,CAAA,GAAA,SAAA;kFAGvB,cAAA,CAAA,OAAA,CAAA,GAAA,OAAA;gEAGlB,cAAA,CAAA,OAAA,CAAA,GAAA,OAAA;oFAGoB,cAAA,CAAA,cAAA,CAAA,GAAA,cAAA;uFAGG,cAAA,CAAA,SAAA,CAAA,GAAA,SAAA;AAhBxEA,IAAAA,OAAAA,cAAAA;AAkBX,CAAA,CAAA,EAAA;AAED,kEACO,MAAMC,kBAA6CC,MAAAA,CAAOC,MAAM,CAACH,cAAAA;AAExE;;;;;;;;;AASC,IACM,SAASI,kBAAAA,CAAmBC,OAA0B,EAAEC,OAAgB,EAAA;AAC3E,IAAA,MAAM,EAAEC,KAAK,EAAEC,SAAS,EAAEC,KAAK,EAAEC,OAAO,EAAEC,aAAa,EAAE,GAAGN,QAAQO,UAAU;IAC9E,IAAI,OAAOL,UAAU,QAAA,IAAaN,gBAAsCY,QAAQ,CAACN,QAAQ,OAAOA,KAAAA;AAChG,IAAA,IAAIC,cAAc,IAAA,EAAM,OAAA,cAAA;AACxB,IAAA,IAAI,OAAOC,KAAAA,KAAU,QAAA,IAAYA,KAAAA,CAAMK,MAAM,GAAG,CAAA,EAAG,OAAA,OAAA;AACnD,IAAA,IAAIJ,YAAY,IAAA,EAAM,OAAA,SAAA;AACtB,IAAA,IAAIK,MAAMC,OAAO,CAACL,kBAAkBA,aAAAA,CAAcG,MAAM,GAAG,CAAA,EAAG,OAAA,SAAA;IAC9D,OAAOR,OAAAA,GAAAA,OAAAA,GAAAA,OAAAA;AACX;;"}
@@ -0,0 +1,3 @@
1
+ import { RegisteredComponentProps } from '@cratis/scene.react';
2
+ export declare function EmptyState({ element, interactions }: RegisteredComponentProps): import("react").JSX.Element;
3
+ //# sourceMappingURL=EmptyState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../../foundation/EmptyState.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAY/D,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,wBAAwB,+BAM7E"}
@@ -0,0 +1,29 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { EmptyStateView } from './StateFrame.js';
3
+ import { readFoundationStrings } from './foundationStrings.js';
4
+ import { readLocale } from './formatting.js';
5
+
6
+ // Copyright (c) Cratis. All rights reserved.
7
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
8
+ /**
9
+ * The empty state as a component of its own: an icon, a headline, a hint and one primary action, embeddable in any region.
10
+ *
11
+ * Every other foundation component shows this same view when it has no data, so a screen reads the same wherever nothing is
12
+ * found. Placed on its own it is what a template puts in a region that has nothing to say yet. The action starts whatever the
13
+ * element's behaviors say, and honours the `actionPermission` rule, so an empty list never offers a creation the user may not do.
14
+ */ function EmptyState({ element, interactions }) {
15
+ return /*#__PURE__*/ jsx("section", {
16
+ className: "foundation foundation-empty-state",
17
+ "data-scene-id": element.id,
18
+ "data-state": "empty",
19
+ lang: readLocale(element),
20
+ children: /*#__PURE__*/ jsx(EmptyStateView, {
21
+ element: element,
22
+ interactions: interactions,
23
+ strings: readFoundationStrings(element)
24
+ })
25
+ });
26
+ }
27
+
28
+ export { EmptyState };
29
+ //# sourceMappingURL=EmptyState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.js","sources":["../../../foundation/EmptyState.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 { EmptyStateView } from './StateFrame';\nimport { readFoundationStrings } from './foundationStrings';\nimport { readLocale } from './formatting';\n\n/**\n * The empty state as a component of its own: an icon, a headline, a hint and one primary action, embeddable in any region.\n *\n * Every other foundation component shows this same view when it has no data, so a screen reads the same wherever nothing is\n * found. Placed on its own it is what a template puts in a region that has nothing to say yet. The action starts whatever the\n * element's behaviors say, and honours the `actionPermission` rule, so an empty list never offers a creation the user may not do.\n */\nexport function EmptyState({ element, interactions }: RegisteredComponentProps) {\n return (\n <section className='foundation foundation-empty-state' data-scene-id={element.id} data-state='empty' lang={readLocale(element)}>\n <EmptyStateView element={element} interactions={interactions} strings={readFoundationStrings(element)} />\n </section>\n );\n}\n"],"names":["EmptyState","element","interactions","_jsx","section","className","data-scene-id","id","data-state","lang","readLocale","EmptyStateView","strings","readFoundationStrings"],"mappings":";;;;;AAAA;AACA;AAOA;;;;;;AAMC,IACM,SAASA,UAAAA,CAAW,EAAEC,OAAO,EAAEC,YAAY,EAA4B,EAAA;AAC1E,IAAA,qBACIC,GAAA,CAACC,SAAAA,EAAAA;QAAQC,SAAAA,EAAU,mCAAA;AAAoCC,QAAAA,eAAAA,EAAeL,QAAQM,EAAE;QAAEC,YAAAA,EAAW,OAAA;AAAQC,QAAAA,IAAAA,EAAMC,UAAAA,CAAWT,OAAAA,CAAAA;AAClH,QAAA,QAAA,gBAAAE,GAAA,CAACQ,cAAAA,EAAAA;YAAeV,OAAAA,EAASA,OAAAA;YAASC,YAAAA,EAAcA,YAAAA;AAAcU,YAAAA,OAAAA,EAASC,qBAAAA,CAAsBZ,OAAAA;;;AAGzG;;"}
@@ -0,0 +1,3 @@
1
+ import { RegisteredComponentProps } from '@cratis/scene.react';
2
+ export declare function FilterBuilder({ element, interactions, bindingOutputs }: RegisteredComponentProps): import("react").JSX.Element;
3
+ //# sourceMappingURL=FilterBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilterBuilder.d.ts","sourceRoot":"","sources":["../../../foundation/FilterBuilder.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,wBAAwB,EAAkB,MAAM,qBAAqB,CAAC;AA2G/E,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,EAAE,wBAAwB,+BAgChG"}
@@ -0,0 +1,305 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { useMemo, useState, useEffect } from 'react';
3
+ import { useValueOutput } from '@cratis/scene.react';
4
+ import { readComponentState, ComponentState } from './ComponentState.js';
5
+ import { ActionButton } from './ActionButton.js';
6
+ import { readFilterFields, normalizeFilter, countActiveConditions, emptyFilter, filterOperators, FilterFieldType, newCondition, maximumFilterDepth, updateGroupAt, valuelessOperators } from './filterModel.js';
7
+ import { readFoundationStrings, formatText } from './foundationStrings.js';
8
+ import { FoundationFrame } from './StateFrame.js';
9
+ import { readPermissionRule } from './PermissionRule.js';
10
+
11
+ const operatorText = (strings, operator)=>{
12
+ const names = {
13
+ contains: strings.opContains,
14
+ equals: strings.opEquals,
15
+ notEquals: strings.opNotEquals,
16
+ startsWith: strings.opStartsWith,
17
+ isEmpty: strings.opIsEmpty,
18
+ greater: strings.opGreater,
19
+ greaterOrEqual: strings.opGreaterOrEqual,
20
+ less: strings.opLess,
21
+ lessOrEqual: strings.opLessOrEqual,
22
+ before: strings.opBefore,
23
+ after: strings.opAfter,
24
+ on: strings.opOn,
25
+ is: strings.opIs,
26
+ isNot: strings.opIsNot,
27
+ true: strings.opTrue,
28
+ false: strings.opFalse
29
+ };
30
+ return names[operator] ?? operator;
31
+ };
32
+ function ValueInput({ field, condition, strings, label, disabled, onChange }) {
33
+ if (valuelessOperators.includes(condition.operator)) return undefined;
34
+ if (field?.type === FilterFieldType.Select) {
35
+ return /*#__PURE__*/ jsxs("select", {
36
+ "aria-label": `${strings.filterValue}, ${label}`,
37
+ value: condition.value,
38
+ disabled: disabled,
39
+ onChange: (event)=>onChange(event.target.value),
40
+ children: [
41
+ /*#__PURE__*/ jsx("option", {
42
+ value: "",
43
+ children: "—"
44
+ }),
45
+ field.options.map((option)=>/*#__PURE__*/ jsx("option", {
46
+ value: option,
47
+ children: option
48
+ }, option))
49
+ ]
50
+ });
51
+ }
52
+ return /*#__PURE__*/ jsx("input", {
53
+ "aria-label": `${strings.filterValue}, ${label}`,
54
+ type: field?.type === FilterFieldType.Number ? 'number' : field?.type === FilterFieldType.Date ? 'date' : 'text',
55
+ value: condition.value,
56
+ disabled: disabled,
57
+ onChange: (event)=>onChange(event.target.value)
58
+ });
59
+ }
60
+ function GroupEditor({ group, path, fields, strings, locked, change }) {
61
+ const label = path.length === 0 ? strings.filterMatchAll.replace(/ \(.*\)$/, '') : formatText(strings.filterGroup, {
62
+ n: path.join('.')
63
+ });
64
+ const depth = path.length + 1;
65
+ return /*#__PURE__*/ jsxs("div", {
66
+ className: "foundation-filter-group",
67
+ role: "group",
68
+ "aria-label": path.length === 0 ? formatText(countActiveConditions(group) === 1 ? strings.filterSummaryOne : strings.filterSummary, {
69
+ count: countActiveConditions(group)
70
+ }) : label,
71
+ "data-depth": depth,
72
+ children: [
73
+ /*#__PURE__*/ jsxs("div", {
74
+ className: "foundation-filter-match",
75
+ children: [
76
+ /*#__PURE__*/ jsxs("select", {
77
+ "aria-label": strings.filterMatchAll,
78
+ value: group.operator,
79
+ disabled: locked,
80
+ onChange: (event)=>change(path, (current)=>({
81
+ ...current,
82
+ operator: event.target.value === 'or' ? 'or' : 'and'
83
+ })),
84
+ children: [
85
+ /*#__PURE__*/ jsx("option", {
86
+ value: "and",
87
+ children: strings.filterMatchAll
88
+ }),
89
+ /*#__PURE__*/ jsx("option", {
90
+ value: "or",
91
+ children: strings.filterMatchAny
92
+ })
93
+ ]
94
+ }),
95
+ path.length > 0 && !locked && /*#__PURE__*/ jsx("button", {
96
+ type: "button",
97
+ className: "foundation-link",
98
+ onClick: ()=>change(path.slice(0, -1), (parent)=>({
99
+ ...parent,
100
+ groups: parent.groups.filter((_, index)=>index !== path[path.length - 1])
101
+ })),
102
+ children: strings.filterRemoveGroup
103
+ })
104
+ ]
105
+ }),
106
+ group.conditions.map((condition, index)=>{
107
+ const field = fields.find((candidate)=>candidate.name === condition.field);
108
+ const conditionLabel = formatText(strings.filterCondition, {
109
+ n: index + 1
110
+ });
111
+ return /*#__PURE__*/ jsxs("div", {
112
+ className: "foundation-filter-row",
113
+ role: "group",
114
+ "aria-label": conditionLabel,
115
+ children: [
116
+ /*#__PURE__*/ jsx("select", {
117
+ "aria-label": `${strings.filterField}, ${conditionLabel}`,
118
+ value: condition.field,
119
+ disabled: locked,
120
+ onChange: (event)=>{
121
+ const next = fields.find((candidate)=>candidate.name === event.target.value);
122
+ change(path, (current)=>({
123
+ ...current,
124
+ conditions: current.conditions.map((existing, position)=>position === index ? {
125
+ field: event.target.value,
126
+ operator: next ? filterOperators[next.type][0] : existing.operator,
127
+ value: ''
128
+ } : existing)
129
+ }));
130
+ },
131
+ children: fields.map((candidate)=>/*#__PURE__*/ jsx("option", {
132
+ value: candidate.name,
133
+ children: candidate.label
134
+ }, candidate.name))
135
+ }),
136
+ /*#__PURE__*/ jsx("select", {
137
+ "aria-label": `${strings.filterOperator}, ${conditionLabel}`,
138
+ value: condition.operator,
139
+ disabled: locked,
140
+ onChange: (event)=>change(path, (current)=>({
141
+ ...current,
142
+ conditions: current.conditions.map((existing, position)=>position === index ? {
143
+ ...existing,
144
+ operator: event.target.value
145
+ } : existing)
146
+ })),
147
+ children: filterOperators[field?.type ?? FilterFieldType.Text].map((operator)=>/*#__PURE__*/ jsx("option", {
148
+ value: operator,
149
+ children: operatorText(strings, operator)
150
+ }, operator))
151
+ }),
152
+ /*#__PURE__*/ jsx(ValueInput, {
153
+ field: field,
154
+ condition: condition,
155
+ strings: strings,
156
+ label: conditionLabel,
157
+ disabled: locked,
158
+ onChange: (value)=>change(path, (current)=>({
159
+ ...current,
160
+ conditions: current.conditions.map((existing, position)=>position === index ? {
161
+ ...existing,
162
+ value
163
+ } : existing)
164
+ }))
165
+ }),
166
+ !locked && /*#__PURE__*/ jsx("button", {
167
+ type: "button",
168
+ className: "foundation-icon-button",
169
+ "aria-label": `${strings.filterRemove}, ${conditionLabel}`,
170
+ onClick: ()=>change(path, (current)=>({
171
+ ...current,
172
+ conditions: current.conditions.filter((_, position)=>position !== index)
173
+ })),
174
+ children: "×"
175
+ })
176
+ ]
177
+ }, index);
178
+ }),
179
+ group.groups.map((nested, index)=>/*#__PURE__*/ jsx(GroupEditor, {
180
+ group: nested,
181
+ path: [
182
+ ...path,
183
+ index
184
+ ],
185
+ fields: fields,
186
+ strings: strings,
187
+ locked: locked,
188
+ change: change
189
+ }, index)),
190
+ !locked && /*#__PURE__*/ jsxs("div", {
191
+ className: "foundation-filter-actions",
192
+ children: [
193
+ /*#__PURE__*/ jsx("button", {
194
+ type: "button",
195
+ className: "foundation-link",
196
+ onClick: ()=>change(path, (current)=>({
197
+ ...current,
198
+ conditions: [
199
+ ...current.conditions,
200
+ newCondition(fields)
201
+ ]
202
+ })),
203
+ children: strings.filterAdd
204
+ }),
205
+ depth < maximumFilterDepth && /*#__PURE__*/ jsx("button", {
206
+ type: "button",
207
+ className: "foundation-link",
208
+ onClick: ()=>change(path, (current)=>({
209
+ ...current,
210
+ groups: [
211
+ ...current.groups,
212
+ {
213
+ operator: 'and',
214
+ conditions: [
215
+ newCondition(fields)
216
+ ],
217
+ groups: []
218
+ }
219
+ ]
220
+ })),
221
+ children: strings.filterAddGroup
222
+ })
223
+ ]
224
+ })
225
+ ]
226
+ });
227
+ }
228
+ /**
229
+ * The `filterBuilder` component: field, operator and value conditions joined by AND or OR, in groups that nest up to three deep.
230
+ *
231
+ * The filter is the component's `value` output - `{ operator, conditions, groups }` - which a list screen binds its query to; the
232
+ * component itself filters nothing. `fields` describe what can be filtered (name, label, type, and options for a select), and
233
+ * the operators on offer follow each field's type. A filter bound in through `value` is read back as the user left it: conditions on
234
+ * fields that no longer exist are dropped rather than shown broken. The component is the filter panel of a list on a desktop and
235
+ * the body of the filter dialog on a phone.
236
+ */ function FilterBuilder({ element, interactions, bindingOutputs }) {
237
+ const fields = useMemo(()=>readFilterFields(element.properties.fields), [
238
+ element.properties.fields
239
+ ]);
240
+ const supplied = useMemo(()=>normalizeFilter(element.properties.filter, fields), [
241
+ element.properties.filter,
242
+ fields
243
+ ]);
244
+ const [filter, setFilter] = useState(supplied);
245
+ const strings = readFoundationStrings(element);
246
+ const suppliedKey = JSON.stringify(supplied);
247
+ const state = readComponentState(element, fields.length > 0);
248
+ const locked = readPermissionRule(element, 'editPermission') !== 'enabled';
249
+ useEffect(()=>setFilter(supplied), [
250
+ suppliedKey
251
+ ]);
252
+ useValueOutput(bindingOutputs, filter);
253
+ const change = (path, apply)=>{
254
+ const next = updateGroupAt(filter, path, apply);
255
+ setFilter(next);
256
+ interactions?.onChange?.();
257
+ };
258
+ const active = countActiveConditions(filter);
259
+ return /*#__PURE__*/ jsx(FoundationFrame, {
260
+ element: element,
261
+ interactions: interactions,
262
+ name: "filter-builder",
263
+ state: state,
264
+ skeleton: [
265
+ 100,
266
+ 100
267
+ ],
268
+ children: state !== ComponentState.Loading && /*#__PURE__*/ jsxs(Fragment, {
269
+ children: [
270
+ /*#__PURE__*/ jsx(GroupEditor, {
271
+ group: filter,
272
+ path: [],
273
+ fields: fields,
274
+ strings: strings,
275
+ locked: locked,
276
+ change: change
277
+ }),
278
+ /*#__PURE__*/ jsxs("div", {
279
+ className: "foundation-filter-footer",
280
+ children: [
281
+ /*#__PURE__*/ jsx("span", {
282
+ className: "foundation-filter-summary",
283
+ "aria-live": "polite",
284
+ children: active === 1 ? strings.filterSummaryOne : formatText(strings.filterSummary, {
285
+ count: active
286
+ })
287
+ }),
288
+ active > 0 && !locked && /*#__PURE__*/ jsx(ActionButton, {
289
+ emphasis: "quiet",
290
+ disabledReason: strings.disabledNoPermission,
291
+ onClick: ()=>{
292
+ setFilter(emptyFilter());
293
+ interactions?.onChange?.();
294
+ },
295
+ children: strings.filterClear
296
+ })
297
+ ]
298
+ })
299
+ ]
300
+ })
301
+ });
302
+ }
303
+
304
+ export { FilterBuilder };
305
+ //# sourceMappingURL=FilterBuilder.js.map