@cratis/scene.blueprint.default 4.38.0 → 4.40.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 +27 -0
- package/defaultBlueprintComponents.ts +10 -1
- package/dist/cjs/ComponentName.js +9 -0
- package/dist/cjs/ComponentName.js.map +1 -1
- package/dist/cjs/defaultBlueprintComponents.js +19 -1
- package/dist/cjs/defaultBlueprintComponents.js.map +1 -1
- package/dist/cjs/foundation/BulkBar.js +62 -0
- package/dist/cjs/foundation/BulkBar.js.map +1 -0
- package/dist/cjs/foundation/DataList.js +436 -0
- package/dist/cjs/foundation/DataList.js.map +1 -0
- package/dist/cjs/foundation/FormScreenBody.js +447 -0
- package/dist/cjs/foundation/FormScreenBody.js.map +1 -0
- package/dist/cjs/foundation/FoundationStates.js +2 -1
- package/dist/cjs/foundation/FoundationStates.js.map +1 -1
- package/dist/cjs/foundation/GlobalSearch.js +54 -0
- package/dist/cjs/foundation/GlobalSearch.js.map +1 -0
- package/dist/cjs/foundation/KanbanBoard.js +222 -0
- package/dist/cjs/foundation/KanbanBoard.js.map +1 -0
- package/dist/cjs/foundation/NotificationsButton.js +45 -0
- package/dist/cjs/foundation/NotificationsButton.js.map +1 -0
- package/dist/cjs/foundation/SubNavigation.js +72 -0
- package/dist/cjs/foundation/SubNavigation.js.map +1 -0
- package/dist/cjs/foundation/TabSet.js +101 -0
- package/dist/cjs/foundation/TabSet.js.map +1 -0
- package/dist/cjs/foundation/WizardProgress.js +185 -0
- package/dist/cjs/foundation/WizardProgress.js.map +1 -0
- package/dist/cjs/foundation/boardModel.js +67 -0
- package/dist/cjs/foundation/boardModel.js.map +1 -0
- package/dist/cjs/foundation/formModel.js +158 -0
- package/dist/cjs/foundation/formModel.js.map +1 -0
- package/dist/cjs/foundation/foundationComponentMetadata.js +54 -0
- package/dist/cjs/foundation/foundationComponentMetadata.js.map +1 -1
- package/dist/cjs/foundation/foundationDescriptors.js +400 -0
- package/dist/cjs/foundation/foundationDescriptors.js.map +1 -1
- package/dist/cjs/foundation/foundationSamples.js +303 -0
- package/dist/cjs/foundation/foundationSamples.js.map +1 -1
- package/dist/cjs/foundation/foundationStrings.js +72 -0
- package/dist/cjs/foundation/foundationStrings.js.map +1 -1
- package/dist/cjs/foundation/listModel.js +200 -0
- package/dist/cjs/foundation/listModel.js.map +1 -0
- package/dist/cjs/foundation/tabModel.js +41 -0
- package/dist/cjs/foundation/tabModel.js.map +1 -0
- package/dist/cjs/foundation/urlState.js +57 -0
- package/dist/cjs/foundation/urlState.js.map +1 -0
- package/dist/cjs/foundation/useCompactWidth.js +23 -0
- package/dist/cjs/foundation/useCompactWidth.js.map +1 -0
- package/dist/cjs/foundation/wizardModel.js +50 -0
- package/dist/cjs/foundation/wizardModel.js.map +1 -0
- package/dist/cjs/index.js +71 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/ComponentName.d.ts +10 -1
- package/dist/esm/ComponentName.d.ts.map +1 -1
- package/dist/esm/ComponentName.js +9 -0
- package/dist/esm/ComponentName.js.map +1 -1
- package/dist/esm/defaultBlueprintComponents.d.ts.map +1 -1
- package/dist/esm/defaultBlueprintComponents.js +19 -1
- package/dist/esm/defaultBlueprintComponents.js.map +1 -1
- package/dist/esm/foundation/BulkBar.d.ts +4 -0
- package/dist/esm/foundation/BulkBar.d.ts.map +1 -0
- package/dist/esm/foundation/BulkBar.js +59 -0
- package/dist/esm/foundation/BulkBar.js.map +1 -0
- package/dist/esm/foundation/DataList.d.ts +3 -0
- package/dist/esm/foundation/DataList.d.ts.map +1 -0
- package/dist/esm/foundation/DataList.js +434 -0
- package/dist/esm/foundation/DataList.js.map +1 -0
- package/dist/esm/foundation/FormScreenBody.d.ts +3 -0
- package/dist/esm/foundation/FormScreenBody.d.ts.map +1 -0
- package/dist/esm/foundation/FormScreenBody.js +445 -0
- package/dist/esm/foundation/FormScreenBody.js.map +1 -0
- package/dist/esm/foundation/FoundationStates.js +2 -1
- package/dist/esm/foundation/FoundationStates.js.map +1 -1
- package/dist/esm/foundation/GlobalSearch.d.ts +3 -0
- package/dist/esm/foundation/GlobalSearch.d.ts.map +1 -0
- package/dist/esm/foundation/GlobalSearch.js +52 -0
- package/dist/esm/foundation/GlobalSearch.js.map +1 -0
- package/dist/esm/foundation/KanbanBoard.d.ts +3 -0
- package/dist/esm/foundation/KanbanBoard.d.ts.map +1 -0
- package/dist/esm/foundation/KanbanBoard.js +220 -0
- package/dist/esm/foundation/KanbanBoard.js.map +1 -0
- package/dist/esm/foundation/NotificationsButton.d.ts +3 -0
- package/dist/esm/foundation/NotificationsButton.d.ts.map +1 -0
- package/dist/esm/foundation/NotificationsButton.js +43 -0
- package/dist/esm/foundation/NotificationsButton.js.map +1 -0
- package/dist/esm/foundation/SubNavigation.d.ts +3 -0
- package/dist/esm/foundation/SubNavigation.d.ts.map +1 -0
- package/dist/esm/foundation/SubNavigation.js +70 -0
- package/dist/esm/foundation/SubNavigation.js.map +1 -0
- package/dist/esm/foundation/TabSet.d.ts +3 -0
- package/dist/esm/foundation/TabSet.d.ts.map +1 -0
- package/dist/esm/foundation/TabSet.js +99 -0
- package/dist/esm/foundation/TabSet.js.map +1 -0
- package/dist/esm/foundation/WizardProgress.d.ts +3 -0
- package/dist/esm/foundation/WizardProgress.d.ts.map +1 -0
- package/dist/esm/foundation/WizardProgress.js +183 -0
- package/dist/esm/foundation/WizardProgress.js.map +1 -0
- package/dist/esm/foundation/boardModel.d.ts +22 -0
- package/dist/esm/foundation/boardModel.d.ts.map +1 -0
- package/dist/esm/foundation/boardModel.js +61 -0
- package/dist/esm/foundation/boardModel.js.map +1 -0
- package/dist/esm/foundation/formModel.d.ts +48 -0
- package/dist/esm/foundation/formModel.d.ts.map +1 -0
- package/dist/esm/foundation/formModel.js +147 -0
- package/dist/esm/foundation/formModel.js.map +1 -0
- package/dist/esm/foundation/foundationComponentMetadata.d.ts.map +1 -1
- package/dist/esm/foundation/foundationComponentMetadata.js +54 -0
- package/dist/esm/foundation/foundationComponentMetadata.js.map +1 -1
- package/dist/esm/foundation/foundationDescriptors.d.ts.map +1 -1
- package/dist/esm/foundation/foundationDescriptors.js +400 -0
- package/dist/esm/foundation/foundationDescriptors.js.map +1 -1
- package/dist/esm/foundation/foundationSamples.d.ts.map +1 -1
- package/dist/esm/foundation/foundationSamples.js +303 -0
- package/dist/esm/foundation/foundationSamples.js.map +1 -1
- package/dist/esm/foundation/foundationStrings.d.ts +72 -0
- package/dist/esm/foundation/foundationStrings.d.ts.map +1 -1
- package/dist/esm/foundation/foundationStrings.js +72 -0
- package/dist/esm/foundation/foundationStrings.js.map +1 -1
- package/dist/esm/foundation/index.d.ts +16 -0
- package/dist/esm/foundation/index.d.ts.map +1 -1
- package/dist/esm/foundation/index.js +16 -0
- package/dist/esm/foundation/index.js.map +1 -1
- package/dist/esm/foundation/listModel.d.ts +49 -0
- package/dist/esm/foundation/listModel.d.ts.map +1 -0
- package/dist/esm/foundation/listModel.js +183 -0
- package/dist/esm/foundation/listModel.js.map +1 -0
- package/dist/esm/foundation/tabModel.d.ts +10 -0
- package/dist/esm/foundation/tabModel.d.ts.map +1 -0
- package/dist/esm/foundation/tabModel.js +37 -0
- package/dist/esm/foundation/tabModel.js.map +1 -0
- package/dist/esm/foundation/urlState.d.ts +4 -0
- package/dist/esm/foundation/urlState.d.ts.map +1 -0
- package/dist/esm/foundation/urlState.js +53 -0
- package/dist/esm/foundation/urlState.js.map +1 -0
- package/dist/esm/foundation/useCompactWidth.d.ts +3 -0
- package/dist/esm/foundation/useCompactWidth.d.ts.map +1 -0
- package/dist/esm/foundation/useCompactWidth.js +20 -0
- package/dist/esm/foundation/useCompactWidth.js.map +1 -0
- package/dist/esm/foundation/wizardModel.d.ts +16 -0
- package/dist/esm/foundation/wizardModel.d.ts.map +1 -0
- package/dist/esm/foundation/wizardModel.js +43 -0
- package/dist/esm/foundation/wizardModel.js.map +1 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/foundation/BulkBar.tsx +38 -0
- package/foundation/DataList.tsx +208 -0
- package/foundation/FormScreenBody.tsx +196 -0
- package/foundation/FoundationStates.tsx +1 -1
- package/foundation/GlobalSearch.tsx +33 -0
- package/foundation/KanbanBoard.tsx +97 -0
- package/foundation/NotificationsButton.tsx +28 -0
- package/foundation/SubNavigation.tsx +49 -0
- package/foundation/TabSet.tsx +65 -0
- package/foundation/WizardProgress.tsx +109 -0
- package/foundation/boardModel.ts +64 -0
- package/foundation/formModel.ts +146 -0
- package/foundation/foundationComponentMetadata.ts +9 -0
- package/foundation/foundationDescriptors.ts +195 -0
- package/foundation/foundationSamples.ts +56 -0
- package/foundation/foundationStrings.ts +72 -0
- package/foundation/index.ts +16 -0
- package/foundation/listModel.ts +190 -0
- package/foundation/tabModel.ts +41 -0
- package/foundation/urlState.ts +52 -0
- package/foundation/useCompactWidth.ts +23 -0
- package/foundation/wizardModel.ts +54 -0
- package/package.json +8 -8
- package/shell/layout.css +513 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var scene_react = require('@cratis/scene.react');
|
|
6
|
+
var boardModel = require('./boardModel.js');
|
|
7
|
+
var ComponentState = require('./ComponentState.js');
|
|
8
|
+
var FoundationIcon = require('./FoundationIcon.js');
|
|
9
|
+
var foundationStrings = require('./foundationStrings.js');
|
|
10
|
+
var PermissionRule = require('./PermissionRule.js');
|
|
11
|
+
var StateFrame = require('./StateFrame.js');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The `kanbanBoard` component: columns mapped to a status or stage, with cards that move between them.
|
|
15
|
+
*
|
|
16
|
+
* `columns` (`id`, `label`, `limit`) and `cards` (`id`, `title`, `column`, `assignee`, up to three `fields`, `badges`) come from a query. A card moves by
|
|
17
|
+
* dragging it to another column **and** by its own "Move to" menu - the keyboard and screen-reader alternative, so nothing depends on a pointer
|
|
18
|
+
* - and every move is announced. Columns show their count and a limit indicator that says "Over the limit" in words, and collapse to a
|
|
19
|
+
* strip. The new arrangement is published as `value` (the cards with their columns) for the screen to save; with `editPermission` not enabled the
|
|
20
|
+
* board is read-only. A card whose column no longer exists is shown in the first column rather than lost.
|
|
21
|
+
*/ function KanbanBoard({ element, interactions, bindingOutputs }) {
|
|
22
|
+
const columns = react.useMemo(()=>boardModel.readColumnsOfBoard(element.properties.columns), [
|
|
23
|
+
element.properties.columns
|
|
24
|
+
]);
|
|
25
|
+
const supplied = react.useMemo(()=>boardModel.readCards(element.properties.cards), [
|
|
26
|
+
element.properties.cards
|
|
27
|
+
]);
|
|
28
|
+
const suppliedKey = JSON.stringify(supplied);
|
|
29
|
+
const [cards, setCards] = react.useState(supplied);
|
|
30
|
+
const [collapsed, setCollapsed] = react.useState(new Set());
|
|
31
|
+
const [announcement, setAnnouncement] = react.useState('');
|
|
32
|
+
const [dragging, setDragging] = react.useState();
|
|
33
|
+
const strings = foundationStrings.readFoundationStrings(element);
|
|
34
|
+
const state = ComponentState.readComponentState(element, columns.length > 0);
|
|
35
|
+
const locked = PermissionRule.readPermissionRule(element, 'editPermission') !== 'enabled';
|
|
36
|
+
react.useEffect(()=>setCards(supplied), [
|
|
37
|
+
suppliedKey
|
|
38
|
+
]);
|
|
39
|
+
scene_react.useValueOutput(bindingOutputs, cards.map((card)=>({
|
|
40
|
+
id: card.id,
|
|
41
|
+
column: card.column
|
|
42
|
+
})));
|
|
43
|
+
const move = (id, to)=>{
|
|
44
|
+
const card = cards.find((candidate)=>candidate.id === id);
|
|
45
|
+
const target = columns.find((column)=>column.id === to);
|
|
46
|
+
const next = boardModel.moveCard(columns, cards, id, to);
|
|
47
|
+
if (!card || !target || next === cards) return;
|
|
48
|
+
setCards(next);
|
|
49
|
+
setAnnouncement(foundationStrings.formatText(strings.boardMoved, {
|
|
50
|
+
title: card.title,
|
|
51
|
+
column: target.label
|
|
52
|
+
}));
|
|
53
|
+
interactions?.onChange?.();
|
|
54
|
+
};
|
|
55
|
+
const drop = (event, to)=>{
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
if (dragging) move(dragging, to);
|
|
58
|
+
setDragging(undefined);
|
|
59
|
+
};
|
|
60
|
+
const toggle = (id)=>setCollapsed((current)=>{
|
|
61
|
+
const next = new Set(current);
|
|
62
|
+
if (next.has(id)) next.delete(id);
|
|
63
|
+
else next.add(id);
|
|
64
|
+
return next;
|
|
65
|
+
});
|
|
66
|
+
return /*#__PURE__*/ jsxRuntime.jsx(StateFrame.FoundationFrame, {
|
|
67
|
+
element: element,
|
|
68
|
+
interactions: interactions,
|
|
69
|
+
name: "kanban-board",
|
|
70
|
+
state: state,
|
|
71
|
+
skeleton: [
|
|
72
|
+
100,
|
|
73
|
+
100,
|
|
74
|
+
100
|
|
75
|
+
],
|
|
76
|
+
children: (state === ComponentState.ComponentState.Ready || state === ComponentState.ComponentState.Partial) && /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
77
|
+
children: [
|
|
78
|
+
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
79
|
+
role: "status",
|
|
80
|
+
"aria-live": "polite",
|
|
81
|
+
className: "foundation-visually-hidden",
|
|
82
|
+
children: announcement
|
|
83
|
+
}),
|
|
84
|
+
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
85
|
+
className: "foundation-board",
|
|
86
|
+
children: columns.map((column)=>{
|
|
87
|
+
const inColumn = boardModel.cardsOf(columns, cards, column.id);
|
|
88
|
+
const closed = collapsed.has(column.id);
|
|
89
|
+
const over = boardModel.overLimit(column, inColumn.length);
|
|
90
|
+
return /*#__PURE__*/ jsxRuntime.jsxs("section", {
|
|
91
|
+
className: "foundation-board-column",
|
|
92
|
+
"data-collapsed": closed,
|
|
93
|
+
"data-over": over,
|
|
94
|
+
"aria-label": foundationStrings.formatText(strings.boardColumn, {
|
|
95
|
+
column: column.label,
|
|
96
|
+
count: inColumn.length
|
|
97
|
+
}),
|
|
98
|
+
onDragOver: (event)=>{
|
|
99
|
+
if (!locked) event.preventDefault();
|
|
100
|
+
},
|
|
101
|
+
onDrop: (event)=>{
|
|
102
|
+
if (!locked) drop(event, column.id);
|
|
103
|
+
},
|
|
104
|
+
children: [
|
|
105
|
+
/*#__PURE__*/ jsxRuntime.jsxs("header", {
|
|
106
|
+
className: "foundation-board-header",
|
|
107
|
+
children: [
|
|
108
|
+
/*#__PURE__*/ jsxRuntime.jsx("button", {
|
|
109
|
+
type: "button",
|
|
110
|
+
className: "foundation-icon-button",
|
|
111
|
+
"aria-expanded": !closed,
|
|
112
|
+
"aria-label": foundationStrings.formatText(closed ? strings.boardExpand : strings.boardCollapse, {
|
|
113
|
+
column: column.label
|
|
114
|
+
}),
|
|
115
|
+
onClick: ()=>toggle(column.id),
|
|
116
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
|
|
117
|
+
name: closed ? 'chevron-right' : 'chevron-down'
|
|
118
|
+
})
|
|
119
|
+
}),
|
|
120
|
+
/*#__PURE__*/ jsxRuntime.jsx("h3", {
|
|
121
|
+
children: column.label
|
|
122
|
+
}),
|
|
123
|
+
/*#__PURE__*/ jsxRuntime.jsxs("span", {
|
|
124
|
+
className: "foundation-count",
|
|
125
|
+
children: [
|
|
126
|
+
inColumn.length,
|
|
127
|
+
column.limit > 0 ? ` / ${column.limit}` : ''
|
|
128
|
+
]
|
|
129
|
+
}),
|
|
130
|
+
over && /*#__PURE__*/ jsxRuntime.jsxs("span", {
|
|
131
|
+
className: "foundation-chip",
|
|
132
|
+
"data-tone": "danger",
|
|
133
|
+
children: [
|
|
134
|
+
/*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
|
|
135
|
+
name: "alert"
|
|
136
|
+
}),
|
|
137
|
+
foundationStrings.formatText(strings.boardWipExceeded, {
|
|
138
|
+
limit: column.limit
|
|
139
|
+
})
|
|
140
|
+
]
|
|
141
|
+
})
|
|
142
|
+
]
|
|
143
|
+
}),
|
|
144
|
+
!closed && /*#__PURE__*/ jsxRuntime.jsxs("ul", {
|
|
145
|
+
className: "foundation-board-cards",
|
|
146
|
+
children: [
|
|
147
|
+
inColumn.length === 0 && /*#__PURE__*/ jsxRuntime.jsx("li", {
|
|
148
|
+
className: "foundation-count",
|
|
149
|
+
children: strings.boardNoCards
|
|
150
|
+
}),
|
|
151
|
+
inColumn.map((card)=>/*#__PURE__*/ jsxRuntime.jsxs("li", {
|
|
152
|
+
className: "foundation-board-card",
|
|
153
|
+
draggable: !locked,
|
|
154
|
+
onDragStart: ()=>setDragging(card.id),
|
|
155
|
+
onDragEnd: ()=>setDragging(undefined),
|
|
156
|
+
children: [
|
|
157
|
+
/*#__PURE__*/ jsxRuntime.jsx("strong", {
|
|
158
|
+
children: card.title
|
|
159
|
+
}),
|
|
160
|
+
card.assignee && /*#__PURE__*/ jsxRuntime.jsxs("span", {
|
|
161
|
+
className: "foundation-count",
|
|
162
|
+
children: [
|
|
163
|
+
/*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
|
|
164
|
+
name: "user"
|
|
165
|
+
}),
|
|
166
|
+
" ",
|
|
167
|
+
card.assignee
|
|
168
|
+
]
|
|
169
|
+
}),
|
|
170
|
+
card.fields.map((field)=>/*#__PURE__*/ jsxRuntime.jsxs("span", {
|
|
171
|
+
className: "foundation-board-field",
|
|
172
|
+
children: [
|
|
173
|
+
/*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
174
|
+
className: "foundation-count",
|
|
175
|
+
children: field.label
|
|
176
|
+
}),
|
|
177
|
+
" ",
|
|
178
|
+
field.value
|
|
179
|
+
]
|
|
180
|
+
}, field.label)),
|
|
181
|
+
card.badges.length > 0 && /*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
182
|
+
className: "foundation-board-badges",
|
|
183
|
+
children: card.badges.map((badge)=>/*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
184
|
+
className: "foundation-chip",
|
|
185
|
+
"data-tone": "neutral",
|
|
186
|
+
children: badge
|
|
187
|
+
}, badge))
|
|
188
|
+
}),
|
|
189
|
+
!locked && /*#__PURE__*/ jsxRuntime.jsxs("select", {
|
|
190
|
+
className: "foundation-board-move",
|
|
191
|
+
"aria-label": foundationStrings.formatText(strings.boardMoveCard, {
|
|
192
|
+
title: card.title
|
|
193
|
+
}),
|
|
194
|
+
value: column.id,
|
|
195
|
+
onChange: (event)=>move(card.id, event.target.value),
|
|
196
|
+
children: [
|
|
197
|
+
/*#__PURE__*/ jsxRuntime.jsx("option", {
|
|
198
|
+
value: column.id,
|
|
199
|
+
disabled: true,
|
|
200
|
+
children: strings.boardMoveTo
|
|
201
|
+
}),
|
|
202
|
+
columns.filter((other)=>other.id !== column.id).map((other)=>/*#__PURE__*/ jsxRuntime.jsx("option", {
|
|
203
|
+
value: other.id,
|
|
204
|
+
children: other.label
|
|
205
|
+
}, other.id))
|
|
206
|
+
]
|
|
207
|
+
})
|
|
208
|
+
]
|
|
209
|
+
}, card.id))
|
|
210
|
+
]
|
|
211
|
+
})
|
|
212
|
+
]
|
|
213
|
+
}, column.id);
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
]
|
|
217
|
+
})
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
exports.KanbanBoard = KanbanBoard;
|
|
222
|
+
//# sourceMappingURL=KanbanBoard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KanbanBoard.js","sources":["../../../foundation/KanbanBoard.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 { DragEvent, useEffect, useMemo, useState } from 'react';\nimport { RegisteredComponentProps, useValueOutput } from '@cratis/scene.react';\nimport { BoardCard, BoardColumn, cardsOf, moveCard, overLimit, readCards, readColumnsOfBoard } from './boardModel';\nimport { ComponentState, readComponentState } from './ComponentState';\nimport { FoundationIcon } from './FoundationIcon';\nimport { formatText, readFoundationStrings } from './foundationStrings';\nimport { readPermissionRule } from './PermissionRule';\nimport { FoundationFrame } from './StateFrame';\n\n/**\n * The `kanbanBoard` component: columns mapped to a status or stage, with cards that move between them.\n *\n * `columns` (`id`, `label`, `limit`) and `cards` (`id`, `title`, `column`, `assignee`, up to three `fields`, `badges`) come from a query. A card moves by\n * dragging it to another column **and** by its own \"Move to\" menu - the keyboard and screen-reader alternative, so nothing depends on a pointer\n * - and every move is announced. Columns show their count and a limit indicator that says \"Over the limit\" in words, and collapse to a\n * strip. The new arrangement is published as `value` (the cards with their columns) for the screen to save; with `editPermission` not enabled the\n * board is read-only. A card whose column no longer exists is shown in the first column rather than lost.\n */\nexport function KanbanBoard({ element, interactions, bindingOutputs }: RegisteredComponentProps) {\n const columns = useMemo(() => readColumnsOfBoard(element.properties.columns), [element.properties.columns]);\n const supplied = useMemo(() => readCards(element.properties.cards), [element.properties.cards]);\n const suppliedKey = JSON.stringify(supplied);\n const [cards, setCards] = useState<BoardCard[]>(supplied);\n const [collapsed, setCollapsed] = useState<Set<string>>(new Set());\n const [announcement, setAnnouncement] = useState('');\n const [dragging, setDragging] = useState<string | undefined>();\n const strings = readFoundationStrings(element);\n const state = readComponentState(element, columns.length > 0);\n const locked = readPermissionRule(element, 'editPermission') !== 'enabled';\n\n useEffect(() => setCards(supplied), [suppliedKey]);\n useValueOutput(bindingOutputs, cards.map(card => ({ id: card.id, column: card.column })));\n\n const move = (id: string, to: string) => {\n const card = cards.find(candidate => candidate.id === id);\n const target = columns.find(column => column.id === to);\n const next = moveCard(columns, cards, id, to);\n if (!card || !target || next === cards) return;\n setCards(next);\n setAnnouncement(formatText(strings.boardMoved, { title: card.title, column: target.label }));\n interactions?.onChange?.();\n };\n const drop = (event: DragEvent, to: string) => { event.preventDefault(); if (dragging) move(dragging, to); setDragging(undefined); };\n const toggle = (id: string) => setCollapsed(current => { const next = new Set(current); if (next.has(id)) next.delete(id); else next.add(id); return next; });\n\n return (\n <FoundationFrame element={element} interactions={interactions} name='kanban-board' state={state} skeleton={[100, 100, 100]}>\n {(state === ComponentState.Ready || state === ComponentState.Partial) && (\n <>\n <div role='status' aria-live='polite' className='foundation-visually-hidden'>{announcement}</div>\n <div className='foundation-board'>\n {columns.map((column: BoardColumn) => {\n const inColumn = cardsOf(columns, cards, column.id);\n const closed = collapsed.has(column.id);\n const over = overLimit(column, inColumn.length);\n return (\n <section key={column.id} className='foundation-board-column' data-collapsed={closed} data-over={over} aria-label={formatText(strings.boardColumn, { column: column.label, count: inColumn.length })}\n onDragOver={event => { if (!locked) event.preventDefault(); }} onDrop={event => { if (!locked) drop(event, column.id); }}>\n <header className='foundation-board-header'>\n <button type='button' className='foundation-icon-button' aria-expanded={!closed} aria-label={formatText(closed ? strings.boardExpand : strings.boardCollapse, { column: column.label })} onClick={() => toggle(column.id)}>\n <FoundationIcon name={closed ? 'chevron-right' : 'chevron-down'} />\n </button>\n <h3>{column.label}</h3>\n <span className='foundation-count'>{inColumn.length}{column.limit > 0 ? ` / ${column.limit}` : ''}</span>\n {over && <span className='foundation-chip' data-tone='danger'><FoundationIcon name='alert' />{formatText(strings.boardWipExceeded, { limit: column.limit })}</span>}\n </header>\n {!closed && (\n <ul className='foundation-board-cards'>\n {inColumn.length === 0 && <li className='foundation-count'>{strings.boardNoCards}</li>}\n {inColumn.map(card => (\n <li key={card.id} className='foundation-board-card' draggable={!locked} onDragStart={() => setDragging(card.id)} onDragEnd={() => setDragging(undefined)}>\n <strong>{card.title}</strong>\n {card.assignee && <span className='foundation-count'><FoundationIcon name='user' /> {card.assignee}</span>}\n {card.fields.map(field => <span key={field.label} className='foundation-board-field'><span className='foundation-count'>{field.label}</span> {field.value}</span>)}\n {card.badges.length > 0 && <span className='foundation-board-badges'>{card.badges.map(badge => <span key={badge} className='foundation-chip' data-tone='neutral'>{badge}</span>)}</span>}\n {!locked && (\n <select className='foundation-board-move' aria-label={formatText(strings.boardMoveCard, { title: card.title })} value={column.id} onChange={event => move(card.id, event.target.value)}>\n <option value={column.id} disabled>{strings.boardMoveTo}</option>\n {columns.filter(other => other.id !== column.id).map(other => <option key={other.id} value={other.id}>{other.label}</option>)}\n </select>\n )}\n </li>\n ))}\n </ul>\n )}\n </section>\n );\n })}\n </div>\n </>\n )}\n </FoundationFrame>\n );\n}\n"],"names":["KanbanBoard","element","interactions","bindingOutputs","columns","useMemo","readColumnsOfBoard","properties","supplied","readCards","cards","suppliedKey","JSON","stringify","setCards","useState","collapsed","setCollapsed","Set","announcement","setAnnouncement","dragging","setDragging","strings","readFoundationStrings","state","readComponentState","length","locked","readPermissionRule","useEffect","useValueOutput","map","card","id","column","move","to","find","candidate","target","next","moveCard","formatText","boardMoved","title","label","onChange","drop","event","preventDefault","undefined","toggle","current","has","delete","add","_jsx","FoundationFrame","name","skeleton","ComponentState","Ready","Partial","_jsxs","_Fragment","div","role","aria-live","className","inColumn","cardsOf","closed","over","overLimit","section","data-collapsed","data-over","aria-label","boardColumn","count","onDragOver","onDrop","header","button","type","aria-expanded","boardExpand","boardCollapse","onClick","FoundationIcon","h3","span","limit","data-tone","boardWipExceeded","ul","li","boardNoCards","draggable","onDragStart","onDragEnd","strong","assignee","fields","field","value","badges","badge","select","boardMoveCard","option","disabled","boardMoveTo","filter","other"],"mappings":";;;;;;;;;;;;AAYA;;;;;;;;IASO,SAASA,WAAAA,CAAY,EAAEC,OAAO,EAAEC,YAAY,EAAEC,cAAc,EAA4B,EAAA;IAC3F,MAAMC,OAAAA,GAAUC,cAAQ,IAAMC,6BAAAA,CAAmBL,QAAQM,UAAU,CAACH,OAAO,CAAA,EAAG;QAACH,OAAAA,CAAQM,UAAU,CAACH;AAAQ,KAAA,CAAA;IAC1G,MAAMI,QAAAA,GAAWH,cAAQ,IAAMI,oBAAAA,CAAUR,QAAQM,UAAU,CAACG,KAAK,CAAA,EAAG;QAACT,OAAAA,CAAQM,UAAU,CAACG;AAAM,KAAA,CAAA;IAC9F,MAAMC,WAAAA,GAAcC,IAAAA,CAAKC,SAAS,CAACL,QAAAA,CAAAA;AACnC,IAAA,MAAM,CAACE,KAAAA,EAAOI,QAAAA,CAAS,GAAGC,cAAAA,CAAsBP,QAAAA,CAAAA;AAChD,IAAA,MAAM,CAACQ,SAAAA,EAAWC,YAAAA,CAAa,GAAGF,eAAsB,IAAIG,GAAAA,EAAAA,CAAAA;AAC5D,IAAA,MAAM,CAACC,YAAAA,EAAcC,eAAAA,CAAgB,GAAGL,cAAAA,CAAS,EAAA,CAAA;IACjD,MAAM,CAACM,QAAAA,EAAUC,WAAAA,CAAY,GAAGP,cAAAA,EAAAA;AAChC,IAAA,MAAMQ,UAAUC,uCAAAA,CAAsBvB,OAAAA,CAAAA;AACtC,IAAA,MAAMwB,KAAAA,GAAQC,iCAAAA,CAAmBzB,OAAAA,EAASG,OAAAA,CAAQuB,MAAM,GAAG,CAAA,CAAA;IAC3D,MAAMC,MAAAA,GAASC,iCAAAA,CAAmB5B,OAAAA,EAAS,gBAAA,CAAA,KAAsB,SAAA;IAEjE6B,eAAAA,CAAU,IAAMhB,SAASN,QAAAA,CAAAA,EAAW;AAACG,QAAAA;AAAY,KAAA,CAAA;AACjDoB,IAAAA,0BAAAA,CAAe5B,gBAAgBO,KAAAA,CAAMsB,GAAG,CAACC,CAAAA,QAAS;AAAEC,YAAAA,EAAAA,EAAID,KAAKC,EAAE;AAAEC,YAAAA,MAAAA,EAAQF,KAAKE;SAAO,CAAA,CAAA,CAAA;IAErF,MAAMC,IAAAA,GAAO,CAACF,EAAAA,EAAYG,EAAAA,GAAAA;QACtB,MAAMJ,IAAAA,GAAOvB,MAAM4B,IAAI,CAACC,CAAAA,SAAAA,GAAaA,SAAAA,CAAUL,EAAE,KAAKA,EAAAA,CAAAA;QACtD,MAAMM,MAAAA,GAASpC,QAAQkC,IAAI,CAACH,CAAAA,MAAAA,GAAUA,MAAAA,CAAOD,EAAE,KAAKG,EAAAA,CAAAA;AACpD,QAAA,MAAMI,IAAAA,GAAOC,mBAAAA,CAAStC,OAAAA,EAASM,KAAAA,EAAOwB,EAAAA,EAAIG,EAAAA,CAAAA;AAC1C,QAAA,IAAI,CAACJ,IAAAA,IAAQ,CAACO,MAAAA,IAAUC,SAAS/B,KAAAA,EAAO;QACxCI,QAAAA,CAAS2B,IAAAA,CAAAA;QACTrB,eAAAA,CAAgBuB,4BAAAA,CAAWpB,OAAAA,CAAQqB,UAAU,EAAE;AAAEC,YAAAA,KAAAA,EAAOZ,KAAKY,KAAK;AAAEV,YAAAA,MAAAA,EAAQK,OAAOM;AAAM,SAAA,CAAA,CAAA;QACzF5C,YAAAA,EAAc6C,QAAAA,IAAAA;AAClB,IAAA,CAAA;IACA,MAAMC,IAAAA,GAAO,CAACC,KAAAA,EAAkBZ,EAAAA,GAAAA;AAAiBY,QAAAA,KAAAA,CAAMC,cAAc,EAAA;QAAI,IAAI7B,QAAAA,EAAUe,KAAKf,QAAAA,EAAUgB,EAAAA,CAAAA;QAAKf,WAAAA,CAAY6B,SAAAA,CAAAA;AAAY,IAAA,CAAA;AACnI,IAAA,MAAMC,MAAAA,GAAS,CAAClB,EAAAA,GAAejB,YAAAA,CAAaoC,CAAAA,OAAAA,GAAAA;YAAa,MAAMZ,IAAAA,GAAO,IAAIvB,GAAAA,CAAImC,OAAAA,CAAAA;AAAU,YAAA,IAAIZ,KAAKa,GAAG,CAACpB,EAAAA,CAAAA,EAAKO,IAAAA,CAAKc,MAAM,CAACrB,EAAAA,CAAAA;AAAUO,iBAAAA,IAAAA,CAAKe,GAAG,CAACtB,EAAAA,CAAAA;YAAK,OAAOO,IAAAA;AAAM,QAAA,CAAA,CAAA;AAE3J,IAAA,qBACIgB,cAAA,CAACC,0BAAAA,EAAAA;QAAgBzD,OAAAA,EAASA,OAAAA;QAASC,YAAAA,EAAcA,YAAAA;QAAcyD,IAAAA,EAAK,cAAA;QAAelC,KAAAA,EAAOA,KAAAA;QAAOmC,QAAAA,EAAU;AAAC,YAAA,GAAA;AAAK,YAAA,GAAA;AAAK,YAAA;AAAI,SAAA;kBACrH,CAACnC,UAAUoC,6BAAAA,CAAeC,KAAK,IAAIrC,KAAAA,KAAUoC,6BAAAA,CAAeE,OAAM,mBAC/DC,eAAA,CAAAC,mBAAA,EAAA;;8BACIR,cAAA,CAACS,KAAAA,EAAAA;oBAAIC,IAAAA,EAAK,QAAA;oBAASC,WAAAA,EAAU,QAAA;oBAASC,SAAAA,EAAU,4BAAA;AAA8BlD,oBAAAA,QAAAA,EAAAA;;8BAC9EsC,cAAA,CAACS,KAAAA,EAAAA;oBAAIG,SAAAA,EAAU,kBAAA;8BACVjE,OAAAA,CAAQ4B,GAAG,CAAC,CAACG,MAAAA,GAAAA;AACV,wBAAA,MAAMmC,QAAAA,GAAWC,kBAAAA,CAAQnE,OAAAA,EAASM,KAAAA,EAAOyB,OAAOD,EAAE,CAAA;AAClD,wBAAA,MAAMsC,MAAAA,GAASxD,SAAAA,CAAUsC,GAAG,CAACnB,OAAOD,EAAE,CAAA;AACtC,wBAAA,MAAMuC,IAAAA,GAAOC,oBAAAA,CAAUvC,MAAAA,EAAQmC,QAAAA,CAAS3C,MAAM,CAAA;AAC9C,wBAAA,qBACIqC,eAAA,CAACW,SAAAA,EAAAA;4BAAwBN,SAAAA,EAAU,yBAAA;4BAA0BO,gBAAAA,EAAgBJ,MAAAA;4BAAQK,WAAAA,EAAWJ,IAAAA;4BAAMK,YAAAA,EAAYnC,4BAAAA,CAAWpB,OAAAA,CAAQwD,WAAW,EAAE;AAAE5C,gCAAAA,MAAAA,EAAQA,OAAOW,KAAK;AAAEkC,gCAAAA,KAAAA,EAAOV,SAAS3C;AAAO,6BAAA,CAAA;AAC7LsD,4BAAAA,UAAAA,EAAYhC,CAAAA,KAAAA,GAAAA;gCAAW,IAAI,CAACrB,MAAAA,EAAQqB,KAAAA,CAAMC,cAAc,EAAA;AAAI,4BAAA,CAAA;AAAGgC,4BAAAA,MAAAA,EAAQjC,CAAAA,KAAAA,GAAAA;AAAW,gCAAA,IAAI,CAACrB,MAAAA,EAAQoB,IAAAA,CAAKC,KAAAA,EAAOd,OAAOD,EAAE,CAAA;AAAG,4BAAA,CAAA;;8CACvH8B,eAAA,CAACmB,QAAAA,EAAAA;oCAAOd,SAAAA,EAAU,yBAAA;;sDACdZ,cAAA,CAAC2B,QAAAA,EAAAA;4CAAOC,IAAAA,EAAK,QAAA;4CAAShB,SAAAA,EAAU,wBAAA;AAAyBiB,4CAAAA,eAAAA,EAAe,CAACd,MAAAA;AAAQM,4CAAAA,YAAAA,EAAYnC,6BAAW6B,MAAAA,GAASjD,OAAAA,CAAQgE,WAAW,GAAGhE,OAAAA,CAAQiE,aAAa,EAAE;AAAErD,gDAAAA,MAAAA,EAAQA,OAAOW;AAAM,6CAAA,CAAA;4CAAI2C,OAAAA,EAAS,IAAMrC,MAAAA,CAAOjB,MAAAA,CAAOD,EAAE,CAAA;AACpN,4CAAA,QAAA,gBAAAuB,cAAA,CAACiC,6BAAAA,EAAAA;AAAe/B,gDAAAA,IAAAA,EAAMa,SAAS,eAAA,GAAkB;;;sDAErDf,cAAA,CAACkC,IAAAA,EAAAA;AAAIxD,4CAAAA,QAAAA,EAAAA,MAAAA,CAAOW;;sDACZkB,eAAA,CAAC4B,MAAAA,EAAAA;4CAAKvB,SAAAA,EAAU,kBAAA;;AAAoBC,gDAAAA,QAAAA,CAAS3C,MAAM;gDAAEQ,MAAAA,CAAO0D,KAAK,GAAG,CAAA,GAAI,CAAC,GAAG,EAAE1D,MAAAA,CAAO0D,KAAK,CAAA,CAAE,GAAG;;;AAC9FpB,wCAAAA,IAAAA,kBAAQT,eAAA,CAAC4B,MAAAA,EAAAA;4CAAKvB,SAAAA,EAAU,iBAAA;4CAAkByB,WAAAA,EAAU,QAAA;;8DAASrC,cAAA,CAACiC,6BAAAA,EAAAA;oDAAe/B,IAAAA,EAAK;;gDAAWhB,4BAAAA,CAAWpB,OAAAA,CAAQwE,gBAAgB,EAAE;AAAEF,oDAAAA,KAAAA,EAAO1D,OAAO0D;AAAM,iDAAA;;;;;AAE5J,gCAAA,CAACrB,wBACER,eAAA,CAACgC,IAAAA,EAAAA;oCAAG3B,SAAAA,EAAU,wBAAA;;wCACTC,QAAAA,CAAS3C,MAAM,KAAK,CAAA,kBAAK8B,cAAA,CAACwC,IAAAA,EAAAA;4CAAG5B,SAAAA,EAAU,kBAAA;AAAoB9C,4CAAAA,QAAAA,EAAAA,OAAAA,CAAQ2E;;AACnE5B,wCAAAA,QAAAA,CAAStC,GAAG,CAACC,CAAAA,IAAAA,iBACV+B,eAAA,CAACiC,IAAAA,EAAAA;gDAAiB5B,SAAAA,EAAU,uBAAA;AAAwB8B,gDAAAA,SAAAA,EAAW,CAACvE,MAAAA;gDAAQwE,WAAAA,EAAa,IAAM9E,WAAAA,CAAYW,IAAAA,CAAKC,EAAE,CAAA;AAAGmE,gDAAAA,SAAAA,EAAW,IAAM/E,WAAAA,CAAY6B,SAAAA,CAAAA;;kEAC1IM,cAAA,CAAC6C,QAAAA,EAAAA;AAAQrE,wDAAAA,QAAAA,EAAAA,IAAAA,CAAKY;;oDACbZ,IAAAA,CAAKsE,QAAQ,kBAAIvC,eAAA,CAAC4B,MAAAA,EAAAA;wDAAKvB,SAAAA,EAAU,kBAAA;;0EAAmBZ,cAAA,CAACiC,6BAAAA,EAAAA;gEAAe/B,IAAAA,EAAK;;AAAS,4DAAA,GAAA;AAAE1B,4DAAAA,IAAAA,CAAKsE;;;AACzFtE,oDAAAA,IAAAA,CAAKuE,MAAM,CAACxE,GAAG,CAACyE,CAAAA,sBAASzC,eAAA,CAAC4B,MAAAA,EAAAA;4DAAuBvB,SAAAA,EAAU,wBAAA;;8EAAyBZ,cAAA,CAACmC,MAAAA,EAAAA;oEAAKvB,SAAAA,EAAU,kBAAA;AAAoBoC,oEAAAA,QAAAA,EAAAA,KAAAA,CAAM3D;;AAAa,gEAAA,GAAA;AAAE2D,gEAAAA,KAAAA,CAAMC;;AAA/GD,yDAAAA,EAAAA,KAAAA,CAAM3D,KAAK,CAAA,CAAA;AAC/Cb,oDAAAA,IAAAA,CAAK0E,MAAM,CAAChF,MAAM,GAAG,mBAAK8B,cAAA,CAACmC,MAAAA,EAAAA;wDAAKvB,SAAAA,EAAU,yBAAA;AAA2BpC,wDAAAA,QAAAA,EAAAA,IAAAA,CAAK0E,MAAM,CAAC3E,GAAG,CAAC4E,CAAAA,sBAASnD,cAAA,CAACmC,MAAAA,EAAAA;gEAAiBvB,SAAAA,EAAU,iBAAA;gEAAkByB,WAAAA,EAAU,SAAA;AAAWc,gEAAAA,QAAAA,EAAAA;AAAxDA,6DAAAA,EAAAA,KAAAA,CAAAA;;AACzG,oDAAA,CAAChF,wBACEoC,eAAA,CAAC6C,QAAAA,EAAAA;wDAAOxC,SAAAA,EAAU,uBAAA;wDAAwBS,YAAAA,EAAYnC,4BAAAA,CAAWpB,OAAAA,CAAQuF,aAAa,EAAE;AAAEjE,4DAAAA,KAAAA,EAAOZ,KAAKY;AAAM,yDAAA,CAAA;AAAI6D,wDAAAA,KAAAA,EAAOvE,OAAOD,EAAE;wDAAEa,QAAAA,EAAUE,CAAAA,QAASb,IAAAA,CAAKH,IAAAA,CAAKC,EAAE,EAAEe,KAAAA,CAAMT,MAAM,CAACkE,KAAK,CAAA;;0EACjLjD,cAAA,CAACsD,QAAAA,EAAAA;AAAOL,gEAAAA,KAAAA,EAAOvE,OAAOD,EAAE;gEAAE8E,QAAQ,EAAA,IAAA;AAAEzF,gEAAAA,QAAAA,EAAAA,OAAAA,CAAQ0F;;AAC3C7G,4DAAAA,OAAAA,CAAQ8G,MAAM,CAACC,CAAAA,KAAAA,GAASA,MAAMjF,EAAE,KAAKC,MAAAA,CAAOD,EAAE,CAAA,CAAEF,GAAG,CAACmF,CAAAA,sBAAS1D,cAAA,CAACsD,QAAAA,EAAAA;AAAsBL,oEAAAA,KAAAA,EAAOS,MAAMjF,EAAE;AAAGiF,oEAAAA,QAAAA,EAAAA,KAAAA,CAAMrE;AAAlCqE,iEAAAA,EAAAA,KAAAA,CAAMjF,EAAE,CAAA;;;;AARtFD,6CAAAA,EAAAA,IAAAA,CAAKC,EAAE,CAAA;;;;AAdlBC,yBAAAA,EAAAA,MAAAA,CAAOD,EAAE,CAAA;AA+B/B,oBAAA,CAAA;;;;;AAMxB;;"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var FoundationIcon = require('./FoundationIcon.js');
|
|
5
|
+
var formatting = require('./formatting.js');
|
|
6
|
+
var foundationStrings = require('./foundationStrings.js');
|
|
7
|
+
|
|
8
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
9
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
10
|
+
/**
|
|
11
|
+
* The `notificationsButton` component: the bell of the topbar, with the unread count.
|
|
12
|
+
*
|
|
13
|
+
* `count` is the unread number - bind it to a query - and the button says it in words ("3 unread") as well as in the badge, which is hidden from
|
|
14
|
+
* assistive technology so it is not read twice. Pressing it runs the behaviors attached to the element, which open whatever the application shows its
|
|
15
|
+
* notifications in. Counts above 99 read "99+" in the badge and in full in the words.
|
|
16
|
+
*/ function NotificationsButton({ element, interactions }) {
|
|
17
|
+
const strings = foundationStrings.readFoundationStrings(element);
|
|
18
|
+
const count = typeof element.properties.count === 'number' && element.properties.count > 0 ? Math.floor(element.properties.count) : 0;
|
|
19
|
+
const spoken = count > 0 ? foundationStrings.formatText(strings.notificationsCount, {
|
|
20
|
+
count: formatting.formatNumber(count, formatting.readLocale(element), formatting.NumberFormat.Number, undefined, 0)
|
|
21
|
+
}) : strings.notificationsNone;
|
|
22
|
+
return /*#__PURE__*/ jsxRuntime.jsxs("button", {
|
|
23
|
+
type: "button",
|
|
24
|
+
className: "foundation foundation-notifications",
|
|
25
|
+
"data-scene-id": element.id,
|
|
26
|
+
onClick: interactions?.onClick,
|
|
27
|
+
children: [
|
|
28
|
+
/*#__PURE__*/ jsxRuntime.jsx(FoundationIcon.FoundationIcon, {
|
|
29
|
+
name: "alert"
|
|
30
|
+
}),
|
|
31
|
+
/*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
32
|
+
className: "foundation-visually-hidden",
|
|
33
|
+
children: `${strings.notificationsLabel}: ${spoken}`
|
|
34
|
+
}),
|
|
35
|
+
count > 0 && /*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
36
|
+
className: "foundation-notifications-badge",
|
|
37
|
+
"aria-hidden": "true",
|
|
38
|
+
children: count > 99 ? '99+' : count
|
|
39
|
+
})
|
|
40
|
+
]
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
exports.NotificationsButton = NotificationsButton;
|
|
45
|
+
//# sourceMappingURL=NotificationsButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationsButton.js","sources":["../../../foundation/NotificationsButton.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { RegisteredComponentProps } from '@cratis/scene.react';\nimport { FoundationIcon } from './FoundationIcon';\nimport { formatNumber, readLocale, NumberFormat } from './formatting';\nimport { formatText, readFoundationStrings } from './foundationStrings';\n\n/**\n * The `notificationsButton` component: the bell of the topbar, with the unread count.\n *\n * `count` is the unread number - bind it to a query - and the button says it in words (\"3 unread\") as well as in the badge, which is hidden from\n * assistive technology so it is not read twice. Pressing it runs the behaviors attached to the element, which open whatever the application shows its\n * notifications in. Counts above 99 read \"99+\" in the badge and in full in the words.\n */\nexport function NotificationsButton({ element, interactions }: RegisteredComponentProps) {\n const strings = readFoundationStrings(element);\n const count = typeof element.properties.count === 'number' && element.properties.count > 0 ? Math.floor(element.properties.count) : 0;\n const spoken = count > 0 ? formatText(strings.notificationsCount, { count: formatNumber(count, readLocale(element), NumberFormat.Number, undefined, 0) }) : strings.notificationsNone;\n\n return (\n <button type='button' className='foundation foundation-notifications' data-scene-id={element.id} onClick={interactions?.onClick}>\n <FoundationIcon name='alert' />\n <span className='foundation-visually-hidden'>{`${strings.notificationsLabel}: ${spoken}`}</span>\n {count > 0 && <span className='foundation-notifications-badge' aria-hidden='true'>{count > 99 ? '99+' : count}</span>}\n </button>\n );\n}\n"],"names":["NotificationsButton","element","interactions","strings","readFoundationStrings","count","properties","Math","floor","spoken","formatText","notificationsCount","formatNumber","readLocale","NumberFormat","Number","undefined","notificationsNone","_jsxs","button","type","className","data-scene-id","id","onClick","_jsx","FoundationIcon","name","span","notificationsLabel","aria-hidden"],"mappings":";;;;;;;AAAA;AACA;AAOA;;;;;;AAMC,IACM,SAASA,mBAAAA,CAAoB,EAAEC,OAAO,EAAEC,YAAY,EAA4B,EAAA;AACnF,IAAA,MAAMC,UAAUC,uCAAAA,CAAsBH,OAAAA,CAAAA;IACtC,MAAMI,KAAAA,GAAQ,OAAOJ,OAAAA,CAAQK,UAAU,CAACD,KAAK,KAAK,YAAYJ,OAAAA,CAAQK,UAAU,CAACD,KAAK,GAAG,IAAIE,IAAAA,CAAKC,KAAK,CAACP,OAAAA,CAAQK,UAAU,CAACD,KAAK,CAAA,GAAI,CAAA;AACpI,IAAA,MAAMI,SAASJ,KAAAA,GAAQ,CAAA,GAAIK,4BAAAA,CAAWP,OAAAA,CAAQQ,kBAAkB,EAAE;AAAEN,QAAAA,KAAAA,EAAOO,wBAAaP,KAAAA,EAAOQ,qBAAAA,CAAWZ,UAAUa,uBAAAA,CAAaC,MAAM,EAAEC,SAAAA,EAAW,CAAA;AAAG,KAAA,CAAA,GAAKb,QAAQc,iBAAiB;AAErL,IAAA,qBACIC,eAAA,CAACC,QAAAA,EAAAA;QAAOC,IAAAA,EAAK,QAAA;QAASC,SAAAA,EAAU,qCAAA;AAAsCC,QAAAA,eAAAA,EAAerB,QAAQsB,EAAE;AAAEC,QAAAA,OAAAA,EAAStB,YAAAA,EAAcsB,OAAAA;;0BACpHC,cAAA,CAACC,6BAAAA,EAAAA;gBAAeC,IAAAA,EAAK;;0BACrBF,cAAA,CAACG,MAAAA,EAAAA;gBAAKP,SAAAA,EAAU,4BAAA;AAA8B,gBAAA,QAAA,EAAA,CAAA,EAAGlB,OAAAA,CAAQ0B,kBAAkB,CAAC,EAAE,EAAEpB,MAAAA,CAAAA;;AAC/EJ,YAAAA,KAAAA,GAAQ,mBAAKoB,cAAA,CAACG,MAAAA,EAAAA;gBAAKP,SAAAA,EAAU,gCAAA;gBAAiCS,aAAAA,EAAY,MAAA;AAAQzB,gBAAAA,QAAAA,EAAAA,KAAAA,GAAQ,KAAK,KAAA,GAAQA;;;;AAGpH;;"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var scene_react = require('@cratis/scene.react');
|
|
6
|
+
var elementProperties = require('../shell/elementProperties.js');
|
|
7
|
+
var tabModel = require('./tabModel.js');
|
|
8
|
+
var ComponentState = require('./ComponentState.js');
|
|
9
|
+
var foundationStrings = require('./foundationStrings.js');
|
|
10
|
+
var StateFrame = require('./StateFrame.js');
|
|
11
|
+
var urlState = require('./urlState.js');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The `subNavigation` component: a module's own sections as a tab bar or a left rail.
|
|
15
|
+
*
|
|
16
|
+
* `items` name the sections (id, label, optional count badge), `orientation` is `horizontal` (tabs, default) or `vertical` (a left rail), and
|
|
17
|
+
* `urlKey` keeps the active section in the address so a deep link restores it. It is a navigation landmark, the current section carries
|
|
18
|
+
* `aria-current="page"`, and choosing a section only changes the section: the shell around it keeps its state, which is what makes it a
|
|
19
|
+
* sub-navigation rather than a page change. The id of the active section is the `value` output, which the module's content binds to.
|
|
20
|
+
*/ function SubNavigation({ element, interactions, bindingOutputs }) {
|
|
21
|
+
const items = react.useMemo(()=>tabModel.readTabs(element.properties.items), [
|
|
22
|
+
element.properties.items
|
|
23
|
+
]);
|
|
24
|
+
const [requested, setRequested] = urlState.useUrlState(elementProperties.readOptionalString(element, 'urlKey'), elementProperties.readOptionalString(element, 'activeItem'));
|
|
25
|
+
const active = tabModel.activeTab(items, requested);
|
|
26
|
+
const strings = foundationStrings.readFoundationStrings(element);
|
|
27
|
+
const state = ComponentState.readComponentState(element, items.length > 0);
|
|
28
|
+
scene_react.useValueOutput(bindingOutputs, active);
|
|
29
|
+
return /*#__PURE__*/ jsxRuntime.jsx(StateFrame.FoundationFrame, {
|
|
30
|
+
element: element,
|
|
31
|
+
interactions: interactions,
|
|
32
|
+
name: "sub-navigation",
|
|
33
|
+
state: state,
|
|
34
|
+
skeleton: [
|
|
35
|
+
50
|
|
36
|
+
],
|
|
37
|
+
children: state !== ComponentState.ComponentState.Loading && /*#__PURE__*/ jsxRuntime.jsx("nav", {
|
|
38
|
+
"aria-label": elementProperties.readOptionalString(element, 'label') ?? strings.subNavLabel,
|
|
39
|
+
className: "foundation-subnav",
|
|
40
|
+
"data-orientation": element.properties.orientation === 'vertical' ? 'vertical' : 'horizontal',
|
|
41
|
+
children: /*#__PURE__*/ jsxRuntime.jsx("ul", {
|
|
42
|
+
children: items.map((item)=>/*#__PURE__*/ jsxRuntime.jsx("li", {
|
|
43
|
+
children: /*#__PURE__*/ jsxRuntime.jsxs("a", {
|
|
44
|
+
href: `?${new URLSearchParams({
|
|
45
|
+
[elementProperties.readOptionalString(element, 'urlKey') ?? 'section']: item.id
|
|
46
|
+
}).toString()}`,
|
|
47
|
+
"aria-current": item.id === active ? 'page' : undefined,
|
|
48
|
+
"aria-disabled": item.disabled || undefined,
|
|
49
|
+
className: "foundation-subnav-link",
|
|
50
|
+
onClick: (event)=>{
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
if (!item.disabled) {
|
|
53
|
+
setRequested(item.id);
|
|
54
|
+
interactions?.onSelect?.();
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
children: [
|
|
58
|
+
item.label,
|
|
59
|
+
item.badge !== undefined && /*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
60
|
+
className: "foundation-tab-badge",
|
|
61
|
+
children: item.badge
|
|
62
|
+
})
|
|
63
|
+
]
|
|
64
|
+
})
|
|
65
|
+
}, item.id))
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exports.SubNavigation = SubNavigation;
|
|
72
|
+
//# sourceMappingURL=SubNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubNavigation.js","sources":["../../../foundation/SubNavigation.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 { useMemo } from 'react';\nimport { RegisteredComponentProps, useValueOutput } from '@cratis/scene.react';\nimport { readOptionalString } from '../shell/elementProperties';\nimport { activeTab, readTabs } from './tabModel';\nimport { ComponentState, readComponentState } from './ComponentState';\nimport { readFoundationStrings } from './foundationStrings';\nimport { FoundationFrame } from './StateFrame';\nimport { useUrlState } from './urlState';\n\n/**\n * The `subNavigation` component: a module's own sections as a tab bar or a left rail.\n *\n * `items` name the sections (id, label, optional count badge), `orientation` is `horizontal` (tabs, default) or `vertical` (a left rail), and\n * `urlKey` keeps the active section in the address so a deep link restores it. It is a navigation landmark, the current section carries\n * `aria-current=\"page\"`, and choosing a section only changes the section: the shell around it keeps its state, which is what makes it a\n * sub-navigation rather than a page change. The id of the active section is the `value` output, which the module's content binds to.\n */\nexport function SubNavigation({ element, interactions, bindingOutputs }: RegisteredComponentProps) {\n const items = useMemo(() => readTabs(element.properties.items), [element.properties.items]);\n const [requested, setRequested] = useUrlState(readOptionalString(element, 'urlKey'), readOptionalString(element, 'activeItem'));\n const active = activeTab(items, requested);\n const strings = readFoundationStrings(element);\n const state = readComponentState(element, items.length > 0);\n\n useValueOutput(bindingOutputs, active);\n\n return (\n <FoundationFrame element={element} interactions={interactions} name='sub-navigation' state={state} skeleton={[50]}>\n {state !== ComponentState.Loading && (\n <nav aria-label={readOptionalString(element, 'label') ?? strings.subNavLabel} className='foundation-subnav' data-orientation={element.properties.orientation === 'vertical' ? 'vertical' : 'horizontal'}>\n <ul>\n {items.map(item => (\n <li key={item.id}>\n <a href={`?${new URLSearchParams({ [readOptionalString(element, 'urlKey') ?? 'section']: item.id }).toString()}`} aria-current={item.id === active ? 'page' : undefined}\n aria-disabled={item.disabled || undefined} className='foundation-subnav-link'\n onClick={event => { event.preventDefault(); if (!item.disabled) { setRequested(item.id); interactions?.onSelect?.(); } }}>\n {item.label}{item.badge !== undefined && <span className='foundation-tab-badge'>{item.badge}</span>}\n </a>\n </li>\n ))}\n </ul>\n </nav>\n )}\n </FoundationFrame>\n );\n}\n"],"names":["SubNavigation","element","interactions","bindingOutputs","items","useMemo","readTabs","properties","requested","setRequested","useUrlState","readOptionalString","active","activeTab","strings","readFoundationStrings","state","readComponentState","length","useValueOutput","_jsx","FoundationFrame","name","skeleton","ComponentState","Loading","nav","aria-label","subNavLabel","className","data-orientation","orientation","ul","map","item","li","_jsxs","a","href","URLSearchParams","id","toString","aria-current","undefined","aria-disabled","disabled","onClick","event","preventDefault","onSelect","label","badge","span"],"mappings":";;;;;;;;;;;;AAYA;;;;;;;IAQO,SAASA,aAAAA,CAAc,EAAEC,OAAO,EAAEC,YAAY,EAAEC,cAAc,EAA4B,EAAA;IAC7F,MAAMC,KAAAA,GAAQC,cAAQ,IAAMC,iBAAAA,CAASL,QAAQM,UAAU,CAACH,KAAK,CAAA,EAAG;QAACH,OAAAA,CAAQM,UAAU,CAACH;AAAM,KAAA,CAAA;IAC1F,MAAM,CAACI,WAAWC,YAAAA,CAAa,GAAGC,qBAAYC,oCAAAA,CAAmBV,OAAAA,EAAS,QAAA,CAAA,EAAWU,oCAAAA,CAAmBV,OAAAA,EAAS,YAAA,CAAA,CAAA;IACjH,MAAMW,MAAAA,GAASC,mBAAUT,KAAAA,EAAOI,SAAAA,CAAAA;AAChC,IAAA,MAAMM,UAAUC,uCAAAA,CAAsBd,OAAAA,CAAAA;AACtC,IAAA,MAAMe,KAAAA,GAAQC,iCAAAA,CAAmBhB,OAAAA,EAASG,KAAAA,CAAMc,MAAM,GAAG,CAAA,CAAA;AAEzDC,IAAAA,0BAAAA,CAAehB,cAAAA,EAAgBS,MAAAA,CAAAA;AAE/B,IAAA,qBACIQ,cAAA,CAACC,0BAAAA,EAAAA;QAAgBpB,OAAAA,EAASA,OAAAA;QAASC,YAAAA,EAAcA,YAAAA;QAAcoB,IAAAA,EAAK,gBAAA;QAAiBN,KAAAA,EAAOA,KAAAA;QAAOO,QAAAA,EAAU;AAAC,YAAA;AAAG,SAAA;kBAC5GP,KAAAA,KAAUQ,6BAAAA,CAAeC,OAAO,kBAC7BL,cAAA,CAACM,KAAAA,EAAAA;AAAIC,YAAAA,YAAAA,EAAYhB,oCAAAA,CAAmBV,OAAAA,EAAS,OAAA,CAAA,IAAYa,OAAAA,CAAQc,WAAW;YAAEC,SAAAA,EAAU,mBAAA;AAAoBC,YAAAA,kBAAAA,EAAkB7B,QAAQM,UAAU,CAACwB,WAAW,KAAK,aAAa,UAAA,GAAa,YAAA;AACvL,YAAA,QAAA,gBAAAX,cAAA,CAACY,IAAAA,EAAAA;AACI5B,gBAAAA,QAAAA,EAAAA,KAAAA,CAAM6B,GAAG,CAACC,CAAAA,IAAAA,iBACPd,cAAA,CAACe,IAAAA,EAAAA;AACG,wBAAA,QAAA,gBAAAC,eAAA,CAACC,GAAAA,EAAAA;AAAEC,4BAAAA,IAAAA,EAAM,CAAC,CAAC,EAAE,IAAIC,eAAAA,CAAgB;AAAE,gCAAA,CAAC5B,qCAAmBV,OAAAA,EAAS,QAAA,CAAA,IAAa,SAAA,GAAYiC,KAAKM;AAAG,6BAAA,CAAA,CAAGC,QAAQ,EAAA,CAAA,CAAI;AAAEC,4BAAAA,cAAAA,EAAcR,IAAAA,CAAKM,EAAE,KAAK5B,MAAAA,GAAS,MAAA,GAAS+B,SAAAA;4BAC1JC,eAAAA,EAAeV,IAAAA,CAAKW,QAAQ,IAAIF,SAAAA;4BAAWd,SAAAA,EAAU,wBAAA;AACrDiB,4BAAAA,OAAAA,EAASC,CAAAA,KAAAA,GAAAA;AAAWA,gCAAAA,KAAAA,CAAMC,cAAc,EAAA;gCAAI,IAAI,CAACd,IAAAA,CAAKW,QAAQ,EAAE;AAAEpC,oCAAAA,YAAAA,CAAayB,KAAKM,EAAE,CAAA;oCAAGtC,YAAAA,EAAc+C,QAAAA,IAAAA;AAAc,gCAAA;AAAE,4BAAA,CAAA;;AACtHf,gCAAAA,IAAAA,CAAKgB,KAAK;gCAAEhB,IAAAA,CAAKiB,KAAK,KAAKR,SAAAA,kBAAavB,cAAA,CAACgC,MAAAA,EAAAA;oCAAKvB,SAAAA,EAAU,sBAAA;AAAwBK,oCAAAA,QAAAA,EAAAA,IAAAA,CAAKiB;;;;AAJrFjB,qBAAAA,EAAAA,IAAAA,CAAKM,EAAE,CAAA;;;;AAa5C;;"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var scene_react = require('@cratis/scene.react');
|
|
6
|
+
var elementProperties = require('../shell/elementProperties.js');
|
|
7
|
+
var tabModel = require('./tabModel.js');
|
|
8
|
+
var ComponentState = require('./ComponentState.js');
|
|
9
|
+
var foundationStrings = require('./foundationStrings.js');
|
|
10
|
+
var StateFrame = require('./StateFrame.js');
|
|
11
|
+
var urlState = require('./urlState.js');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The `tabSet` component: a set of tabs, each showing the content filed under its id in the element's slots.
|
|
15
|
+
*
|
|
16
|
+
* `tabs` name the tabs (id, label, optional count badge, disabled); the content of tab `overview` is the slot `overview`. It follows the
|
|
17
|
+
* ARIA tabs pattern - arrows, Home and End move and select, the active tab is the one tab stop, each panel is labelled by its tab - and the
|
|
18
|
+
* active tab is kept in the address under `urlKey` when one is given, so a deep link and a refresh restore it. The id of the active tab is the
|
|
19
|
+
* `value` output. The tabs a record page offers (Overview, Related, Files, History) are configurable by changing this property.
|
|
20
|
+
*/ function TabSet({ element, interactions, slots, bindingOutputs }) {
|
|
21
|
+
const tabs = react.useMemo(()=>tabModel.readTabs(element.properties.tabs), [
|
|
22
|
+
element.properties.tabs
|
|
23
|
+
]);
|
|
24
|
+
const [requested, setRequested] = urlState.useUrlState(elementProperties.readOptionalString(element, 'urlKey'), elementProperties.readOptionalString(element, 'activeTab'));
|
|
25
|
+
const active = tabModel.activeTab(tabs, requested);
|
|
26
|
+
const strings = foundationStrings.readFoundationStrings(element);
|
|
27
|
+
const state = ComponentState.readComponentState(element, tabs.length > 0);
|
|
28
|
+
const list = react.useRef(null);
|
|
29
|
+
scene_react.useValueOutput(bindingOutputs, active);
|
|
30
|
+
const choose = (id, focus = false)=>{
|
|
31
|
+
if (id === undefined) return;
|
|
32
|
+
setRequested(id);
|
|
33
|
+
interactions?.onSelect?.();
|
|
34
|
+
if (focus) requestAnimationFrame(()=>list.current?.querySelector(`[data-tab="${CSS.escape(id)}"]`)?.focus());
|
|
35
|
+
};
|
|
36
|
+
const move = (event)=>{
|
|
37
|
+
const direction = {
|
|
38
|
+
ArrowRight: 'next',
|
|
39
|
+
ArrowDown: 'next',
|
|
40
|
+
ArrowLeft: 'previous',
|
|
41
|
+
ArrowUp: 'previous',
|
|
42
|
+
Home: 'first',
|
|
43
|
+
End: 'last'
|
|
44
|
+
}[event.key];
|
|
45
|
+
if (direction === undefined) return;
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
choose(tabModel.stepTab(tabs, active, direction), true);
|
|
48
|
+
};
|
|
49
|
+
return /*#__PURE__*/ jsxRuntime.jsx(StateFrame.FoundationFrame, {
|
|
50
|
+
element: element,
|
|
51
|
+
interactions: interactions,
|
|
52
|
+
name: "tab-set",
|
|
53
|
+
state: state,
|
|
54
|
+
skeleton: [
|
|
55
|
+
60,
|
|
56
|
+
100
|
|
57
|
+
],
|
|
58
|
+
children: state !== ComponentState.ComponentState.Loading && /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
59
|
+
children: [
|
|
60
|
+
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
61
|
+
ref: list,
|
|
62
|
+
role: "tablist",
|
|
63
|
+
"aria-label": elementProperties.readOptionalString(element, 'label') ?? strings.tabsLabel,
|
|
64
|
+
className: "foundation-tabs",
|
|
65
|
+
onKeyDown: move,
|
|
66
|
+
children: tabs.map((tab)=>/*#__PURE__*/ jsxRuntime.jsxs("button", {
|
|
67
|
+
id: `${element.id}-tab-${tab.id}`,
|
|
68
|
+
"data-tab": tab.id,
|
|
69
|
+
type: "button",
|
|
70
|
+
role: "tab",
|
|
71
|
+
className: "foundation-tab",
|
|
72
|
+
"aria-selected": tab.id === active,
|
|
73
|
+
"aria-controls": `${element.id}-panel-${tab.id}`,
|
|
74
|
+
tabIndex: tab.id === active ? 0 : -1,
|
|
75
|
+
disabled: tab.disabled,
|
|
76
|
+
onClick: ()=>choose(tab.id),
|
|
77
|
+
children: [
|
|
78
|
+
tab.label,
|
|
79
|
+
tab.badge !== undefined && /*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
80
|
+
className: "foundation-tab-badge",
|
|
81
|
+
children: tab.badge
|
|
82
|
+
})
|
|
83
|
+
]
|
|
84
|
+
}, tab.id))
|
|
85
|
+
}),
|
|
86
|
+
tabs.map((tab)=>/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
87
|
+
id: `${element.id}-panel-${tab.id}`,
|
|
88
|
+
role: "tabpanel",
|
|
89
|
+
"aria-labelledby": `${element.id}-tab-${tab.id}`,
|
|
90
|
+
hidden: tab.id !== active,
|
|
91
|
+
tabIndex: 0,
|
|
92
|
+
className: "foundation-tab-panel",
|
|
93
|
+
children: tab.id === active ? slots?.[tab.id] : undefined
|
|
94
|
+
}, tab.id))
|
|
95
|
+
]
|
|
96
|
+
})
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
exports.TabSet = TabSet;
|
|
101
|
+
//# sourceMappingURL=TabSet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabSet.js","sources":["../../../foundation/TabSet.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, useMemo, useRef } from 'react';\nimport { RegisteredComponentProps, useValueOutput } from '@cratis/scene.react';\nimport { readOptionalString } from '../shell/elementProperties';\nimport { activeTab, readTabs, stepTab } from './tabModel';\nimport { ComponentState, readComponentState } from './ComponentState';\nimport { readFoundationStrings } from './foundationStrings';\nimport { FoundationFrame } from './StateFrame';\nimport { useUrlState } from './urlState';\n\n/**\n * The `tabSet` component: a set of tabs, each showing the content filed under its id in the element's slots.\n *\n * `tabs` name the tabs (id, label, optional count badge, disabled); the content of tab `overview` is the slot `overview`. It follows the\n * ARIA tabs pattern - arrows, Home and End move and select, the active tab is the one tab stop, each panel is labelled by its tab - and the\n * active tab is kept in the address under `urlKey` when one is given, so a deep link and a refresh restore it. The id of the active tab is the\n * `value` output. The tabs a record page offers (Overview, Related, Files, History) are configurable by changing this property.\n */\nexport function TabSet({ element, interactions, slots, bindingOutputs }: RegisteredComponentProps) {\n const tabs = useMemo(() => readTabs(element.properties.tabs), [element.properties.tabs]);\n const [requested, setRequested] = useUrlState(readOptionalString(element, 'urlKey'), readOptionalString(element, 'activeTab'));\n const active = activeTab(tabs, requested);\n const strings = readFoundationStrings(element);\n const state = readComponentState(element, tabs.length > 0);\n const list = useRef<HTMLDivElement>(null);\n\n useValueOutput(bindingOutputs, active);\n\n const choose = (id: string | undefined, focus = false) => {\n if (id === undefined) return;\n setRequested(id);\n interactions?.onSelect?.();\n if (focus) requestAnimationFrame(() => list.current?.querySelector<HTMLElement>(`[data-tab=\"${CSS.escape(id)}\"]`)?.focus());\n };\n const move = (event: KeyboardEvent) => {\n const direction = { ArrowRight: 'next', ArrowDown: 'next', ArrowLeft: 'previous', ArrowUp: 'previous', Home: 'first', End: 'last' }[event.key] as 'next' | 'previous' | 'first' | 'last' | undefined;\n if (direction === undefined) return;\n event.preventDefault();\n choose(stepTab(tabs, active, direction), true);\n };\n\n return (\n <FoundationFrame element={element} interactions={interactions} name='tab-set' state={state} skeleton={[60, 100]}>\n {state !== ComponentState.Loading && (\n <>\n <div ref={list} role='tablist' aria-label={readOptionalString(element, 'label') ?? strings.tabsLabel} className='foundation-tabs' onKeyDown={move}>\n {tabs.map(tab => (\n <button key={tab.id} id={`${element.id}-tab-${tab.id}`} data-tab={tab.id} type='button' role='tab' className='foundation-tab' aria-selected={tab.id === active}\n aria-controls={`${element.id}-panel-${tab.id}`} tabIndex={tab.id === active ? 0 : -1} disabled={tab.disabled} onClick={() => choose(tab.id)}>\n {tab.label}{tab.badge !== undefined && <span className='foundation-tab-badge'>{tab.badge}</span>}\n </button>\n ))}\n </div>\n {tabs.map(tab => (\n <div key={tab.id} id={`${element.id}-panel-${tab.id}`} role='tabpanel' aria-labelledby={`${element.id}-tab-${tab.id}`} hidden={tab.id !== active} tabIndex={0} className='foundation-tab-panel'>\n {tab.id === active ? slots?.[tab.id] : undefined}\n </div>\n ))}\n </>\n )}\n </FoundationFrame>\n );\n}\n"],"names":["TabSet","element","interactions","slots","bindingOutputs","tabs","useMemo","readTabs","properties","requested","setRequested","useUrlState","readOptionalString","active","activeTab","strings","readFoundationStrings","state","readComponentState","length","list","useRef","useValueOutput","choose","id","focus","undefined","onSelect","requestAnimationFrame","current","querySelector","CSS","escape","move","event","direction","ArrowRight","ArrowDown","ArrowLeft","ArrowUp","Home","End","key","preventDefault","stepTab","_jsx","FoundationFrame","name","skeleton","ComponentState","Loading","_jsxs","_Fragment","div","ref","role","aria-label","tabsLabel","className","onKeyDown","map","tab","button","data-tab","type","aria-selected","aria-controls","tabIndex","disabled","onClick","label","badge","span","aria-labelledby","hidden"],"mappings":"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"}
|