@helloimjolopez-pathway/pathway-components 0.8.0 → 0.9.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/components/_shared/focus-ring.js +45 -0
- package/components/nav-shell/nav-shell.jsx +2 -2
- package/components/sidenav/accounting-side-nav.jsx +14 -3
- package/components/sidenav/sidenav.jsx +32 -0
- package/dist/pathway-accounting-sidenav.js +7 -7
- package/dist/pathway-components.js +26 -26
- package/dist/pathway-sidenav.js +5 -5
- package/package.json +1 -1
- package/components/bottom-sheet/bottom-sheet-demo.jsx +0 -145
- package/components/nav-shell/nav-shell-demo.jsx +0 -59
- package/components/radio/radio-demo.jsx +0 -175
- package/components/scroll-to-enable/scroll-to-enable-demo.jsx +0 -125
- package/components/toggle-button/toggle-button-demo.jsx +0 -193
- package/components/tooltip/tooltip-demo.jsx +0 -149
- package/components/top-nav/top-nav-demo.jsx +0 -79
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard focus ring shared by controls that style themselves inline.
|
|
3
|
+
*
|
|
4
|
+
* One ring for every Pathway control: FocusRing/Width of Stroke/FocusRing/Base,
|
|
5
|
+
* drawn as an outline that hugs the element's edge (no gap), the way Figma draws
|
|
6
|
+
* it: an outside stroke on the control's own container in each Focused variant.
|
|
7
|
+
* Menu rows take the inset variant, as PopoverMenu.Item does in Figma. Where the
|
|
8
|
+
* Figma ring takes the place of the control's border, FOCUS_RING_REPLACE also
|
|
9
|
+
* hides that border while the ring shows.
|
|
10
|
+
*
|
|
11
|
+
* A stylesheet rule rather than inline style, because :focus-visible (keyboard
|
|
12
|
+
* focus only, never a mouse click) can only be matched by a selector.
|
|
13
|
+
*/
|
|
14
|
+
export const FOCUS_RING = "pw-focus-ring";
|
|
15
|
+
export const FOCUS_RING_INSET = "pw-focus-ring pw-focus-ring--inset";
|
|
16
|
+
// The ring replaces the control's border (drawn as an inset box-shadow or a CSS
|
|
17
|
+
// border). A control that also carries an elevation keeps it by setting
|
|
18
|
+
// --pw-ring-keep-shadow in its own style.
|
|
19
|
+
export const FOCUS_RING_REPLACE = "pw-focus-ring pw-focus-ring--replace";
|
|
20
|
+
// For a button that is a bigger touch target than what it draws (an action
|
|
21
|
+
// icon's 44 target around its 28 layer, the 48 profile button around its 32
|
|
22
|
+
// avatar): the ring goes on the drawn layer, marked data-pw-ring-target, as
|
|
23
|
+
// the Figma Focus Ring layer does.
|
|
24
|
+
export const FOCUS_RING_LAYER = "pw-focus-ring pw-focus-ring--layer";
|
|
25
|
+
|
|
26
|
+
// Also exported so a shadow root can carry it: a rule in document.head does not
|
|
27
|
+
// reach inside one, so the custom elements append this to their own styles.
|
|
28
|
+
export const FOCUS_RING_CSS = `
|
|
29
|
+
.pw-focus-ring:focus{outline:none}
|
|
30
|
+
.pw-focus-ring:focus-visible{outline:var(--contextual-layout-units-focusring-width) solid var(--semantic-color-stroke-focusring-base);outline-offset:0}
|
|
31
|
+
.pw-focus-ring--inset:focus-visible{outline-offset:calc(-1 * var(--contextual-layout-units-focusring-width))}
|
|
32
|
+
.pw-focus-ring--replace:focus-visible{border-color:transparent !important;box-shadow:var(--pw-ring-keep-shadow, none) !important}
|
|
33
|
+
.pw-focus-ring--layer:focus-visible{outline:none}
|
|
34
|
+
.pw-focus-ring--layer:focus-visible [data-pw-ring-target]{outline:var(--contextual-layout-units-focusring-width) solid var(--semantic-color-stroke-focusring-base);outline-offset:0}
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
let injected = false;
|
|
38
|
+
export function injectFocusRing() {
|
|
39
|
+
if (injected || typeof document === "undefined") return;
|
|
40
|
+
injected = true;
|
|
41
|
+
const el = document.createElement("style");
|
|
42
|
+
el.setAttribute("data-pathway", "focus-ring");
|
|
43
|
+
el.textContent = FOCUS_RING_CSS;
|
|
44
|
+
document.head.appendChild(el);
|
|
45
|
+
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import React, { useState, useEffect, useCallback } from "react";
|
|
14
14
|
import TopNav, { DEFAULT_MODULES } from "../top-nav/top-nav.jsx";
|
|
15
15
|
import { SideNav } from "../sidenav/sidenav.jsx";
|
|
16
|
-
import {
|
|
16
|
+
import { moduleHeader } from "../sidenav/accounting-side-nav.jsx";
|
|
17
17
|
|
|
18
18
|
// ─── CONSTANTS ────────────────────────────────────────────────────────────────
|
|
19
19
|
const TOPNAV_H = 60; // px — spec §9.3 rule 1
|
|
@@ -292,7 +292,7 @@ export function NavShell({
|
|
|
292
292
|
hideCollapseButton={isTablet || isMobile}
|
|
293
293
|
headerEnd={navHeaderEnd}
|
|
294
294
|
footer={navFooter}
|
|
295
|
-
headerStart={appSwitcher
|
|
295
|
+
headerStart={moduleHeader(appSwitcher)}
|
|
296
296
|
appSwitcher={appSwitcher ? { ...appSwitcher, activeId: appActive, onSelect: handleAppSelect,
|
|
297
297
|
// Mobile opens the menu as a BottomSheet (Figma 40016737:141824).
|
|
298
298
|
presentation: isMobile ? "sheet" : "popover" } : null}
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import React, { useEffect, useState } from "react";
|
|
31
31
|
import { SideNav } from "./sidenav.jsx";
|
|
32
|
-
import {
|
|
32
|
+
import { SideNavHeaderLabel } from "./sidenav.jsx";
|
|
33
|
+
import { ModuleIcon } from "../module-icon/module-icon.jsx";
|
|
33
34
|
|
|
34
35
|
// The Accounting module's applications, each with its own side nav. NavShell's
|
|
35
36
|
// `app-switcher` and <pathway-accounting-sidenav> fall back to this when no
|
|
@@ -49,7 +50,8 @@ const APP_NAV_STANDARD = ["Dashboard", "Enter", "Manage", "View", "Reports", "Mo
|
|
|
49
50
|
export const ACCOUNTING_APP_SWITCHER = {
|
|
50
51
|
label: "Financials Home",
|
|
51
52
|
icon: "apps",
|
|
52
|
-
// The module's
|
|
53
|
+
// The module's label in the SideNav header: Figma SideNav.Header.Label with
|
|
54
|
+
// the Accounting icon chip (40016737:141726, 2026-11-12).
|
|
53
55
|
moduleMark: { module: "accounting", label: "Financials" },
|
|
54
56
|
// The Accounting TopNav is TopNav.Global with Search and Actions hidden
|
|
55
57
|
// (Figma 40007879:18072): module switcher, org switcher and profile only.
|
|
@@ -66,6 +68,15 @@ export const ACCOUNTING_APP_SWITCHER = {
|
|
|
66
68
|
{ id: "purchasing-management", label: "Purchasing Management", navItems: accountingNav("pm", ["Dashboard", "Enter", "Manage", "Reports", "Modify", "Help"]) },
|
|
67
69
|
],
|
|
68
70
|
};
|
|
71
|
+
// The nav header's start slot for a module: SideNav.Header.Label with the
|
|
72
|
+
// module's icon chip. NavShell uses the same, so the two headers never differ.
|
|
73
|
+
export function moduleHeader(appSwitcher) {
|
|
74
|
+
const m = appSwitcher && appSwitcher.moduleMark;
|
|
75
|
+
if (!m) return null;
|
|
76
|
+
return <SideNavHeaderLabel label={m.label}
|
|
77
|
+
icon={m.module ? <ModuleIcon module={m.module} size={14} color="mono" /> : null} />;
|
|
78
|
+
}
|
|
79
|
+
|
|
69
80
|
const MOBILE_MAX = 767; // below 768, as NavShell's breakpoint
|
|
70
81
|
|
|
71
82
|
function useIsMobile() {
|
|
@@ -107,7 +118,7 @@ export function AccountingSideNav({
|
|
|
107
118
|
|
|
108
119
|
return (
|
|
109
120
|
<SideNav key={current && current.id} items={items} activeId={active} onNavigate={navigate}
|
|
110
|
-
headerStart={appSwitcher
|
|
121
|
+
headerStart={moduleHeader(appSwitcher)}
|
|
111
122
|
appSwitcher={{ ...appSwitcher, activeId: current && current.id, onSelect: selectApp, presentation: mode }}
|
|
112
123
|
{...rest} />
|
|
113
124
|
);
|
|
@@ -747,6 +747,38 @@ export function AppSwitcher({ label: fallbackLabel, icon = "apps", home, apps =
|
|
|
747
747
|
);
|
|
748
748
|
}
|
|
749
749
|
|
|
750
|
+
// ─── SideNavHeaderLabel ───────────────────────────────────────────────────────
|
|
751
|
+
// Figma SideNav.Header.Label (40018260:4928), read 2026-11-12 from the
|
|
752
|
+
// Accounting Module Nav Shell (40016737:141726). The label at the start of the
|
|
753
|
+
// nav header, beside the collapse control. Text only for a pillar rail; with
|
|
754
|
+
// `icon`, the module's icon chip sits before the name (a module rail, such as
|
|
755
|
+
// Accounting's Financials).
|
|
756
|
+
// IconChip 28, CornerRadius/Base, Fill/Static/Brand/Strong, clips
|
|
757
|
+
// icon the module glyph at 14, Fill/Static/Neutral/Mono
|
|
758
|
+
// label Heading/Local/Base/Semibold: 14 / 600 / 18 / 0.3,
|
|
759
|
+
// Foreground/Static/Neutral/Strong, truncates; gap Gap/XXTight
|
|
760
|
+
// width 160 in Figma: here it fills the row up to the collapse control
|
|
761
|
+
export function SideNavHeaderLabel({ label, icon = null }) {
|
|
762
|
+
return (
|
|
763
|
+
<span style={{ display: "flex", alignItems: "center", minWidth: 0, flex: 1,
|
|
764
|
+
gap: "var(--semantic-layout-units-gap-xxtight)" }}>
|
|
765
|
+
{icon && (
|
|
766
|
+
<span aria-hidden="true" style={{ width: 28, height: 28, flexShrink: 0, overflow: "hidden",
|
|
767
|
+
display: "inline-flex", alignItems: "center", justifyContent: "center",
|
|
768
|
+
borderRadius: "var(--semantic-layout-units-cornerradius-base)",
|
|
769
|
+
background: c("fill-static-brand-strong"), color: c("fill-static-neutral-mono") }}>
|
|
770
|
+
{icon}
|
|
771
|
+
</span>
|
|
772
|
+
)}
|
|
773
|
+
<span style={{ flex: 1, minWidth: 0, fontFamily: "var(--semantic-type-family-brand)",
|
|
774
|
+
fontWeight: "var(--semantic-type-weight-semibold)", fontSize: "var(--semantic-type-font-size-s)",
|
|
775
|
+
lineHeight: "var(--semantic-type-line-height-s-tight)", letterSpacing: "var(--semantic-type-letter-spacing-spacious)",
|
|
776
|
+
color: c("foreground-static-neutral-strong"),
|
|
777
|
+
whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{label}</span>
|
|
778
|
+
</span>
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
|
|
750
782
|
// ─── CollapseButton ───────────────────────────────────────────────────────────
|
|
751
783
|
// Redesigned in Figma (2026-05-12): now uses Slot.RowStart (Module.Mark icon)
|
|
752
784
|
// + Slot.RowEnd (Action Icon). The action icon uses Foreground/Action/Secondary/Rest
|