@k2b/ui 0.38.1 → 0.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/dist/browser/actions/Dropdown.js +42 -6
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/SelectionToolbar.js +11 -6
- package/dist/browser/actions/SelectionToolbar.js.map +1 -1
- package/dist/browser/actions/Toolbar.js +5 -1
- package/dist/browser/actions/Toolbar.js.map +1 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +11 -2
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +31 -17
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +49 -5
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/text-editor/TextEditor.js +331 -214
- package/dist/browser/text-editor/TextEditor.js.map +1 -1
- package/dist/browser/text-editor/table.js +43 -6
- package/dist/browser/text-editor/table.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +38 -6
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/SelectionToolbar.js +11 -6
- package/dist/ssr/actions/SelectionToolbar.js.map +1 -1
- package/dist/ssr/actions/Toolbar.js +5 -1
- package/dist/ssr/actions/Toolbar.js.map +1 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +10 -2
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +31 -17
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +49 -5
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/text-editor/TextEditor.js +225 -96
- package/dist/ssr/text-editor/TextEditor.js.map +1 -1
- package/dist/ssr/text-editor/table.js +43 -6
- package/dist/ssr/text-editor/table.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/Dropdown.d.ts +15 -1
- package/dist/types/actions/Toolbar.d.ts +6 -1
- package/dist/types/actions/index.d.ts +1 -1
- package/dist/types/layout/AppWorkspace.d.ts +14 -0
- package/dist/types/layout/app-workspace-controller.d.ts +2 -0
- package/package.json +1 -1
|
@@ -66,6 +66,8 @@ const sidebarHideable = root => sidebarElement(root)?.dataset.workspaceHideable
|
|
|
66
66
|
* stays application state, so the controller only requests the change.
|
|
67
67
|
*/
|
|
68
68
|
export const APP_WORKSPACE_SIDEBAR_HIDE_EVENT = "k2b-app-workspace-sidebar-hide";
|
|
69
|
+
/** Asks the owning `AppWorkspace.Sidebar` to show again; its `onHiddenChange` decides. */
|
|
70
|
+
export const APP_WORKSPACE_SIDEBAR_SHOW_EVENT = "k2b-app-workspace-sidebar-show";
|
|
69
71
|
/** Asks the owning Detail to reopen its current available object. */
|
|
70
72
|
export const APP_WORKSPACE_DETAIL_OPEN_EVENT = "k2b-app-workspace-detail-open";
|
|
71
73
|
/** Asks the owning `AppWorkspace.Detail` to close; its `onClose` decides. */
|
|
@@ -303,6 +305,12 @@ const overlayTarget = toggle => {
|
|
|
303
305
|
};
|
|
304
306
|
};
|
|
305
307
|
const overlayRegions = (root, sidebar) => Array.from(root.children).flatMap(child => child instanceof HTMLElement && (child.localName === "solid-island" || child.localName === "solid-client") ? Array.from(child.children) : [child]).filter(child => child instanceof HTMLElement && child !== sidebar && !child.contains(sidebar));
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* A sidebar button tells whether its sidebar shows: as an open overlay where the sidebar is one, otherwise as a
|
|
311
|
+
* column that is not hidden.
|
|
312
|
+
*/
|
|
313
|
+
const sidebarShown = (root, sidebar) => sidebarForm(root) === "overlay" ? root.dataset.sidebarOverlay === "open" : !sidebar.hidden;
|
|
306
314
|
export const installAppWorkspaceController = (options = {}) => {
|
|
307
315
|
const eventRoot = options.root ?? document;
|
|
308
316
|
// A document has no owner document; an element root listens on its own.
|
|
@@ -311,6 +319,17 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
311
319
|
let overlay = null;
|
|
312
320
|
// A server-rendered head names the sidebar before the sidebar renders; the button learns its real id now.
|
|
313
321
|
for (const toggle of eventRoot.querySelectorAll(TOGGLE_SELECTOR)) overlayTarget(toggle);
|
|
322
|
+
/** Every sidebar button, the workspace head's and an application's own, states whether its sidebar shows. */
|
|
323
|
+
const syncSidebarToggles = () => {
|
|
324
|
+
for (const toggle of eventRoot.querySelectorAll(TOGGLE_SELECTOR)) {
|
|
325
|
+
const root = workspaceRoot(toggle);
|
|
326
|
+
const sidebar = root ? sidebarElement(root) : null;
|
|
327
|
+
if (!root || !sidebar) continue;
|
|
328
|
+
// The head's button only opens the overlay; an application's button also shows and hides the column.
|
|
329
|
+
const expanded = String(toggle.closest(".k2b-app-workspace__head") ? root.dataset.sidebarOverlay === "open" : sidebarShown(root, sidebar));
|
|
330
|
+
if (toggle.getAttribute("aria-expanded") !== expanded) toggle.setAttribute("aria-expanded", expanded);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
314
333
|
const openOverlay = target => {
|
|
315
334
|
if (overlay) closeOverlay("none");
|
|
316
335
|
const inerted = overlayRegions(target.root, target.sidebar).filter(region => !region.hasAttribute("inert"));
|
|
@@ -320,6 +339,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
320
339
|
};
|
|
321
340
|
target.root.dataset.sidebarOverlay = "open";
|
|
322
341
|
target.toggle.setAttribute("aria-expanded", "true");
|
|
342
|
+
syncSidebarToggles();
|
|
323
343
|
inerted.forEach(region => region.setAttribute("inert", ""));
|
|
324
344
|
// Focus starts on the current destination, so the reader knows where they
|
|
325
345
|
// are: on its own tab stop, or on the tree item around it.
|
|
@@ -342,6 +362,8 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
342
362
|
overlay = null;
|
|
343
363
|
delete closing.root.dataset.sidebarOverlay;
|
|
344
364
|
closing.toggle.setAttribute("aria-expanded", "false");
|
|
365
|
+
// Escape, the scrim or a chosen destination also close it: every sidebar button of the workspace says so.
|
|
366
|
+
syncSidebarToggles();
|
|
345
367
|
closing.inerted.forEach(region => region.removeAttribute("inert"));
|
|
346
368
|
if (focus === "none") return;
|
|
347
369
|
const active = document.activeElement;
|
|
@@ -377,10 +399,27 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
377
399
|
}
|
|
378
400
|
const toggle = target?.closest(TOGGLE_SELECTOR);
|
|
379
401
|
if (toggle) {
|
|
402
|
+
if (claimedToggleClicks.has(event)) return;
|
|
403
|
+
const root = workspaceRoot(toggle);
|
|
404
|
+
const sidebar = root ? sidebarElement(root) : null;
|
|
405
|
+
// A sidebar the person hid comes back first; where it is an overlay, it then opens.
|
|
406
|
+
if (root && sidebar?.hidden && sidebarHideable(root)) {
|
|
407
|
+
claimedToggleClicks.add(event);
|
|
408
|
+
sidebar.dispatchEvent(new CustomEvent(APP_WORKSPACE_SIDEBAR_SHOW_EVENT));
|
|
409
|
+
ownerWindow.requestAnimationFrame(() => {
|
|
410
|
+
const next = !sidebar.hidden && sidebarForm(root) === "overlay" ? overlayTarget(toggle) : null;
|
|
411
|
+
if (next) openOverlay(next);
|
|
412
|
+
syncSidebarToggles();
|
|
413
|
+
});
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
380
416
|
const next = overlayTarget(toggle);
|
|
381
|
-
if (!next
|
|
417
|
+
if (!next) return;
|
|
382
418
|
claimedToggleClicks.add(event);
|
|
383
419
|
if (overlay?.sidebar === next.sidebar) closeOverlay("button");else if (sidebarForm(next.root) === "overlay") openOverlay(next);
|
|
420
|
+
// A column: an application's own button hides a sidebar it lets people hide.
|
|
421
|
+
else if (sidebarHideable(next.root)) next.sidebar.dispatchEvent(new CustomEvent(APP_WORKSPACE_SIDEBAR_HIDE_EVENT));
|
|
422
|
+
syncSidebarToggles();
|
|
384
423
|
return;
|
|
385
424
|
}
|
|
386
425
|
if (!overlay || !target) return;
|
|
@@ -466,7 +505,8 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
466
505
|
for (const root of allRoots()) {
|
|
467
506
|
for (const aside of rootElements(root, detailSelector)) {
|
|
468
507
|
const toggle = detailToggle(aside);
|
|
469
|
-
|
|
508
|
+
// The panel decides whether it reopens; its button may be the workspace's own or an application's.
|
|
509
|
+
if (!toggle || aside.dataset.workspaceDetailReopen !== "true") continue;
|
|
470
510
|
const expanded = !aside.hidden && (!wide?.matches || !detailWaiting(aside) || detailDrawer(aside));
|
|
471
511
|
const value = String(expanded);
|
|
472
512
|
if (toggle.getAttribute("aria-expanded") !== value) toggle.setAttribute("aria-expanded", value);
|
|
@@ -581,7 +621,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
581
621
|
return;
|
|
582
622
|
}
|
|
583
623
|
const shared = detailToggle(aside);
|
|
584
|
-
if (shared
|
|
624
|
+
if (shared && aside.dataset.workspaceDetailReopen === "true" && phone?.matches && phonePage(aside) && !aside.hidden && !aside.contains(control)) {
|
|
585
625
|
// WebKit can update matchMedia after resize has already focused the now
|
|
586
626
|
// visible application control. Move into the page before Main becomes inert.
|
|
587
627
|
detailControlFocus = null;
|
|
@@ -590,7 +630,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
590
630
|
}
|
|
591
631
|
if (detailControlVisible(control)) return;
|
|
592
632
|
detailControlFocus = null;
|
|
593
|
-
if (shared
|
|
633
|
+
if (!shared || aside.dataset.workspaceDetailReopen !== "true") {
|
|
594
634
|
// Selection-only details keep their existing returning-column title target.
|
|
595
635
|
if (control === shared && !aside.hidden && !detailWaiting(aside)) requestTitle(aside);
|
|
596
636
|
return;
|
|
@@ -602,6 +642,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
602
642
|
});
|
|
603
643
|
};
|
|
604
644
|
const syncHostState = () => {
|
|
645
|
+
syncSidebarToggles();
|
|
605
646
|
rescueDetailControlFocus();
|
|
606
647
|
if (pendingDetail && !canOpenPendingDetail(pendingDetail.aside)) cancelPendingDetail();
|
|
607
648
|
if (overlay && sidebarForm(overlay.root) !== "overlay") closeOverlay("none");
|
|
@@ -1055,7 +1096,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1055
1096
|
const focused = ownerDocument.activeElement;
|
|
1056
1097
|
const toggle = detailToggle(aside);
|
|
1057
1098
|
const returnControl = detailReturnControl(aside);
|
|
1058
|
-
if (toggle
|
|
1099
|
+
if (toggle && aside.dataset.workspaceDetailReopen === "true" && returnControl && (aside.contains(focused) || focused === ownerDocument.body && aside.contains(lastFocus.get(root) ?? null))) {
|
|
1059
1100
|
returnControl.focus({
|
|
1060
1101
|
preventScroll: true
|
|
1061
1102
|
});
|
|
@@ -1795,6 +1836,8 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1795
1836
|
const layoutNode = node => node instanceof Element && (node.matches(LAYOUT_REGION_SELECTOR) || Boolean(node.querySelector(LAYOUT_REGION_SELECTOR)));
|
|
1796
1837
|
const mutationObserver = typeof MutationObserver === "undefined" ? null : new MutationObserver(records => {
|
|
1797
1838
|
if (records.some(record => record.type === "childList" || ["hidden", "aria-controls", "aria-expanded", "data-workspace-detail-drawer"].includes(record.attributeName ?? ""))) syncDetailRequestControls();
|
|
1839
|
+
// A sidebar shown or hidden, or a sidebar button added: the buttons state it.
|
|
1840
|
+
if (records.some(record => record.type === "attributes" && record.attributeName === "hidden" && record.target instanceof Element && record.target.matches(".k2b-app-workspace__sidebar") || [...record.addedNodes].some(node => node instanceof Element && (node.matches(TOGGLE_SELECTOR) || node.querySelector(TOGGLE_SELECTOR))))) syncSidebarToggles();
|
|
1798
1841
|
syncPhonePages();
|
|
1799
1842
|
if (pendingTitle && (pendingTitle.aside.hidden || !pendingTitle.aside.isConnected)) cancelTitle();
|
|
1800
1843
|
if (pendingDetail && (!canOpenPendingDetail(pendingDetail.aside) || !pendingDetail.snapshot.chosen || !pendingDetail.snapshot.item.isConnected)) cancelPendingDetail();
|
|
@@ -1850,6 +1893,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1850
1893
|
syncPhonePages();
|
|
1851
1894
|
syncObservedRoots();
|
|
1852
1895
|
syncDetailRequestControls();
|
|
1896
|
+
syncSidebarToggles();
|
|
1853
1897
|
mutationObserver?.observe(eventRoot, {
|
|
1854
1898
|
attributes: true,
|
|
1855
1899
|
attributeOldValue: true,
|