flexdesk 0.17.18 → 0.18.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/CHANGELOG.md +53 -0
- package/README.md +1 -0
- package/css/flexdesk.css +7544 -5916
- package/css/reset.css +1 -1
- package/css/tokens.css +23 -1
- package/dist/charts.js +10 -6
- package/dist/charts.js.map +1 -1
- package/dist/chunk-5W4EEKSK.js +778 -0
- package/dist/chunk-5W4EEKSK.js.map +7 -0
- package/dist/chunk-DNJ3N4T4.js +82 -0
- package/dist/chunk-DNJ3N4T4.js.map +7 -0
- package/dist/{chunk-REJ5HLIM.js → chunk-HYJYYEPK.js} +2 -2
- package/dist/{chunk-7U4IB65H.js → chunk-LLBJ2SJH.js} +5 -3
- package/dist/{chunk-7U4IB65H.js.map → chunk-LLBJ2SJH.js.map} +1 -1
- package/dist/{chunk-7OL6F2AM.js → chunk-P74F6I6P.js} +6 -4
- package/dist/{chunk-7OL6F2AM.js.map → chunk-P74F6I6P.js.map} +1 -1
- package/dist/chunk-PAI2ZUWV.js +260 -0
- package/dist/chunk-PAI2ZUWV.js.map +7 -0
- package/dist/chunk-Q7BALEPX.js +527 -0
- package/dist/chunk-Q7BALEPX.js.map +7 -0
- package/dist/chunk-QXAOTGCC.js +40 -0
- package/dist/chunk-QXAOTGCC.js.map +7 -0
- package/dist/{chunk-XJNADRGR.js → chunk-RKVYIXDC.js} +664 -91
- package/dist/chunk-RKVYIXDC.js.map +7 -0
- package/dist/{chunk-2Z2ENHR3.js → chunk-U5GKJUOC.js} +3 -3
- package/dist/{chunk-2Z2ENHR3.js.map → chunk-U5GKJUOC.js.map} +1 -1
- package/dist/chunk-UKP22RUG.js +219 -0
- package/dist/chunk-UKP22RUG.js.map +7 -0
- package/dist/chunk-VLOAI3HS.js +43 -0
- package/dist/chunk-VLOAI3HS.js.map +7 -0
- package/dist/{chunk-WUFLGETN.js → chunk-WVFGV5FT.js} +2 -39
- package/dist/{chunk-WUFLGETN.js.map → chunk-WVFGV5FT.js.map} +3 -3
- package/dist/{chunk-PGZ4EHSE.js → chunk-ZL3VKINP.js} +41 -390
- package/dist/chunk-ZL3VKINP.js.map +7 -0
- package/dist/editor.js +3 -2
- package/dist/editor.js.map +1 -1
- package/dist/flexdesk.css +7544 -5916
- package/dist/flow.js +29 -97
- package/dist/flow.js.map +3 -3
- package/dist/git.js +1356 -0
- package/dist/git.js.map +7 -0
- package/dist/reset.css +1 -1
- package/dist/tiles.js +20 -15
- package/dist/tiles.js.map +2 -2
- package/dist/tokens.css +23 -1
- package/dist/widgets.js +3967 -1188
- package/dist/widgets.js.map +4 -4
- package/dist/wm.js +120 -32
- package/dist/wm.js.map +2 -2
- package/docs/README.md +9 -4
- package/docs/best-practices.md +2 -2
- package/docs/components/chat-shell.md +198 -0
- package/docs/components/conversation.md +10 -0
- package/docs/components/filter-builder.md +246 -0
- package/docs/components/forms-and-dialogs.md +22 -0
- package/docs/components/git.md +355 -0
- package/docs/components/input-fields.md +167 -2
- package/docs/components/keymap.md +8 -0
- package/docs/components/menus.md +82 -2
- package/docs/components/panels-and-desktops.md +16 -5
- package/docs/components/shell.md +104 -1
- package/docs/components/workspace-picker.md +149 -0
- package/docs/concepts/building-and-packaging.md +2 -2
- package/docs/concepts/packages-and-entry-points.md +14 -13
- package/docs/concepts/state-guard.md +3 -3
- package/docs/quickstart.md +1 -1
- package/git.js +13 -0
- package/package.json +6 -1
- package/src/flow/kit/dom.js +28 -119
- package/src/flow/kit/step_picker.js +1 -1
- package/src/flow/kit/value_picker.js +1 -1
- package/src/flow/outline/menu.js +1 -1
- package/src/git/diff_viewer.js +212 -0
- package/src/git/diff_window.js +51 -0
- package/src/git/git_graph.js +401 -0
- package/src/git/git_ops.js +61 -0
- package/src/git/git_panel.js +755 -0
- package/src/git/index.js +9 -0
- package/src/git/line_diff.js +202 -0
- package/src/tiles/tile_base.js +5 -4
- package/src/tiling/desktops.js +10 -8
- package/src/tiling/keymap.js +6 -5
- package/src/tiling/kind_taxonomy.js +15 -2
- package/src/tiling/shell.js +124 -17
- package/src/tiling/tile_renderer.js +2 -3
- package/src/ui/components/action_dropdown.js +4 -78
- package/src/ui/components/anchored_layer.js +255 -0
- package/src/ui/components/chat_shell.js +920 -0
- package/src/ui/components/chat_state_machine.js +223 -0
- package/src/ui/components/choice_controls.js +45 -2
- package/src/ui/components/color_field.js +3 -2
- package/src/ui/components/color_list_field.js +3 -2
- package/src/ui/components/combobox.js +422 -0
- package/src/ui/components/conversation_view.js +17 -2
- package/src/ui/components/data_table.js +2 -2
- package/src/ui/components/filter_builder.js +766 -0
- package/src/ui/components/filter_model.js +614 -0
- package/src/ui/components/managed_window.js +24 -47
- package/src/ui/components/modal.js +79 -109
- package/src/ui/components/option_list.js +160 -0
- package/src/ui/components/popover.js +94 -0
- package/src/ui/components/recent_items.js +169 -0
- package/src/ui/components/select.js +322 -0
- package/src/ui/components/tag_input.js +77 -8
- package/src/ui/components/workspace_picker.js +1155 -0
- package/src/ui/utils/fire_event.js +17 -0
- package/src/ui/utils/focusable.js +25 -0
- package/src/ui/utils/modal_host.js +27 -0
- package/widgets.js +12 -2
- package/css/base.css +0 -10547
- package/css/overrides.css +0 -2596
- package/dist/chunk-7JI7HHSY.js +0 -107
- package/dist/chunk-7JI7HHSY.js.map +0 -7
- package/dist/chunk-MIW7D6WC.js +0 -526
- package/dist/chunk-MIW7D6WC.js.map +0 -7
- package/dist/chunk-PGZ4EHSE.js.map +0 -7
- package/dist/chunk-XJNADRGR.js.map +0 -7
- /package/dist/{chunk-REJ5HLIM.js.map → chunk-HYJYYEPK.js.map} +0 -0
|
@@ -28,12 +28,20 @@
|
|
|
28
28
|
* tags.getValue(); // ['baseline']
|
|
29
29
|
* tags.setValue(['a', 'b']);
|
|
30
30
|
* tags.dispose();
|
|
31
|
+
*
|
|
32
|
+
* `suggestions` (0.18.0) offers known tags under the box, on `attachInputOptions`:
|
|
33
|
+
* the arrow keys walk the rows, and Enter or a comma takes the active one; with none
|
|
34
|
+
* active they commit what was typed. Whatever the list's source, a row is in the one
|
|
35
|
+
* spelling, says a tag once and is not a tag already in the list. An array is filtered
|
|
36
|
+
* and ordered here, the earliest match first and then alphabetically; a function
|
|
37
|
+
* answers for itself and keeps its own order, and may be async.
|
|
38
|
+
* `normalise` (0.18.0) keeps one spelling of a tag: `Path Finding` and `path-finding`
|
|
39
|
+
* cannot both exist, whichever way one arrives. It is handed the trimmed text.
|
|
31
40
|
*/
|
|
41
|
+
import { attachInputOptions } from './combobox.js';
|
|
42
|
+
import { shownValue } from './choice_controls.js';
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
const normalise = (list) => (Array.isArray(list) ? list : [])
|
|
35
|
-
.map((v) => (v == null ? '' : String(v).trim()))
|
|
36
|
-
.filter((v) => v !== '');
|
|
44
|
+
const optionValue = (o) => (o !== null && typeof o === 'object' ? o.value : o);
|
|
37
45
|
|
|
38
46
|
/**
|
|
39
47
|
* @typedef {Object} TagInputOptions
|
|
@@ -45,6 +53,9 @@ const normalise = (list) => (Array.isArray(list) ? list : [])
|
|
|
45
53
|
* @property {string} [label] - The text box's accessible name.
|
|
46
54
|
* @property {(tag: string) => string} [removeLabel] - A remove button's `aria-label`.
|
|
47
55
|
* @property {string} [className] - Extra classes on the root.
|
|
56
|
+
* @property {Array|((query: string, ctx: {signal: AbortSignal}) => Array|Promise<Array>)} [suggestions] -
|
|
57
|
+
* Known tags: strings or `{ value, label?, description?, icon?, hint? }`.
|
|
58
|
+
* @property {(text: string) => string} [normalise] - The one spelling of a tag.
|
|
48
59
|
*/
|
|
49
60
|
|
|
50
61
|
/**
|
|
@@ -59,8 +70,16 @@ export function createTagInput(host, options = {}) {
|
|
|
59
70
|
const allowDuplicates = !!options.allowDuplicates;
|
|
60
71
|
const removeLabel = typeof options.removeLabel === 'function'
|
|
61
72
|
? options.removeLabel : (tag) => `Remove ${tag}`;
|
|
73
|
+
const spell = typeof options.normalise === 'function'
|
|
74
|
+
? (text) => String(options.normalise(text.trim()) ?? '').trim() : (text) => text.trim();
|
|
75
|
+
|
|
76
|
+
/** The list as spelled, the empty ones left out, and a repeat unless it is allowed. */
|
|
77
|
+
const cleaned = (list) => {
|
|
78
|
+
const out = (Array.isArray(list) ? list : []).map((v) => (v == null ? '' : spell(String(v)))).filter((v) => v !== '');
|
|
79
|
+
return allowDuplicates ? out : [...new Set(out)];
|
|
80
|
+
};
|
|
62
81
|
|
|
63
|
-
let tags =
|
|
82
|
+
let tags = cleaned(options.value);
|
|
64
83
|
let disposed = false;
|
|
65
84
|
|
|
66
85
|
const root = document.createElement('div');
|
|
@@ -134,7 +153,7 @@ export function createTagInput(host, options = {}) {
|
|
|
134
153
|
if (disposed || readOnly) return false;
|
|
135
154
|
const next = [...tags];
|
|
136
155
|
for (const piece of String(text).split(',')) {
|
|
137
|
-
const tag = piece
|
|
156
|
+
const tag = spell(piece);
|
|
138
157
|
if (tag === '') continue;
|
|
139
158
|
if (!allowDuplicates && next.includes(tag)) continue;
|
|
140
159
|
next.push(tag);
|
|
@@ -150,17 +169,66 @@ export function createTagInput(host, options = {}) {
|
|
|
150
169
|
return true;
|
|
151
170
|
};
|
|
152
171
|
|
|
172
|
+
/** Known tags as rows: in the one spelling, each once, less those already in the list. */
|
|
173
|
+
const offered = (list) => {
|
|
174
|
+
const seen = new Set();
|
|
175
|
+
const rows = [];
|
|
176
|
+
for (const o of list || []) {
|
|
177
|
+
const tag = spell(shownValue(optionValue(o)));
|
|
178
|
+
if (tag === '' || seen.has(tag) || (!allowDuplicates && tags.includes(tag))) continue;
|
|
179
|
+
seen.add(tag);
|
|
180
|
+
rows.push(o !== null && typeof o === 'object' ? { ...o, value: tag } : tag);
|
|
181
|
+
}
|
|
182
|
+
return rows;
|
|
183
|
+
};
|
|
184
|
+
// What is typed is the query however the list opened: an arrow key or a click
|
|
185
|
+
// reopening it must not offer rows that have nothing to do with the text in the box.
|
|
186
|
+
/** An array of known tags: those holding what is typed, the earliest match first, then alphabetically. */
|
|
187
|
+
const rankedFor = () => {
|
|
188
|
+
const needle = spell(input.value).toLowerCase();
|
|
189
|
+
const word = (o) => shownValue(optionValue(o));
|
|
190
|
+
const at = (o) => word(o).toLowerCase().indexOf(needle);
|
|
191
|
+
return offered(options.suggestions).filter((o) => at(o) >= 0)
|
|
192
|
+
.sort((x, y) => at(x) - at(y) || word(x).localeCompare(word(y)));
|
|
193
|
+
};
|
|
194
|
+
/** A function's answer, whenever it comes. */
|
|
195
|
+
const askedFor = (_query, ctx) => {
|
|
196
|
+
const answer = options.suggestions(input.value, ctx);
|
|
197
|
+
return typeof answer?.then === 'function' ? answer.then(offered) : offered(answer);
|
|
198
|
+
};
|
|
199
|
+
const asking = typeof options.suggestions === 'function';
|
|
200
|
+
|
|
201
|
+
// Before the box's own keydown listener: a row taken by Enter is not also a commit.
|
|
202
|
+
const menu = input && options.suggestions
|
|
203
|
+
? attachInputOptions(input, {
|
|
204
|
+
options: asking ? askedFor : rankedFor,
|
|
205
|
+
anchor: root,
|
|
206
|
+
normalise: spell,
|
|
207
|
+
openOnFocus: true,
|
|
208
|
+
passEnter: true,
|
|
209
|
+
debounce: asking ? undefined : 0,
|
|
210
|
+
onPick(option) {
|
|
211
|
+
input.value = '';
|
|
212
|
+
commitText(shownValue(option.value));
|
|
213
|
+
input.focus();
|
|
214
|
+
},
|
|
215
|
+
})
|
|
216
|
+
: null;
|
|
217
|
+
|
|
153
218
|
const commitInput = () => {
|
|
154
219
|
if (!input) return;
|
|
155
220
|
const text = input.value;
|
|
156
221
|
input.value = '';
|
|
222
|
+
menu?.close();
|
|
157
223
|
commitText(text);
|
|
158
224
|
};
|
|
159
225
|
|
|
160
226
|
if (input) {
|
|
161
227
|
input.addEventListener('keydown', (ev) => {
|
|
162
228
|
if (ev.isComposing) return;
|
|
163
|
-
if (ev.key === '
|
|
229
|
+
if (ev.key === ',' && menu?.takeActive()) {
|
|
230
|
+
ev.preventDefault();
|
|
231
|
+
} else if (ev.key === 'Enter' || ev.key === ',') {
|
|
164
232
|
ev.preventDefault();
|
|
165
233
|
commitInput();
|
|
166
234
|
} else if (ev.key === 'Backspace' && input.value === '' && tags.length) {
|
|
@@ -202,13 +270,14 @@ export function createTagInput(host, options = {}) {
|
|
|
202
270
|
/** Replaces the list. Does not call `onChange`. */
|
|
203
271
|
setValue(list) {
|
|
204
272
|
if (disposed) return;
|
|
205
|
-
tags =
|
|
273
|
+
tags = cleaned(list);
|
|
206
274
|
paint();
|
|
207
275
|
},
|
|
208
276
|
focus() { input?.focus(); },
|
|
209
277
|
dispose() {
|
|
210
278
|
if (disposed) return;
|
|
211
279
|
disposed = true;
|
|
280
|
+
menu?.destroy();
|
|
212
281
|
root.remove();
|
|
213
282
|
},
|
|
214
283
|
};
|