@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.
- package/ComponentName.ts +24 -0
- package/defaultBlueprint.ts +2 -1
- package/defaultBlueprintComponentMetadata.ts +2 -0
- package/defaultBlueprintComponents.ts +9 -0
- package/dist/cjs/ComponentName.js +8 -0
- package/dist/cjs/ComponentName.js.map +1 -1
- package/dist/cjs/defaultBlueprint.js +9 -5
- package/dist/cjs/defaultBlueprint.js.map +1 -1
- package/dist/cjs/defaultBlueprintComponentMetadata.js +8 -0
- package/dist/cjs/defaultBlueprintComponentMetadata.js.map +1 -1
- package/dist/cjs/defaultBlueprintComponents.js +21 -1
- package/dist/cjs/defaultBlueprintComponents.js.map +1 -1
- package/dist/cjs/foundation/ActionButton.js +33 -0
- package/dist/cjs/foundation/ActionButton.js.map +1 -0
- package/dist/cjs/foundation/ChartWrapper.js +520 -0
- package/dist/cjs/foundation/ChartWrapper.js.map +1 -0
- package/dist/cjs/foundation/ColumnChooser.js +156 -0
- package/dist/cjs/foundation/ColumnChooser.js.map +1 -0
- package/dist/cjs/foundation/ComponentState.js +42 -0
- package/dist/cjs/foundation/ComponentState.js.map +1 -0
- package/dist/cjs/foundation/EmptyState.js +31 -0
- package/dist/cjs/foundation/EmptyState.js.map +1 -0
- package/dist/cjs/foundation/FilterBuilder.js +307 -0
- package/dist/cjs/foundation/FilterBuilder.js.map +1 -0
- package/dist/cjs/foundation/FoundationIcon.js +58 -0
- package/dist/cjs/foundation/FoundationIcon.js.map +1 -0
- package/dist/cjs/foundation/FoundationStates.js +62 -0
- package/dist/cjs/foundation/FoundationStates.js.map +1 -0
- package/dist/cjs/foundation/PermissionRule.js +22 -0
- package/dist/cjs/foundation/PermissionRule.js.map +1 -0
- package/dist/cjs/foundation/SavedViewsMenu.js +199 -0
- package/dist/cjs/foundation/SavedViewsMenu.js.map +1 -0
- package/dist/cjs/foundation/StatCard.js +61 -0
- package/dist/cjs/foundation/StatCard.js.map +1 -0
- package/dist/cjs/foundation/StateFrame.js +200 -0
- package/dist/cjs/foundation/StateFrame.js.map +1 -0
- package/dist/cjs/foundation/StatusChip.js +64 -0
- package/dist/cjs/foundation/StatusChip.js.map +1 -0
- package/dist/cjs/foundation/TrendChip.js +93 -0
- package/dist/cjs/foundation/TrendChip.js.map +1 -0
- package/dist/cjs/foundation/chartGeometry.js +101 -0
- package/dist/cjs/foundation/chartGeometry.js.map +1 -0
- package/dist/cjs/foundation/columnModel.js +43 -0
- package/dist/cjs/foundation/columnModel.js.map +1 -0
- package/dist/cjs/foundation/filterModel.js +123 -0
- package/dist/cjs/foundation/filterModel.js.map +1 -0
- package/dist/cjs/foundation/formatting.js +85 -0
- package/dist/cjs/foundation/formatting.js.map +1 -0
- package/dist/cjs/foundation/foundationComponentMetadata.js +69 -0
- package/dist/cjs/foundation/foundationComponentMetadata.js.map +1 -0
- package/dist/cjs/foundation/foundationDescriptors.js +385 -0
- package/dist/cjs/foundation/foundationDescriptors.js.map +1 -0
- package/dist/cjs/foundation/foundationSamples.js +201 -0
- package/dist/cjs/foundation/foundationSamples.js.map +1 -0
- package/dist/cjs/foundation/foundationStrings.js +130 -0
- package/dist/cjs/foundation/foundationStrings.js.map +1 -0
- package/dist/cjs/foundation/useElementWidth.js +31 -0
- package/dist/cjs/foundation/useElementWidth.js.map +1 -0
- package/dist/cjs/foundation/viewModel.js +24 -0
- package/dist/cjs/foundation/viewModel.js.map +1 -0
- package/dist/cjs/index.js +90 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/themes/dark.js +9 -1
- package/dist/cjs/themes/dark.js.map +1 -1
- package/dist/cjs/themes/light.js +10 -2
- package/dist/cjs/themes/light.js.map +1 -1
- package/dist/esm/ComponentName.d.ts +9 -1
- package/dist/esm/ComponentName.d.ts.map +1 -1
- package/dist/esm/ComponentName.js +8 -0
- package/dist/esm/ComponentName.js.map +1 -1
- package/dist/esm/defaultBlueprint.d.ts.map +1 -1
- package/dist/esm/defaultBlueprint.js +9 -5
- package/dist/esm/defaultBlueprint.js.map +1 -1
- package/dist/esm/defaultBlueprintComponentMetadata.d.ts.map +1 -1
- package/dist/esm/defaultBlueprintComponentMetadata.js +8 -0
- package/dist/esm/defaultBlueprintComponentMetadata.js.map +1 -1
- package/dist/esm/defaultBlueprintComponents.d.ts.map +1 -1
- package/dist/esm/defaultBlueprintComponents.js +21 -1
- package/dist/esm/defaultBlueprintComponents.js.map +1 -1
- package/dist/esm/foundation/ActionButton.d.ts +13 -0
- package/dist/esm/foundation/ActionButton.d.ts.map +1 -0
- package/dist/esm/foundation/ActionButton.js +31 -0
- package/dist/esm/foundation/ActionButton.js.map +1 -0
- package/dist/esm/foundation/ChartWrapper.d.ts +5 -0
- package/dist/esm/foundation/ChartWrapper.d.ts.map +1 -0
- package/dist/esm/foundation/ChartWrapper.js +517 -0
- package/dist/esm/foundation/ChartWrapper.js.map +1 -0
- package/dist/esm/foundation/ColumnChooser.d.ts +3 -0
- package/dist/esm/foundation/ColumnChooser.d.ts.map +1 -0
- package/dist/esm/foundation/ColumnChooser.js +154 -0
- package/dist/esm/foundation/ColumnChooser.js.map +1 -0
- package/dist/esm/foundation/ComponentState.d.ts +12 -0
- package/dist/esm/foundation/ComponentState.d.ts.map +1 -0
- package/dist/esm/foundation/ComponentState.js +38 -0
- package/dist/esm/foundation/ComponentState.js.map +1 -0
- package/dist/esm/foundation/EmptyState.d.ts +3 -0
- package/dist/esm/foundation/EmptyState.d.ts.map +1 -0
- package/dist/esm/foundation/EmptyState.js +29 -0
- package/dist/esm/foundation/EmptyState.js.map +1 -0
- package/dist/esm/foundation/FilterBuilder.d.ts +3 -0
- package/dist/esm/foundation/FilterBuilder.d.ts.map +1 -0
- package/dist/esm/foundation/FilterBuilder.js +305 -0
- package/dist/esm/foundation/FilterBuilder.js.map +1 -0
- package/dist/esm/foundation/Foundation.stories.d.ts +37 -0
- package/dist/esm/foundation/Foundation.stories.d.ts.map +1 -0
- package/dist/esm/foundation/Foundation.stories.js +34 -0
- package/dist/esm/foundation/Foundation.stories.js.map +1 -0
- package/dist/esm/foundation/FoundationIcon.d.ts +7 -0
- package/dist/esm/foundation/FoundationIcon.d.ts.map +1 -0
- package/dist/esm/foundation/FoundationIcon.js +55 -0
- package/dist/esm/foundation/FoundationIcon.js.map +1 -0
- package/dist/esm/foundation/FoundationStates.d.ts +8 -0
- package/dist/esm/foundation/FoundationStates.d.ts.map +1 -0
- package/dist/esm/foundation/FoundationStates.js +60 -0
- package/dist/esm/foundation/FoundationStates.js.map +1 -0
- package/dist/esm/foundation/PermissionRule.d.ts +8 -0
- package/dist/esm/foundation/PermissionRule.d.ts.map +1 -0
- package/dist/esm/foundation/PermissionRule.js +19 -0
- package/dist/esm/foundation/PermissionRule.js.map +1 -0
- package/dist/esm/foundation/SavedViewsMenu.d.ts +4 -0
- package/dist/esm/foundation/SavedViewsMenu.d.ts.map +1 -0
- package/dist/esm/foundation/SavedViewsMenu.js +196 -0
- package/dist/esm/foundation/SavedViewsMenu.js.map +1 -0
- package/dist/esm/foundation/StatCard.d.ts +3 -0
- package/dist/esm/foundation/StatCard.d.ts.map +1 -0
- package/dist/esm/foundation/StatCard.js +59 -0
- package/dist/esm/foundation/StatCard.js.map +1 -0
- package/dist/esm/foundation/StateFrame.d.ts +15 -0
- package/dist/esm/foundation/StateFrame.d.ts.map +1 -0
- package/dist/esm/foundation/StateFrame.js +197 -0
- package/dist/esm/foundation/StateFrame.js.map +1 -0
- package/dist/esm/foundation/StatusChip.d.ts +13 -0
- package/dist/esm/foundation/StatusChip.d.ts.map +1 -0
- package/dist/esm/foundation/StatusChip.js +59 -0
- package/dist/esm/foundation/StatusChip.js.map +1 -0
- package/dist/esm/foundation/TrendChip.d.ts +18 -0
- package/dist/esm/foundation/TrendChip.d.ts.map +1 -0
- package/dist/esm/foundation/TrendChip.js +88 -0
- package/dist/esm/foundation/TrendChip.js.map +1 -0
- package/dist/esm/foundation/chartGeometry.d.ts +34 -0
- package/dist/esm/foundation/chartGeometry.d.ts.map +1 -0
- package/dist/esm/foundation/chartGeometry.js +93 -0
- package/dist/esm/foundation/chartGeometry.js.map +1 -0
- package/dist/esm/foundation/columnModel.d.ts +11 -0
- package/dist/esm/foundation/columnModel.d.ts.map +1 -0
- package/dist/esm/foundation/columnModel.js +38 -0
- package/dist/esm/foundation/columnModel.js.map +1 -0
- package/dist/esm/foundation/filterModel.d.ts +33 -0
- package/dist/esm/foundation/filterModel.d.ts.map +1 -0
- package/dist/esm/foundation/filterModel.js +112 -0
- package/dist/esm/foundation/filterModel.js.map +1 -0
- package/dist/esm/foundation/formatting.d.ts +13 -0
- package/dist/esm/foundation/formatting.d.ts.map +1 -0
- package/dist/esm/foundation/formatting.js +78 -0
- package/dist/esm/foundation/formatting.js.map +1 -0
- package/dist/esm/foundation/foundationComponentMetadata.d.ts +3 -0
- package/dist/esm/foundation/foundationComponentMetadata.d.ts.map +1 -0
- package/dist/esm/foundation/foundationComponentMetadata.js +67 -0
- package/dist/esm/foundation/foundationComponentMetadata.js.map +1 -0
- package/dist/esm/foundation/foundationDescriptors.d.ts +6 -0
- package/dist/esm/foundation/foundationDescriptors.d.ts.map +1 -0
- package/dist/esm/foundation/foundationDescriptors.js +380 -0
- package/dist/esm/foundation/foundationDescriptors.js.map +1 -0
- package/dist/esm/foundation/foundationSamples.d.ts +10 -0
- package/dist/esm/foundation/foundationSamples.d.ts.map +1 -0
- package/dist/esm/foundation/foundationSamples.js +198 -0
- package/dist/esm/foundation/foundationSamples.js.map +1 -0
- package/dist/esm/foundation/foundationStrings.d.ts +103 -0
- package/dist/esm/foundation/foundationStrings.d.ts.map +1 -0
- package/dist/esm/foundation/foundationStrings.js +126 -0
- package/dist/esm/foundation/foundationStrings.js.map +1 -0
- package/dist/esm/foundation/index.d.ts +25 -0
- package/dist/esm/foundation/index.d.ts.map +1 -0
- package/dist/esm/foundation/index.js +25 -0
- package/dist/esm/foundation/index.js.map +1 -0
- package/dist/esm/foundation/useElementWidth.d.ts +3 -0
- package/dist/esm/foundation/useElementWidth.d.ts.map +1 -0
- package/dist/esm/foundation/useElementWidth.js +29 -0
- package/dist/esm/foundation/useElementWidth.js.map +1 -0
- package/dist/esm/foundation/viewModel.d.ts +7 -0
- package/dist/esm/foundation/viewModel.d.ts.map +1 -0
- package/dist/esm/foundation/viewModel.js +22 -0
- package/dist/esm/foundation/viewModel.js.map +1 -0
- package/dist/esm/gallery/widgets.js +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +24 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/themes/dark.d.ts.map +1 -1
- package/dist/esm/themes/dark.js +9 -1
- package/dist/esm/themes/dark.js.map +1 -1
- package/dist/esm/themes/light.d.ts.map +1 -1
- package/dist/esm/themes/light.js +10 -2
- package/dist/esm/themes/light.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/foundation/ActionButton.tsx +39 -0
- package/foundation/ChartWrapper.tsx +252 -0
- package/foundation/ColumnChooser.tsx +73 -0
- package/foundation/ComponentState.ts +53 -0
- package/foundation/EmptyState.tsx +22 -0
- package/foundation/FilterBuilder.tsx +144 -0
- package/foundation/Foundation.stories.tsx +46 -0
- package/foundation/FoundationIcon.tsx +49 -0
- package/foundation/FoundationStates.tsx +46 -0
- package/foundation/PermissionRule.ts +26 -0
- package/foundation/SavedViewsMenu.tsx +94 -0
- package/foundation/StatCard.tsx +44 -0
- package/foundation/StateFrame.tsx +126 -0
- package/foundation/StatusChip.tsx +51 -0
- package/foundation/TrendChip.tsx +78 -0
- package/foundation/chartGeometry.ts +108 -0
- package/foundation/columnModel.ts +39 -0
- package/foundation/filterModel.ts +111 -0
- package/foundation/formatting.ts +69 -0
- package/foundation/foundationComponentMetadata.ts +21 -0
- package/foundation/foundationDescriptors.ts +204 -0
- package/foundation/foundationSamples.ts +63 -0
- package/foundation/foundationStrings.ts +137 -0
- package/foundation/index.ts +27 -0
- package/foundation/useElementWidth.ts +31 -0
- package/foundation/viewModel.ts +21 -0
- package/index.ts +1 -0
- package/package.json +9 -8
- package/shell/layout.css +526 -0
- package/themes/dark.ts +8 -0
- 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":";;;;;;;;;AAWA;;;;;;;IAQO,SAASA,aAAAA,CAAc,EAAEC,OAAO,EAAEC,YAAY,EAAEC,cAAc,EAA4B,EAAA;IAC7F,MAAMC,QAAAA,GAAWC,QAAQ,IAAMC,WAAAA,CAAYL,QAAQM,UAAU,CAACC,OAAO,CAAA,EAAG;QAACP,OAAAA,CAAQM,UAAU,CAACC;AAAQ,KAAA,CAAA;IACpG,MAAMC,WAAAA,GAAcC,IAAAA,CAAKC,SAAS,CAACP,QAAAA,CAAAA;AACnC,IAAA,MAAM,CAACI,OAAAA,EAASI,UAAAA,CAAW,GAAGC,QAAAA,CAA0BT,QAAAA,CAAAA;AACxD,IAAA,MAAM,CAACU,IAAAA,EAAMC,OAAAA,CAAQ,GAAGF,QAAAA,CAAS,KAAA,CAAA;AACjC,IAAA,MAAMG,UAAUC,qBAAAA,CAAsBhB,OAAAA,CAAAA;AACtC,IAAA,MAAMiB,KAAAA,GAAQC,kBAAAA,CAAmBlB,OAAAA,EAASG,QAAAA,CAASgB,MAAM,GAAG,CAAA,CAAA;AAC5D,IAAA,MAAMC,OAAAA,GAAUC,KAAAA,EAAAA;AAChB,IAAA,MAAMC,SAASC,MAAAA,CAA0B,IAAA,CAAA;IAEzCC,SAAAA,CAAU,IAAMb,WAAWR,QAAAA,CAAAA,EAAW;AAACK,QAAAA;AAAY,KAAA,CAAA;AACnDiB,IAAAA,cAAAA,CAAevB,gBAAgBwB,gBAAAA,CAAiBnB,OAAAA,CAAAA,CAAAA;AAEhD,IAAA,MAAMoB,QAAQ,CAACC,IAAAA,GAAAA;QAA4BjB,UAAAA,CAAWiB,IAAAA,CAAAA;QAAO3B,YAAAA,EAAc4B,QAAAA,IAAAA;AAAc,IAAA,CAAA;AACzF,IAAA,MAAMC,QAAQ,CAACC,KAAAA,GAAAA;AACX,QAAA,IAAIA,KAAAA,CAAMC,GAAG,KAAK,QAAA,IAAY,CAACnB,IAAAA,EAAM;QACrCC,OAAAA,CAAQ,KAAA,CAAA;AACRQ,QAAAA,MAAAA,CAAOW,OAAO,EAAEC,KAAAA,EAAAA;AACpB,IAAA,CAAA;AAEA,IAAA,qBACIC,GAAA,CAACC,eAAAA,EAAAA;QAAgBpC,OAAAA,EAASA,OAAAA;QAASC,YAAAA,EAAcA,YAAAA;QAAcoC,IAAAA,EAAK,gBAAA;QAAiBpB,KAAAA,EAAOA,KAAAA;QAAOqB,QAAAA,EAAU;AAAC,YAAA;AAAG,SAAA;kBAC5GrB,KAAAA,KAAUsB,cAAAA,CAAeC,OAAO,kBAC7BC,IAAA,CAACC,KAAAA,EAAAA;YAAIC,SAAAA,EAAU,yBAAA;YAA0BC,SAAAA,EAAWd,KAAAA;;8BAChDW,IAAA,CAACnB,QAAAA,EAAAA;oBAAOuB,GAAAA,EAAKvB,MAAAA;oBAAQwB,IAAAA,EAAK,QAAA;oBAASH,SAAAA,EAAU,mBAAA;oBAAoBI,eAAAA,EAAc,WAAA;oBAAYC,eAAAA,EAAenC,IAAAA;oBAAMoC,eAAAA,EAAe7B,OAAAA;oBAAS8B,OAAAA,EAAS,IAAMpC,QAAQ,CAACD,IAAAA,CAAAA;;sCAC5JsB,GAAA,CAACgB,cAAAA,EAAAA;4BAAed,IAAAA,EAAK;;sCACrBF,GAAA,CAACiB,MAAAA,EAAAA;AAAMrC,4BAAAA,QAAAA,EAAAA,OAAAA,CAAQsC;;sCACflB,GAAA,CAACiB,MAAAA,EAAAA;4BAAKT,SAAAA,EAAU,kBAAA;sCAAoBW,UAAAA,CAAWvC,OAAAA,CAAQwC,YAAY,EAAE;gCAAEC,KAAAA,EAAO9B,gBAAAA,CAAiBnB,SAASY,MAAM;AAAEsC,gCAAAA,KAAAA,EAAOlD,QAAQY;AAAO,6BAAA;;;;8BAE1IsB,IAAA,CAACC,KAAAA,EAAAA;oBAAIgB,EAAAA,EAAItC,OAAAA;oBAASuB,SAAAA,EAAU,oBAAA;AAAqBgB,oBAAAA,MAAAA,EAAQ,CAAC9C,IAAAA;;sCACtDsB,GAAA,CAACyB,IAAAA,EAAAA;4BAAGjB,SAAAA,EAAU,iBAAA;AAAkBkB,4BAAAA,YAAAA,EAAY9C,QAAQsC,aAAa;AAC5D9C,4BAAAA,QAAAA,EAAAA,OAAAA,CAAQuD,GAAG,CAAC,CAACC,MAAAA,EAAQC,sBAClBvB,IAAA,CAACwB,IAAAA,EAAAA;oCAAmBtB,SAAAA,EAAU,qBAAA;;sDAC1BF,IAAA,CAACyB,OAAAA,EAAAA;4CAAMvB,SAAAA,EAAU,kBAAA;;8DACbR,GAAA,CAACgC,OAAAA,EAAAA;oDAAMrB,IAAAA,EAAK,UAAA;AAAWsB,oDAAAA,OAAAA,EAASL,OAAOM,OAAO;AAAEC,oDAAAA,QAAAA,EAAUP,OAAOQ,MAAM;oDAAE1C,QAAAA,EAAU,IAAMF,KAAAA,CAAM6C,YAAAA,CAAajE,OAAAA,EAASyD,KAAAA,CAAAA;;8DACrH7B,GAAA,CAACiB,MAAAA,EAAAA;AAAMW,oDAAAA,QAAAA,EAAAA,MAAAA,CAAOG;;gDACbH,MAAAA,CAAOQ,MAAM,kBAAI9B,IAAA,CAACW,MAAAA,EAAAA;oDAAKT,SAAAA,EAAU,kBAAA;;AAAmB,wDAAA,GAAA;AAAE5B,wDAAAA,OAAAA,CAAQ0D,aAAa;AAAC,wDAAA;;;;;sDAEjFtC,GAAA,CAACb,QAAAA,EAAAA;4CAAOwB,IAAAA,EAAK,QAAA;4CAASH,SAAAA,EAAU,wBAAA;AAAyB2B,4CAAAA,QAAAA,EAAUN,KAAAA,KAAU,CAAA;4CAAGH,YAAAA,EAAYP,UAAAA,CAAWvC,OAAAA,CAAQ2D,aAAa,EAAE;AAAErC,gDAAAA,IAAAA,EAAM0B,OAAOG;AAAM,6CAAA,CAAA;AAAIhB,4CAAAA,OAAAA,EAAS,IAAMvB,KAAAA,CAAMgD,UAAAA,CAAWpE,OAAAA,EAASyD,OAAO,EAAC,CAAA,CAAA;AACpM,4CAAA,QAAA,gBAAA7B,GAAA,CAACgB,cAAAA,EAAAA;gDAAed,IAAAA,EAAK;;;sDAEzBF,GAAA,CAACb,QAAAA,EAAAA;4CAAOwB,IAAAA,EAAK,QAAA;4CAASH,SAAAA,EAAU,wBAAA;4CAAyB2B,QAAAA,EAAUN,KAAAA,KAAUzD,OAAAA,CAAQY,MAAM,GAAG,CAAA;4CAAG0C,YAAAA,EAAYP,UAAAA,CAAWvC,OAAAA,CAAQ6D,eAAe,EAAE;AAAEvC,gDAAAA,IAAAA,EAAM0B,OAAOG;AAAM,6CAAA,CAAA;AAAIhB,4CAAAA,OAAAA,EAAS,IAAMvB,KAAAA,CAAMgD,UAAAA,CAAWpE,OAAAA,EAASyD,KAAAA,EAAO,CAAA,CAAA,CAAA;AACtN,4CAAA,QAAA,gBAAA7B,GAAA,CAACgB,cAAAA,EAAAA;gDAAed,IAAAA,EAAK;;;;AAVpB0B,iCAAAA,EAAAA,MAAAA,CAAOL,EAAE,CAAA;;sCAe1BvB,GAAA,CAACb,QAAAA,EAAAA;4BAAOwB,IAAAA,EAAK,QAAA;4BAASH,SAAAA,EAAU,iBAAA;AAAkBO,4BAAAA,OAAAA,EAAS,IAAMvB,KAAAA,CAAMpB,OAAAA,CAAQuD,GAAG,CAACC,CAAAA,UAAW;AAAE,wCAAA,GAAGA,MAAM;wCAAEM,OAAAA,EAAS;qCAAK,CAAA,CAAA,CAAA;AAAOtD,4BAAAA,QAAAA,EAAAA,OAAAA,CAAQ8D;;;;;;;AAMhK;;"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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
|