@artstorefronts/arthelper-nav 0.1.0-alpha.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 +266 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +134 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +21 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +12 -0
- package/dist/context.js.map +1 -0
- package/dist/cookie.d.ts +13 -0
- package/dist/cookie.d.ts.map +1 -0
- package/dist/cookie.js +28 -0
- package/dist/cookie.js.map +1 -0
- package/dist/fallback.d.ts +13 -0
- package/dist/fallback.d.ts.map +1 -0
- package/dist/fallback.js +17 -0
- package/dist/fallback.js.map +1 -0
- package/dist/icons.d.ts +14 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +29 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.css +509 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/nav-bar.d.ts +13 -0
- package/dist/nav-bar.d.ts.map +1 -0
- package/dist/nav-bar.js +91 -0
- package/dist/nav-bar.js.map +1 -0
- package/dist/nav-trigger.d.ts +16 -0
- package/dist/nav-trigger.d.ts.map +1 -0
- package/dist/nav-trigger.js +21 -0
- package/dist/nav-trigger.js.map +1 -0
- package/dist/provider.d.ts +19 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +46 -0
- package/dist/provider.js.map +1 -0
- package/dist/resolve.d.ts +32 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +51 -0
- package/dist/resolve.js.map +1 -0
- package/dist/theme.d.ts +13 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +21 -0
- package/dist/theme.js.map +1 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useNav } from './context.js';
|
|
4
|
+
import { NavIcon, WaffleIcon } from './icons.js';
|
|
5
|
+
import { themeVars } from './theme.js';
|
|
6
|
+
/**
|
|
7
|
+
* The waffle plus active-app chip a host places by hand in its own header, beside
|
|
8
|
+
* its logo. This is the RESTORE control: while the bar is collapsed it is the only
|
|
9
|
+
* way back, so it is visibly interactive and always carries the restore label.
|
|
10
|
+
*
|
|
11
|
+
* It is display:none while the bar is expanded (and therefore out of the
|
|
12
|
+
* accessibility tree), which is why the label and aria-expanded are fixed rather
|
|
13
|
+
* than swapped — the bar's own waffle is the hide control.
|
|
14
|
+
*/
|
|
15
|
+
function NavTrigger({ className }) {
|
|
16
|
+
const { config, activeApp, collapsed, toggle } = useNav();
|
|
17
|
+
const classes = ['ahsuite-docked', className ?? ''].filter(Boolean).join(' ');
|
|
18
|
+
return (_jsxs("button", { "aria-expanded": false, "aria-label": "Show the suite bar", className: classes, "data-collapsed": collapsed ? 'true' : 'false', "data-theme": config.theme.mode, onClick: toggle, style: themeVars(config.theme), title: "Show the suite bar", type: "button", children: [_jsx("span", { className: "ahsuite-chip ahsuite-chip--active", children: _jsx(NavIcon, { name: activeApp?.app.icon ?? '' }) }), _jsx(WaffleIcon, { className: "ahsuite-waffle-mini" })] }));
|
|
19
|
+
}
|
|
20
|
+
export { NavTrigger };
|
|
21
|
+
//# sourceMappingURL=nav-trigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav-trigger.js","sourceRoot":"","sources":["../src/nav-trigger.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAMvC;;;;;;;;GAQG;AACH,SAAS,UAAU,CAAC,EAAE,SAAS,EAAmB;IAChD,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IAE1D,MAAM,OAAO,GAAG,CAAC,gBAAgB,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE9E,OAAO,CACL,mCACiB,KAAK,gBACT,oBAAoB,EAC/B,SAAS,EAAE,OAAO,oBACF,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,gBAChC,MAAM,CAAC,KAAK,CAAC,IAAI,EAC7B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAC9B,KAAK,EAAC,oBAAoB,EAC1B,IAAI,EAAC,QAAQ,aAEb,eAAM,SAAS,EAAC,mCAAmC,YACjD,KAAC,OAAO,IAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,GAAI,GACvC,EACP,KAAC,UAAU,IAAC,SAAS,EAAC,qBAAqB,GAAG,IACvC,CACV,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { NavAppClickArgs, NavConfigPayload } from './types.js';
|
|
3
|
+
interface NavProviderProps {
|
|
4
|
+
/** Full URL of the public nav-config endpoint. Derived by the host; no new env var. */
|
|
5
|
+
configUrl: string;
|
|
6
|
+
/** The catalog id of the app the host itself is — never inferred from the URL or the payload. */
|
|
7
|
+
activeAppId: string;
|
|
8
|
+
/** Called immediately before navigation. The only analytics seam; the package imports none. */
|
|
9
|
+
onAppClick?: (args: NavAppClickArgs) => void;
|
|
10
|
+
/** Overrides the compiled-in fallback, e.g. for a satellite with a different first-party set. */
|
|
11
|
+
fallbackConfig?: NavConfigPayload;
|
|
12
|
+
/** A server-rendered host passes the collapsed cookie it already read, so the first byte is correct. */
|
|
13
|
+
initialCollapsed?: boolean;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
declare function NavProvider({ configUrl, activeAppId, onAppClick, fallbackConfig, initialCollapsed, children, }: NavProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export { NavProvider };
|
|
18
|
+
export type { NavProviderProps };
|
|
19
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMlF,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC;AAEpF,UAAU,gBAAgB;IACxB,uFAAuF;IACvF,SAAS,EAAE,MAAM,CAAC;IAClB,iGAAiG;IACjG,WAAW,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7C,iGAAiG;IACjG,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,wGAAwG;IACxG,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,WAAW,EACX,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,EAAE,gBAAgB,2CAiDlB;AAED,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { cached, fetchConfig } from './config.js';
|
|
5
|
+
import { NavContext } from './context.js';
|
|
6
|
+
import { readCollapsed, writeCollapsed } from './cookie.js';
|
|
7
|
+
import { FALLBACK_CONFIG } from './fallback.js';
|
|
8
|
+
import { resolveApps } from './resolve.js';
|
|
9
|
+
function NavProvider({ configUrl, activeAppId, onAppClick, fallbackConfig, initialCollapsed, children, }) {
|
|
10
|
+
const fallback = fallbackConfig ?? FALLBACK_CONFIG;
|
|
11
|
+
// Stale-while-revalidate: paint the last good payload (or the embedded fallback)
|
|
12
|
+
// synchronously, then swap in the fetched one. First paint never waits on the network.
|
|
13
|
+
const [config, setConfig] = useState(() => cached(configUrl) ?? fallback);
|
|
14
|
+
const [collapsed, setCollapsedState] = useState(() => initialCollapsed ?? readCollapsed() ?? false);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
let live = true;
|
|
17
|
+
void fetchConfig(configUrl).then((next) => {
|
|
18
|
+
if (!live || !next) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
setConfig(next);
|
|
22
|
+
});
|
|
23
|
+
return () => {
|
|
24
|
+
live = false;
|
|
25
|
+
};
|
|
26
|
+
}, [configUrl]);
|
|
27
|
+
const setCollapsed = useCallback((next) => {
|
|
28
|
+
setCollapsedState(next);
|
|
29
|
+
writeCollapsed(next);
|
|
30
|
+
}, []);
|
|
31
|
+
const toggle = useCallback(() => {
|
|
32
|
+
setCollapsedState((current) => {
|
|
33
|
+
writeCollapsed(!current);
|
|
34
|
+
return !current;
|
|
35
|
+
});
|
|
36
|
+
}, []);
|
|
37
|
+
const apps = useMemo(() => resolveApps(config, activeAppId, fallback), [config, activeAppId, fallback]);
|
|
38
|
+
const activeApp = useMemo(() => apps.find((item) => item.active), [apps]);
|
|
39
|
+
const activate = useCallback((entry) => {
|
|
40
|
+
onAppClick?.({ app: entry.app, activeAppId, collapsed });
|
|
41
|
+
}, [onAppClick, activeAppId, collapsed]);
|
|
42
|
+
const value = useMemo(() => ({ config, activeAppId, apps, activeApp, collapsed, setCollapsed, toggle, activate }), [config, activeAppId, apps, activeApp, collapsed, setCollapsed, toggle, activate]);
|
|
43
|
+
return _jsx(NavContext.Provider, { value: value, children: children });
|
|
44
|
+
}
|
|
45
|
+
export { NavProvider };
|
|
46
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { NavApp, NavConfigPayload, ResolvedNavApp } from './types.js';
|
|
2
|
+
declare function hasDestination(app: NavApp): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* The one filter, applied identically to the embedded fallback and to the fetched
|
|
5
|
+
* payload: an entry renders only when it is enabled AND has a destination, so an
|
|
6
|
+
* endpoint outage can never paint a dead tile.
|
|
7
|
+
*
|
|
8
|
+
* The host's own app is the single exemption from `enabled` — it is always
|
|
9
|
+
* rendered and indicated, resolved from the fallback when the payload omits it,
|
|
10
|
+
* because an app that hid itself from its own bar would leave the artist with no
|
|
11
|
+
* indication of where they are and NavTrigger with no chip to dock. It is never
|
|
12
|
+
* exempt from the destination requirement: without one it becomes an inert
|
|
13
|
+
* indicator chip rather than a broken link.
|
|
14
|
+
*
|
|
15
|
+
* A LEGITIMATELY EMPTY payload (`apps: []`, which `normalize` now honours instead of
|
|
16
|
+
* discarding) changes nothing here, deliberately. The empty array is a statement about
|
|
17
|
+
* the CATALOG — the set of other apps a viewer may switch to — and the host's own entry
|
|
18
|
+
* has never been part of that set; it is the one exemption from it. Both invariants
|
|
19
|
+
* therefore hold at once: the catalog is empty, and the viewer still sees where they
|
|
20
|
+
* are and NavTrigger still has a chip to dock. Dropping the active entry too would
|
|
21
|
+
* trade a real regression (no orientation, a blank docked chip) for no gain, and the
|
|
22
|
+
* resolver cannot even see the distinction — an empty fetched payload and an empty
|
|
23
|
+
* `fallbackConfig` arrive here identically.
|
|
24
|
+
*
|
|
25
|
+
* Note this is not a licence to invent destinations: only the ids the compiled-in
|
|
26
|
+
* FALLBACK_CONFIG actually carries (today just `home`) can be resolved this way, which
|
|
27
|
+
* is why an empty payload leaves a satellite host's bar genuinely empty rather than
|
|
28
|
+
* guessing at a domain that may not exist on the stage yet.
|
|
29
|
+
*/
|
|
30
|
+
declare function resolveApps(config: NavConfigPayload, activeAppId: string, fallback: NavConfigPayload): ResolvedNavApp[];
|
|
31
|
+
export { hasDestination, resolveApps };
|
|
32
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3E,iBAAS,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE5C;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,iBAAS,WAAW,CAAC,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,cAAc,EAAE,CAYhH;AAED,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { FALLBACK_CONFIG } from './fallback.js';
|
|
2
|
+
function hasDestination(app) {
|
|
3
|
+
return app.href.trim().length > 0;
|
|
4
|
+
}
|
|
5
|
+
function entry(app, activeAppId) {
|
|
6
|
+
return { app, active: app.id === activeAppId, navigable: hasDestination(app) };
|
|
7
|
+
}
|
|
8
|
+
function findApp(apps, id) {
|
|
9
|
+
return apps.find((app) => app.id === id);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The one filter, applied identically to the embedded fallback and to the fetched
|
|
13
|
+
* payload: an entry renders only when it is enabled AND has a destination, so an
|
|
14
|
+
* endpoint outage can never paint a dead tile.
|
|
15
|
+
*
|
|
16
|
+
* The host's own app is the single exemption from `enabled` — it is always
|
|
17
|
+
* rendered and indicated, resolved from the fallback when the payload omits it,
|
|
18
|
+
* because an app that hid itself from its own bar would leave the artist with no
|
|
19
|
+
* indication of where they are and NavTrigger with no chip to dock. It is never
|
|
20
|
+
* exempt from the destination requirement: without one it becomes an inert
|
|
21
|
+
* indicator chip rather than a broken link.
|
|
22
|
+
*
|
|
23
|
+
* A LEGITIMATELY EMPTY payload (`apps: []`, which `normalize` now honours instead of
|
|
24
|
+
* discarding) changes nothing here, deliberately. The empty array is a statement about
|
|
25
|
+
* the CATALOG — the set of other apps a viewer may switch to — and the host's own entry
|
|
26
|
+
* has never been part of that set; it is the one exemption from it. Both invariants
|
|
27
|
+
* therefore hold at once: the catalog is empty, and the viewer still sees where they
|
|
28
|
+
* are and NavTrigger still has a chip to dock. Dropping the active entry too would
|
|
29
|
+
* trade a real regression (no orientation, a blank docked chip) for no gain, and the
|
|
30
|
+
* resolver cannot even see the distinction — an empty fetched payload and an empty
|
|
31
|
+
* `fallbackConfig` arrive here identically.
|
|
32
|
+
*
|
|
33
|
+
* Note this is not a licence to invent destinations: only the ids the compiled-in
|
|
34
|
+
* FALLBACK_CONFIG actually carries (today just `home`) can be resolved this way, which
|
|
35
|
+
* is why an empty payload leaves a satellite host's bar genuinely empty rather than
|
|
36
|
+
* guessing at a domain that may not exist on the stage yet.
|
|
37
|
+
*/
|
|
38
|
+
function resolveApps(config, activeAppId, fallback) {
|
|
39
|
+
const visible = config.apps.filter((app) => app.id === activeAppId || (app.enabled && hasDestination(app)));
|
|
40
|
+
const resolved = visible.map((app) => entry(app, activeAppId));
|
|
41
|
+
if (resolved.some((item) => item.active)) {
|
|
42
|
+
return resolved;
|
|
43
|
+
}
|
|
44
|
+
const embedded = findApp(fallback.apps, activeAppId) ?? findApp(FALLBACK_CONFIG.apps, activeAppId);
|
|
45
|
+
if (!embedded) {
|
|
46
|
+
return resolved;
|
|
47
|
+
}
|
|
48
|
+
return [entry(embedded, activeAppId), ...resolved];
|
|
49
|
+
}
|
|
50
|
+
export { hasDestination, resolveApps };
|
|
51
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,SAAS,cAAc,CAAC,GAAW;IACjC,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,KAAK,CAAC,GAAW,EAAE,WAAmB;IAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,WAAW,EAAE,SAAS,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,SAAS,OAAO,CAAC,IAAc,EAAE,EAAU;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,SAAS,WAAW,CAAC,MAAwB,EAAE,WAAmB,EAAE,QAA0B;IAC5F,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,WAAW,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5G,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;IAC/D,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,OAAO,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACnG,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC;AACrD,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
import type { NavTheme } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The palettes themselves live in index.css, keyed off data-theme, so switching
|
|
5
|
+
* mode is a config edit rather than a package release. Only the two tokens CSS
|
|
6
|
+
* cannot know in advance come through inline.
|
|
7
|
+
*
|
|
8
|
+
* accent_color replaces the active chip's two-stop gradient with a single flat
|
|
9
|
+
* fill: one value cannot define two stops, so nothing is derived from it.
|
|
10
|
+
*/
|
|
11
|
+
declare function themeVars(theme: NavTheme): CSSProperties;
|
|
12
|
+
export { themeVars };
|
|
13
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;GAOG;AACH,iBAAS,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,aAAa,CASjD;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* The palettes themselves live in index.css, keyed off data-theme, so switching
|
|
4
|
+
* mode is a config edit rather than a package release. Only the two tokens CSS
|
|
5
|
+
* cannot know in advance come through inline.
|
|
6
|
+
*
|
|
7
|
+
* accent_color replaces the active chip's two-stop gradient with a single flat
|
|
8
|
+
* fill: one value cannot define two stops, so nothing is derived from it.
|
|
9
|
+
*/
|
|
10
|
+
function themeVars(theme) {
|
|
11
|
+
const vars = {
|
|
12
|
+
'--ahsuite-tiles-justify': theme.alignment === 'centered' ? 'center' : 'flex-start',
|
|
13
|
+
};
|
|
14
|
+
if (theme.accent_color) {
|
|
15
|
+
vars['--ahsuite-chip-active-bg'] = theme.accent_color;
|
|
16
|
+
vars['--ahsuite-chip-active-image'] = 'none';
|
|
17
|
+
}
|
|
18
|
+
return vars;
|
|
19
|
+
}
|
|
20
|
+
export { themeVars };
|
|
21
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAKb;;;;;;;GAOG;AACH,SAAS,SAAS,CAAC,KAAe;IAChC,MAAM,IAAI,GAA2B;QACnC,yBAAyB,EAAE,KAAK,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY;KACpF,CAAC;IACF,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,IAAI,CAAC,0BAA0B,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;QACtD,IAAI,CAAC,6BAA6B,CAAC,GAAG,MAAM,CAAC;IAC/C,CAAC;IACD,OAAO,IAAqB,CAAC;AAC/B,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire shape of GET /rest/nav-config.
|
|
3
|
+
*
|
|
4
|
+
* The contract is additive: within a schema_version fields are only ever added,
|
|
5
|
+
* never removed or repurposed. Renderers ignore fields they do not recognise and
|
|
6
|
+
* degrade rather than throw on a higher schema_version, so an asynchronously
|
|
7
|
+
* deployed fleet can run mixed renderer versions against one payload.
|
|
8
|
+
*/
|
|
9
|
+
type NavThemeMode = 'dark' | 'light';
|
|
10
|
+
type NavAlignment = 'left' | 'centered';
|
|
11
|
+
interface NavTheme {
|
|
12
|
+
mode: NavThemeMode;
|
|
13
|
+
accent_color: string | null;
|
|
14
|
+
alignment: NavAlignment;
|
|
15
|
+
}
|
|
16
|
+
interface NavLogo {
|
|
17
|
+
label: string;
|
|
18
|
+
href: string;
|
|
19
|
+
}
|
|
20
|
+
interface NavApp {
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
icon: string;
|
|
24
|
+
href: string;
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface NavConfigPayload {
|
|
28
|
+
schema_version: number;
|
|
29
|
+
theme: NavTheme;
|
|
30
|
+
logo: NavLogo;
|
|
31
|
+
apps: NavApp[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One entry as the renderer sees it. `navigable` is false for the host's own app
|
|
35
|
+
* when the catalog gives it no destination: it still renders and is still
|
|
36
|
+
* indicated, but as an inert chip rather than a broken link.
|
|
37
|
+
*/
|
|
38
|
+
interface ResolvedNavApp {
|
|
39
|
+
app: NavApp;
|
|
40
|
+
active: boolean;
|
|
41
|
+
navigable: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** The single seam a host's analytics hooks into. Fired immediately before navigation. */
|
|
44
|
+
interface NavAppClickArgs {
|
|
45
|
+
app: NavApp;
|
|
46
|
+
activeAppId: string;
|
|
47
|
+
collapsed: boolean;
|
|
48
|
+
}
|
|
49
|
+
export type { NavAlignment, NavApp, NavAppClickArgs, NavConfigPayload, NavLogo, NavTheme, NavThemeMode, ResolvedNavApp, };
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,KAAK,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC;AAErC,KAAK,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC;AAExC,UAAU,QAAQ;IAChB,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,YAAY,CAAC;CACzB;AAED,UAAU,OAAO;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,MAAM;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,QAAQ,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;GAIG;AACH,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,0FAA0F;AAC1F,UAAU,eAAe;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,YAAY,EACV,YAAY,EACZ,MAAM,EACN,eAAe,EACf,gBAAgB,EAChB,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire shape of GET /rest/nav-config.
|
|
3
|
+
*
|
|
4
|
+
* The contract is additive: within a schema_version fields are only ever added,
|
|
5
|
+
* never removed or repurposed. Renderers ignore fields they do not recognise and
|
|
6
|
+
* degrade rather than throw on a higher schema_version, so an asynchronously
|
|
7
|
+
* deployed fleet can run mixed renderer versions against one payload.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@artstorefronts/arthelper-nav",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "The ArtHelper suite navigation bar — a config-driven, cross-origin app switcher.",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"files": [
|
|
11
|
+
"/dist"
|
|
12
|
+
],
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc && node --import tsx build.ts",
|
|
18
|
+
"test": "vitest --watch=false"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"lucide-react": ">=0.446.0",
|
|
22
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
23
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@testing-library/dom": "^10.4.0",
|
|
27
|
+
"@testing-library/react": "^16.3.2",
|
|
28
|
+
"@types/react": "^19",
|
|
29
|
+
"@types/react-dom": "^19",
|
|
30
|
+
"jsdom": "^26.1.0",
|
|
31
|
+
"lucide-react": "^0.446.0",
|
|
32
|
+
"react": "19.1.2",
|
|
33
|
+
"react-dom": "19.1.2",
|
|
34
|
+
"tsx": "^4.0.0",
|
|
35
|
+
"typescript": "^5.6.2",
|
|
36
|
+
"vitest": "^3.2.4"
|
|
37
|
+
}
|
|
38
|
+
}
|