@colixsystems/widget-sdk 0.196.0 → 0.197.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/README.md +5 -1
- package/dist/host.d.ts +15 -3
- package/dist/navigation.cjs +58 -25
- package/dist/navigation.js +58 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,7 +77,11 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
77
77
|
|
|
78
78
|
## Status
|
|
79
79
|
|
|
80
|
-
`v0.
|
|
80
|
+
`v0.197.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
|
|
81
|
+
|
|
82
|
+
### What's new in 0.197.0 (contract 1.157.0)
|
|
83
|
+
|
|
84
|
+
**Host navigation: a page's sidebar menu can be opened from any page.** `resolveSidebarUnfold({ entries, active, sections })` used to answer only the section being viewed, so a host could draw a section's menu only while the visitor was inside it. The result now also carries `trees`: one `{ under, items, standalone, inside }` for every sidebar entry that carries a local menu, in menu order. `inside` is true for the section being viewed, which a host draws open; the others it draws folded behind the entry's arrow. `under`, `items` and `standalone` still describe the viewed section, so existing callers keep working. Widgets are unaffected: this is the host surface (`@colixsystems/widget-sdk/host`), and the widget contract version does not change.
|
|
81
85
|
|
|
82
86
|
### What's new in 0.196.0 (contract 1.157.0)
|
|
83
87
|
|
package/dist/host.d.ts
CHANGED
|
@@ -254,14 +254,26 @@ export interface SidebarUnfoldItem {
|
|
|
254
254
|
[field: string]: unknown;
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
/** One section's local menu and the sidebar entry it hangs beneath. `inside`
|
|
258
|
+
* marks the section the visitor is in — the one that starts unfolded. */
|
|
259
|
+
export interface SidebarUnfoldTree {
|
|
260
|
+
under: string;
|
|
261
|
+
items: Array<SidebarUnfoldItem & { current: boolean }>;
|
|
262
|
+
standalone: boolean;
|
|
263
|
+
inside: boolean;
|
|
264
|
+
}
|
|
265
|
+
|
|
257
266
|
/** Where a page's `SIDEBAR` local menu unfolds (REQ-NAV-LOCAL, sc-7696).
|
|
258
|
-
* `under` is the global menu entry the
|
|
259
|
-
*
|
|
260
|
-
* list the page, so the page itself is the entry.
|
|
267
|
+
* `under` is the global menu entry the visitor's own section hangs beneath,
|
|
268
|
+
* or null when they are in none. `standalone` marks the case where the global
|
|
269
|
+
* menu does not list the page, so the page itself is the entry. `trees` is
|
|
270
|
+
* every section an entry carries, in menu order, so an entry can offer its
|
|
271
|
+
* menu from any page; a `standalone` tree comes last. */
|
|
261
272
|
export interface SidebarUnfold {
|
|
262
273
|
under: string | null;
|
|
263
274
|
items: Array<SidebarUnfoldItem & { current: boolean }>;
|
|
264
275
|
standalone: boolean;
|
|
276
|
+
trees: SidebarUnfoldTree[];
|
|
265
277
|
}
|
|
266
278
|
|
|
267
279
|
/** Resolve where the viewed page's local menu unfolds in the sidebar and the
|
package/dist/navigation.cjs
CHANGED
|
@@ -636,21 +636,25 @@ function resolveTopBarTokens(theme) {
|
|
|
636
636
|
* inside it, so the menu is never lost — a section off the menu is exactly
|
|
637
637
|
* the case that would otherwise render blank.
|
|
638
638
|
*
|
|
639
|
+
* sc-10693: `trees` answers EVERY section, not only the visitor's own, so a
|
|
640
|
+
* section's entry can offer its menu from any page. `under` / `items` /
|
|
641
|
+
* `standalone` still name the one the visitor is inside.
|
|
642
|
+
*
|
|
639
643
|
* @param {{ entries?: unknown, active?: unknown, sections?: unknown }} input
|
|
640
644
|
* `entries` — the global menu's keys, in menu order.
|
|
641
645
|
* `active` — the key of the page being viewed.
|
|
642
646
|
* `sections` — `{ [key]: { menu, items } }` for pages whose local nav is
|
|
643
647
|
* `SIDEBAR`; `menu` identifies the saved menu, `items` carry their own key.
|
|
644
|
-
* @returns {{ under: string|null, items: Array<object>, standalone: boolean }}
|
|
645
|
-
* `under` is null when
|
|
646
|
-
* section's own page, which the host draws as the entry. Each
|
|
647
|
-
* returned with a `current` flag rather than leaving each host to
|
|
648
|
-
* recompute it.
|
|
648
|
+
* @returns {{ under: string|null, items: Array<object>, standalone: boolean, trees: Array<object> }}
|
|
649
|
+
* `under` is null when the visitor is in no section; when `standalone` it
|
|
650
|
+
* names the section's own page, which the host draws as the entry. Each
|
|
651
|
+
* item is returned with a `current` flag rather than leaving each host to
|
|
652
|
+
* recompute it. `trees` lists `{ under, items, standalone, inside }` in menu
|
|
653
|
+
* order, a `standalone` one last; `inside` marks the visitor's own.
|
|
649
654
|
*/
|
|
650
655
|
function resolveSidebarUnfold(input) {
|
|
651
656
|
const { entries, active, sections } = isPlainObject(input) ? input : {};
|
|
652
|
-
const
|
|
653
|
-
if (typeof active !== "string" || !active) return nothing;
|
|
657
|
+
const viewed = typeof active === "string" && active ? active : null;
|
|
654
658
|
const bank = isPlainObject(sections) ? sections : {};
|
|
655
659
|
const order = Array.isArray(entries) ? entries : [];
|
|
656
660
|
const sectionAt = (key) => {
|
|
@@ -663,31 +667,60 @@ function resolveSidebarUnfold(input) {
|
|
|
663
667
|
return (
|
|
664
668
|
Boolean(candidate) &&
|
|
665
669
|
candidate.items.some(
|
|
666
|
-
(item) => isPlainObject(item) && item.key ===
|
|
670
|
+
(item) => isPlainObject(item) && item.key === viewed,
|
|
667
671
|
)
|
|
668
672
|
);
|
|
669
673
|
};
|
|
670
674
|
// The page's own section wins; otherwise the section whose menu lists it,
|
|
671
675
|
// preferring one a global entry carries so the tree hangs where it always
|
|
672
676
|
// does. Both are the same section from the visitor's side.
|
|
673
|
-
const section =
|
|
674
|
-
sectionAt(
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
677
|
+
const section = viewed
|
|
678
|
+
? sectionAt(viewed) ||
|
|
679
|
+
sectionAt(order.find(lists)) ||
|
|
680
|
+
sectionAt(Object.keys(bank).find(lists))
|
|
681
|
+
: null;
|
|
682
|
+
const mark = (items) =>
|
|
683
|
+
items.map((item) => ({
|
|
684
|
+
...(isPlainObject(item) ? item : {}),
|
|
685
|
+
current:
|
|
686
|
+
viewed !== null &&
|
|
687
|
+
isPlainObject(item) &&
|
|
688
|
+
typeof item.key === "string" &&
|
|
689
|
+
item.key === viewed,
|
|
690
|
+
}));
|
|
691
|
+
// A saved menu hangs under the FIRST global entry carrying it, so two
|
|
692
|
+
// entries sharing one menu never draw it twice.
|
|
693
|
+
const claimed = [];
|
|
694
|
+
const trees = [];
|
|
695
|
+
for (const key of order) {
|
|
696
|
+
if (!isPlainObject(bank[key])) continue;
|
|
697
|
+
const { menu } = bank[key];
|
|
698
|
+
if (claimed.includes(menu)) continue;
|
|
699
|
+
claimed.push(menu);
|
|
700
|
+
// An unusable key still owns its menu: nothing may hang it elsewhere.
|
|
701
|
+
if (typeof key !== "string" || !key) continue;
|
|
702
|
+
const inside = Boolean(section) && menu === section.menu;
|
|
703
|
+
const own = inside ? section : sectionAt(key);
|
|
704
|
+
if (!own) continue;
|
|
705
|
+
trees.push({ under: key, items: mark(own.items), standalone: false, inside });
|
|
706
|
+
}
|
|
707
|
+
if (!section) return { under: null, items: [], standalone: false, trees };
|
|
708
|
+
const owned = trees.find((tree) => tree.inside);
|
|
709
|
+
if (owned) {
|
|
710
|
+
return { under: owned.under, items: owned.items, standalone: false, trees };
|
|
689
711
|
}
|
|
690
|
-
|
|
712
|
+
const alone = {
|
|
713
|
+
under: section.key,
|
|
714
|
+
items: mark(section.items),
|
|
715
|
+
standalone: true,
|
|
716
|
+
inside: true,
|
|
717
|
+
};
|
|
718
|
+
return {
|
|
719
|
+
under: alone.under,
|
|
720
|
+
items: alone.items,
|
|
721
|
+
standalone: true,
|
|
722
|
+
trees: [...trees, alone],
|
|
723
|
+
};
|
|
691
724
|
}
|
|
692
725
|
|
|
693
726
|
/**
|
package/dist/navigation.js
CHANGED
|
@@ -627,21 +627,25 @@ export function resolveTopBarTokens(theme) {
|
|
|
627
627
|
* inside it, so the menu is never lost — a section off the menu is exactly
|
|
628
628
|
* the case that would otherwise render blank.
|
|
629
629
|
*
|
|
630
|
+
* sc-10693: `trees` answers EVERY section, not only the visitor's own, so a
|
|
631
|
+
* section's entry can offer its menu from any page. `under` / `items` /
|
|
632
|
+
* `standalone` still name the one the visitor is inside.
|
|
633
|
+
*
|
|
630
634
|
* @param {{ entries?: unknown, active?: unknown, sections?: unknown }} input
|
|
631
635
|
* `entries` — the global menu's keys, in menu order.
|
|
632
636
|
* `active` — the key of the page being viewed.
|
|
633
637
|
* `sections` — `{ [key]: { menu, items } }` for pages whose local nav is
|
|
634
638
|
* `SIDEBAR`; `menu` identifies the saved menu, `items` carry their own key.
|
|
635
|
-
* @returns {{ under: string|null, items: Array<object>, standalone: boolean }}
|
|
636
|
-
* `under` is null when
|
|
637
|
-
* section's own page, which the host draws as the entry. Each
|
|
638
|
-
* returned with a `current` flag rather than leaving each host to
|
|
639
|
-
* recompute it.
|
|
639
|
+
* @returns {{ under: string|null, items: Array<object>, standalone: boolean, trees: Array<object> }}
|
|
640
|
+
* `under` is null when the visitor is in no section; when `standalone` it
|
|
641
|
+
* names the section's own page, which the host draws as the entry. Each
|
|
642
|
+
* item is returned with a `current` flag rather than leaving each host to
|
|
643
|
+
* recompute it. `trees` lists `{ under, items, standalone, inside }` in menu
|
|
644
|
+
* order, a `standalone` one last; `inside` marks the visitor's own.
|
|
640
645
|
*/
|
|
641
646
|
export function resolveSidebarUnfold(input) {
|
|
642
647
|
const { entries, active, sections } = isPlainObject(input) ? input : {};
|
|
643
|
-
const
|
|
644
|
-
if (typeof active !== "string" || !active) return nothing;
|
|
648
|
+
const viewed = typeof active === "string" && active ? active : null;
|
|
645
649
|
const bank = isPlainObject(sections) ? sections : {};
|
|
646
650
|
const order = Array.isArray(entries) ? entries : [];
|
|
647
651
|
const sectionAt = (key) => {
|
|
@@ -654,31 +658,60 @@ export function resolveSidebarUnfold(input) {
|
|
|
654
658
|
return (
|
|
655
659
|
Boolean(candidate) &&
|
|
656
660
|
candidate.items.some(
|
|
657
|
-
(item) => isPlainObject(item) && item.key ===
|
|
661
|
+
(item) => isPlainObject(item) && item.key === viewed,
|
|
658
662
|
)
|
|
659
663
|
);
|
|
660
664
|
};
|
|
661
665
|
// The page's own section wins; otherwise the section whose menu lists it,
|
|
662
666
|
// preferring one a global entry carries so the tree hangs where it always
|
|
663
667
|
// does. Both are the same section from the visitor's side.
|
|
664
|
-
const section =
|
|
665
|
-
sectionAt(
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
668
|
+
const section = viewed
|
|
669
|
+
? sectionAt(viewed) ||
|
|
670
|
+
sectionAt(order.find(lists)) ||
|
|
671
|
+
sectionAt(Object.keys(bank).find(lists))
|
|
672
|
+
: null;
|
|
673
|
+
const mark = (items) =>
|
|
674
|
+
items.map((item) => ({
|
|
675
|
+
...(isPlainObject(item) ? item : {}),
|
|
676
|
+
current:
|
|
677
|
+
viewed !== null &&
|
|
678
|
+
isPlainObject(item) &&
|
|
679
|
+
typeof item.key === "string" &&
|
|
680
|
+
item.key === viewed,
|
|
681
|
+
}));
|
|
682
|
+
// A saved menu hangs under the FIRST global entry carrying it, so two
|
|
683
|
+
// entries sharing one menu never draw it twice.
|
|
684
|
+
const claimed = [];
|
|
685
|
+
const trees = [];
|
|
686
|
+
for (const key of order) {
|
|
687
|
+
if (!isPlainObject(bank[key])) continue;
|
|
688
|
+
const { menu } = bank[key];
|
|
689
|
+
if (claimed.includes(menu)) continue;
|
|
690
|
+
claimed.push(menu);
|
|
691
|
+
// An unusable key still owns its menu: nothing may hang it elsewhere.
|
|
692
|
+
if (typeof key !== "string" || !key) continue;
|
|
693
|
+
const inside = Boolean(section) && menu === section.menu;
|
|
694
|
+
const own = inside ? section : sectionAt(key);
|
|
695
|
+
if (!own) continue;
|
|
696
|
+
trees.push({ under: key, items: mark(own.items), standalone: false, inside });
|
|
697
|
+
}
|
|
698
|
+
if (!section) return { under: null, items: [], standalone: false, trees };
|
|
699
|
+
const owned = trees.find((tree) => tree.inside);
|
|
700
|
+
if (owned) {
|
|
701
|
+
return { under: owned.under, items: owned.items, standalone: false, trees };
|
|
680
702
|
}
|
|
681
|
-
|
|
703
|
+
const alone = {
|
|
704
|
+
under: section.key,
|
|
705
|
+
items: mark(section.items),
|
|
706
|
+
standalone: true,
|
|
707
|
+
inside: true,
|
|
708
|
+
};
|
|
709
|
+
return {
|
|
710
|
+
under: alone.under,
|
|
711
|
+
items: alone.items,
|
|
712
|
+
standalone: true,
|
|
713
|
+
trees: [...trees, alone],
|
|
714
|
+
};
|
|
682
715
|
}
|
|
683
716
|
|
|
684
717
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.197.0",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"homepage": "https://github.com/Colix-AB/AppStudio",
|
|
6
6
|
"type": "module",
|