@grafloria/element 0.4.8 → 0.4.9
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/package.json
CHANGED
|
@@ -268,6 +268,12 @@ export interface DashboardHandle {
|
|
|
268
268
|
readonly activeView: string;
|
|
269
269
|
/** A widget handle by id (undefined when unknown). */
|
|
270
270
|
widget(id: string): WidgetHandle | undefined;
|
|
271
|
+
/**
|
|
272
|
+
* SELECT a widget and move keyboard focus to it — what a press on the widget
|
|
273
|
+
* does. The selected widget shows its painted grip (`dragHandle: { grip }`)
|
|
274
|
+
* and a quiet ring; a void click clears. False when the id is unknown.
|
|
275
|
+
*/
|
|
276
|
+
focusWidget(id: string): boolean;
|
|
271
277
|
/** Every widget handle of a view (default: the active one). */
|
|
272
278
|
widgetsOf(viewId?: string): WidgetHandle[];
|
|
273
279
|
/**
|
|
@@ -504,6 +504,11 @@ export function createDashboardHandle(ctx) {
|
|
|
504
504
|
widget(id) {
|
|
505
505
|
return makeWidgetHandle(id);
|
|
506
506
|
},
|
|
507
|
+
focusWidget(id) {
|
|
508
|
+
var _a, _b;
|
|
509
|
+
const b = binders.get((_a = viewOfWidget.get(id)) !== null && _a !== void 0 ? _a : '');
|
|
510
|
+
return (_b = b === null || b === void 0 ? void 0 : b.focusWidget(id)) !== null && _b !== void 0 ? _b : false;
|
|
511
|
+
},
|
|
507
512
|
widgetsOf(viewId) {
|
|
508
513
|
var _a;
|
|
509
514
|
const v = views.find((x) => x.id === (viewId !== null && viewId !== void 0 ? viewId : ctx.active));
|
|
@@ -609,6 +609,20 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
609
609
|
* and the ROVING TABINDEX — exactly one member per board is a tab stop.
|
|
610
610
|
* Runs with the handles, so a repainted host gets it back too.
|
|
611
611
|
*/
|
|
612
|
+
/**
|
|
613
|
+
* THE SELECTED WIDGET — the one a press or keyboard focus last landed on.
|
|
614
|
+
* Stamped on its host as `axdb-selected`; that is what shows the painted
|
|
615
|
+
* grip (the DevExpress designer shows an item's bar on the selected item
|
|
616
|
+
* only). A press on a member selects it even when it starts no gesture; a
|
|
617
|
+
* void click clears it. Distinct from the roving tab stop, which must stay.
|
|
618
|
+
*/
|
|
619
|
+
let selectedId;
|
|
620
|
+
const selectWidget = (id) => {
|
|
621
|
+
if (id === selectedId)
|
|
622
|
+
return;
|
|
623
|
+
selectedId = id;
|
|
624
|
+
syncA11y();
|
|
625
|
+
};
|
|
612
626
|
const syncA11y = (only) => {
|
|
613
627
|
var _a, _b;
|
|
614
628
|
if (disposed)
|
|
@@ -616,6 +630,8 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
616
630
|
const members = [...((_a = group.members) !== null && _a !== void 0 ? _a : [])].filter((id) => !!diagram.getNode(id));
|
|
617
631
|
if (focusedId && !members.includes(focusedId))
|
|
618
632
|
focusedId = undefined;
|
|
633
|
+
if (selectedId && !members.includes(selectedId))
|
|
634
|
+
selectedId = undefined;
|
|
619
635
|
const stop = focusedId !== null && focusedId !== void 0 ? focusedId : members[0];
|
|
620
636
|
for (const id of members) {
|
|
621
637
|
if (only && !only.has(id))
|
|
@@ -634,6 +650,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
634
650
|
host.setAttribute('aria-roledescription', 'dashboard widget');
|
|
635
651
|
host.setAttribute('aria-label', bits.join(', '));
|
|
636
652
|
host.setAttribute('tabindex', id === stop ? '0' : '-1');
|
|
653
|
+
host.classList.toggle('axdb-selected', id === selectedId);
|
|
637
654
|
}
|
|
638
655
|
};
|
|
639
656
|
/**
|
|
@@ -1688,11 +1705,15 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1688
1705
|
// The board's own empty area: a void click. Nothing to drag, and the
|
|
1689
1706
|
// selection clears exactly as a click outside any board would.
|
|
1690
1707
|
(_f = (_e = diagram).clearSelection) === null || _f === void 0 ? void 0 : _f.call(_e);
|
|
1708
|
+
selectWidget(undefined);
|
|
1691
1709
|
api.render();
|
|
1692
1710
|
return;
|
|
1693
1711
|
}
|
|
1694
1712
|
const node = diagram.getNode(onGrip ? gripId : hit.node.id);
|
|
1695
|
-
if (!node
|
|
1713
|
+
if (!node)
|
|
1714
|
+
return;
|
|
1715
|
+
selectWidget(node.id); // a press selects, whether or not it starts a gesture
|
|
1716
|
+
if (((_g = node.state) === null || _g === void 0 ? void 0 : _g.locked) === true)
|
|
1696
1717
|
return; // pinned: refuse; click still focuses
|
|
1697
1718
|
if (isStatic)
|
|
1698
1719
|
return; // a static board: claimed and deadened, click still focuses
|
|
@@ -1833,8 +1854,9 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1833
1854
|
const hit = memberHostAt(e.target);
|
|
1834
1855
|
if (!hit || disposed)
|
|
1835
1856
|
return;
|
|
1836
|
-
if (focusedId !== hit.id) {
|
|
1857
|
+
if (focusedId !== hit.id || selectedId !== hit.id) {
|
|
1837
1858
|
focusedId = hit.id;
|
|
1859
|
+
selectedId = hit.id;
|
|
1838
1860
|
syncA11y();
|
|
1839
1861
|
}
|
|
1840
1862
|
};
|
|
@@ -2186,6 +2208,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2186
2208
|
if (disposed || !((_a = group.members) !== null && _a !== void 0 ? _a : new Set()).has(id) || !diagram.getNode(id))
|
|
2187
2209
|
return false;
|
|
2188
2210
|
focusedId = id;
|
|
2211
|
+
selectedId = id;
|
|
2189
2212
|
syncA11y();
|
|
2190
2213
|
(_c = (_b = hostOf(id)) === null || _b === void 0 ? void 0 : _b.focus) === null || _c === void 0 ? void 0 : _c.call(_b, { preventScroll: true });
|
|
2191
2214
|
return true;
|
|
@@ -369,11 +369,21 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
369
369
|
return '';
|
|
370
370
|
return `${Math.round((r.width / f.width) * 100)} percent wide, ${Math.round((r.height / f.height) * 100)} percent tall`;
|
|
371
371
|
};
|
|
372
|
+
/** The selected widget (see grid-binder): stamped `axdb-selected`, shows the grip. */
|
|
373
|
+
let selectedId;
|
|
374
|
+
const selectWidget = (id) => {
|
|
375
|
+
if (id === selectedId)
|
|
376
|
+
return;
|
|
377
|
+
selectedId = id;
|
|
378
|
+
syncA11y();
|
|
379
|
+
};
|
|
372
380
|
const syncA11y = () => {
|
|
373
381
|
var _a, _b, _c, _d;
|
|
374
382
|
if (disposed)
|
|
375
383
|
return;
|
|
376
384
|
const order = splitLeaves(paintedTree()).filter((id) => !!diagram.getNode(id));
|
|
385
|
+
if (selectedId && !order.includes(selectedId))
|
|
386
|
+
selectedId = undefined;
|
|
377
387
|
// No corner handles on a split board: size comes from the dividers. A host
|
|
378
388
|
// that carried the grid's handle (a board switched live) sheds it here.
|
|
379
389
|
for (const id of order)
|
|
@@ -401,6 +411,7 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
401
411
|
host.setAttribute('aria-roledescription', 'dashboard widget');
|
|
402
412
|
host.setAttribute('aria-label', bits.filter(Boolean).join(', '));
|
|
403
413
|
host.setAttribute('tabindex', id === stop ? '0' : '-1');
|
|
414
|
+
host.classList.toggle('axdb-selected', id === selectedId);
|
|
404
415
|
});
|
|
405
416
|
};
|
|
406
417
|
// -- commit -----------------------------------------------------------------
|
|
@@ -637,11 +648,15 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
637
648
|
const onGrip = !!gripId && ((_f = group.members) !== null && _f !== void 0 ? _f : new Set()).has(gripId);
|
|
638
649
|
if (!hit.node && !onGrip) {
|
|
639
650
|
(_h = (_g = diagram).clearSelection) === null || _h === void 0 ? void 0 : _h.call(_g);
|
|
651
|
+
selectWidget(undefined);
|
|
640
652
|
api.render();
|
|
641
653
|
return;
|
|
642
654
|
}
|
|
643
655
|
const node = diagram.getNode(onGrip ? gripId : hit.node.id);
|
|
644
|
-
if (!node
|
|
656
|
+
if (!node)
|
|
657
|
+
return;
|
|
658
|
+
selectWidget(node.id); // a press selects, whether or not it starts a gesture
|
|
659
|
+
if (((_j = node.state) === null || _j === void 0 ? void 0 : _j.locked) === true || isStatic)
|
|
645
660
|
return;
|
|
646
661
|
if (((_k = node.getMetadata) === null || _k === void 0 ? void 0 : _k.call(node, 'widgetMovable')) === false)
|
|
647
662
|
return;
|
|
@@ -779,8 +794,9 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
779
794
|
const hit = memberHostAt(e.target);
|
|
780
795
|
if (!hit || disposed)
|
|
781
796
|
return;
|
|
782
|
-
if (focusedId !== hit.id) {
|
|
797
|
+
if (focusedId !== hit.id || selectedId !== hit.id) {
|
|
783
798
|
focusedId = hit.id;
|
|
799
|
+
selectedId = hit.id;
|
|
784
800
|
syncA11y();
|
|
785
801
|
}
|
|
786
802
|
};
|
|
@@ -978,6 +994,7 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
978
994
|
if (!((_a = group.members) !== null && _a !== void 0 ? _a : new Set()).has(id) || !diagram.getNode(id))
|
|
979
995
|
return false;
|
|
980
996
|
focusedId = id;
|
|
997
|
+
selectedId = id;
|
|
981
998
|
syncA11y();
|
|
982
999
|
(_c = (_b = hostOf(id)) === null || _b === void 0 ? void 0 : _b.focus) === null || _c === void 0 ? void 0 : _c.call(_b, { preventScroll: true });
|
|
983
1000
|
return true;
|
|
@@ -192,21 +192,50 @@ const CSS = `
|
|
|
192
192
|
.grafloria-node-host > .axdb-grip {
|
|
193
193
|
position: absolute; z-index: 4; box-sizing: border-box; width: 24px; height: 12px;
|
|
194
194
|
border: 1px solid var(--axdb-line, #e7eaf1); border-radius: 3px; background: var(--axdb-card, #fff);
|
|
195
|
-
color: var(--axdb-muted, #5a6478); cursor: grab;
|
|
195
|
+
color: var(--axdb-muted, #5a6478); cursor: grab;
|
|
196
|
+
/* Shown on the SELECTED widget only (the DevExpress designer shows an item's
|
|
197
|
+
bar on the selected item): a press or keyboard focus selects, a void
|
|
198
|
+
click clears. Hidden, it takes no pointer either. */
|
|
199
|
+
opacity: 0; pointer-events: none; transition: opacity .12s ease;
|
|
196
200
|
}
|
|
201
|
+
.grafloria-node-host.axdb-selected > .axdb-grip, .grafloria-node-host:focus-within > .axdb-grip { opacity: 1; pointer-events: auto; }
|
|
197
202
|
.grafloria-node-host > .axdb-grip::before {
|
|
198
203
|
content: ''; position: absolute; left: 5px; top: 2px; width: 12px; height: 6px;
|
|
199
204
|
background: radial-gradient(circle, currentColor 1px, transparent 1.4px) 0 0 / 4px 3px;
|
|
200
205
|
}
|
|
201
|
-
.grafloria-node-host
|
|
202
|
-
|
|
206
|
+
.grafloria-node-host > .axdb-grip:hover { border-color: #3b52d9; color: #3b52d9; }
|
|
207
|
+
/* The selected card says so, quietly. */
|
|
208
|
+
.grafloria-node-host.axdb-selected > .axdb-widget { box-shadow: 0 0 0 1.5px rgba(59, 82, 217, .55), 0 1px 2px rgba(16, 24, 40, .05), 0 1px 3px rgba(16, 24, 40, .05); }
|
|
209
|
+
/* INSIDE: centred on the header's text line and flush with the card padding,
|
|
210
|
+
per size tier (padding 13/15, then 8/14, 4/12, 2/12). */
|
|
211
|
+
.grafloria-node-host > .axdb-grip--inside { top: 14px; }
|
|
212
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--left { left: 15px; }
|
|
213
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--right { right: 15px; }
|
|
214
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--center { top: 3px; }
|
|
215
|
+
@container axdb-tile (max-height: 90px) {
|
|
216
|
+
.grafloria-node-host > .axdb-grip--inside { top: 9px; }
|
|
217
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--left { left: 14px; }
|
|
218
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--right { right: 14px; }
|
|
219
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--center { top: 2px; }
|
|
220
|
+
}
|
|
221
|
+
@container axdb-tile (max-height: 46px) {
|
|
222
|
+
.grafloria-node-host > .axdb-grip--inside { top: 5px; }
|
|
223
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--left { left: 12px; }
|
|
224
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--right { right: 12px; }
|
|
225
|
+
.grafloria-node-host > .axdb-grip--inside.axdb-grip--center { top: 1px; }
|
|
226
|
+
}
|
|
227
|
+
@container axdb-tile (max-height: 26px) {
|
|
228
|
+
.grafloria-node-host > .axdb-grip--inside { top: 2px; }
|
|
229
|
+
}
|
|
230
|
+
/* OUTSIDE: a tab on the card's top edge, its corners in line with the card's. */
|
|
203
231
|
.grafloria-node-host > .axdb-grip--outside { top: -11px; height: 11px; border-bottom-left-radius: 0; border-bottom-right-radius: 0; border-bottom: 0; box-shadow: 0 -1px 2px rgba(16, 24, 40, .08); }
|
|
204
|
-
.grafloria-node-host > .axdb-grip--left { left:
|
|
205
|
-
.grafloria-node-host > .axdb-grip--right { right:
|
|
232
|
+
.grafloria-node-host > .axdb-grip--outside.axdb-grip--left { left: 10px; }
|
|
233
|
+
.grafloria-node-host > .axdb-grip--outside.axdb-grip--right { right: 10px; }
|
|
206
234
|
.grafloria-node-host > .axdb-grip--center { left: 50%; transform: translateX(-50%); }
|
|
207
|
-
|
|
208
|
-
.grafloria-node-host.axdb-gp-inside.axdb-gp-
|
|
209
|
-
.grafloria-node-host.axdb-gp-inside.axdb-gp-
|
|
235
|
+
/* The header makes room for an inside grip on its side; a centred one sits above it. */
|
|
236
|
+
.grafloria-node-host.axdb-gp-inside.axdb-gp-left .axdb-widget > .axdb-widget-h { padding-left: 32px; }
|
|
237
|
+
.grafloria-node-host.axdb-gp-inside.axdb-gp-right .axdb-widget > .axdb-widget-h { padding-right: 32px; }
|
|
238
|
+
.grafloria-node-host.axdb-gp-inside.axdb-gp-center .axdb-widget > .axdb-widget-h { padding-top: 12px; }
|
|
210
239
|
.axdb-widget-b { flex: 1; min-height: 0; position: relative; }
|
|
211
240
|
.axdb-widget-b > svg { display: block; width: 100%; height: 100%; }
|
|
212
241
|
.axdb-widget-b.axdb-scroll { overflow: auto; }
|