@flytedan/flytebot-design-system 0.41.0 → 0.42.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/index.cjs +52 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +52 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -316,7 +316,11 @@ interface CollapsibleProps {
|
|
|
316
316
|
}
|
|
317
317
|
declare function Collapsible({ title, subtitle, badge, icon, defaultOpen, open, onToggle, children, className, ...rest }: CollapsibleProps): React.JSX.Element;
|
|
318
318
|
|
|
319
|
-
/** A right-side panel for detail and editing without losing the list behind it.
|
|
319
|
+
/** A right-side panel for detail and editing without losing the list behind it.
|
|
320
|
+
* MP-248: always modal (declares `aria-modal="true"`), so it traps Tab/Shift+Tab inside
|
|
321
|
+
* itself and returns focus to its trigger on close, via the design system's shared
|
|
322
|
+
* `useFocusTrap` (the same hook Modal uses) — one focus-trap implementation, reused
|
|
323
|
+
* rather than hand-rolled a second time. */
|
|
320
324
|
interface DrawerProps {
|
|
321
325
|
open?: boolean;
|
|
322
326
|
title?: React.ReactNode;
|
|
@@ -3177,7 +3181,12 @@ interface FeatureGateProps {
|
|
|
3177
3181
|
}
|
|
3178
3182
|
/** Feature gate. ALWAYS silent when off — an unreleased feature should leave no trace. */
|
|
3179
3183
|
declare function FeatureGate({ flag, fallback, children, onRoadmap, blur, minHeight, label, variant, preview, bypassPerm }: FeatureGateProps): React.ReactNode;
|
|
3180
|
-
/** Inline "why is this disabled" affordance for buttons that must stay visible.
|
|
3184
|
+
/** Inline "why is this disabled" affordance for buttons that must stay visible.
|
|
3185
|
+
* MP-253: while the session is pending, permission is unknown, not denied — the same rule
|
|
3186
|
+
* Gate applies. Rendering the control live would risk a stale-role grant; rendering the
|
|
3187
|
+
* "Requires X" denial would assert a permission gap that might not be real. So it dims the
|
|
3188
|
+
* control (never `can()`), with a title that says the state is unverified rather than
|
|
3189
|
+
* claiming a specific permission is missing. */
|
|
3181
3190
|
declare function PermissionHint({ perm, children }: {
|
|
3182
3191
|
perm: string | string[];
|
|
3183
3192
|
children?: React.ReactNode;
|
package/dist/index.d.ts
CHANGED
|
@@ -316,7 +316,11 @@ interface CollapsibleProps {
|
|
|
316
316
|
}
|
|
317
317
|
declare function Collapsible({ title, subtitle, badge, icon, defaultOpen, open, onToggle, children, className, ...rest }: CollapsibleProps): React.JSX.Element;
|
|
318
318
|
|
|
319
|
-
/** A right-side panel for detail and editing without losing the list behind it.
|
|
319
|
+
/** A right-side panel for detail and editing without losing the list behind it.
|
|
320
|
+
* MP-248: always modal (declares `aria-modal="true"`), so it traps Tab/Shift+Tab inside
|
|
321
|
+
* itself and returns focus to its trigger on close, via the design system's shared
|
|
322
|
+
* `useFocusTrap` (the same hook Modal uses) — one focus-trap implementation, reused
|
|
323
|
+
* rather than hand-rolled a second time. */
|
|
320
324
|
interface DrawerProps {
|
|
321
325
|
open?: boolean;
|
|
322
326
|
title?: React.ReactNode;
|
|
@@ -3177,7 +3181,12 @@ interface FeatureGateProps {
|
|
|
3177
3181
|
}
|
|
3178
3182
|
/** Feature gate. ALWAYS silent when off — an unreleased feature should leave no trace. */
|
|
3179
3183
|
declare function FeatureGate({ flag, fallback, children, onRoadmap, blur, minHeight, label, variant, preview, bypassPerm }: FeatureGateProps): React.ReactNode;
|
|
3180
|
-
/** Inline "why is this disabled" affordance for buttons that must stay visible.
|
|
3184
|
+
/** Inline "why is this disabled" affordance for buttons that must stay visible.
|
|
3185
|
+
* MP-253: while the session is pending, permission is unknown, not denied — the same rule
|
|
3186
|
+
* Gate applies. Rendering the control live would risk a stale-role grant; rendering the
|
|
3187
|
+
* "Requires X" denial would assert a permission gap that might not be real. So it dims the
|
|
3188
|
+
* control (never `can()`), with a title that says the state is unverified rather than
|
|
3189
|
+
* claiming a specific permission is missing. */
|
|
3181
3190
|
declare function PermissionHint({ perm, children }: {
|
|
3182
3191
|
perm: string | string[];
|
|
3183
3192
|
children?: React.ReactNode;
|
package/dist/index.js
CHANGED
|
@@ -772,54 +772,17 @@ function Collapsible({
|
|
|
772
772
|
}
|
|
773
773
|
|
|
774
774
|
// src/components/surfaces/Drawer.tsx
|
|
775
|
-
import * as
|
|
775
|
+
import * as React6 from "react";
|
|
776
776
|
import { createPortal as createPortal2 } from "react-dom";
|
|
777
|
-
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
778
|
-
function Drawer({ open = true, title, onClose, footer, children, className = "", ...rest }) {
|
|
779
|
-
const zIndex = useOverlayLayer(open);
|
|
780
|
-
const [closing, setClosing] = React5.useState(false);
|
|
781
|
-
const close = React5.useCallback(() => {
|
|
782
|
-
if (!onClose) return;
|
|
783
|
-
setClosing(true);
|
|
784
|
-
setTimeout(onClose, 210);
|
|
785
|
-
}, [onClose]);
|
|
786
|
-
React5.useEffect(() => {
|
|
787
|
-
if (!open || !onClose) return;
|
|
788
|
-
const h = (e) => {
|
|
789
|
-
if (e.key === "Escape") close();
|
|
790
|
-
};
|
|
791
|
-
document.addEventListener("keydown", h);
|
|
792
|
-
return () => document.removeEventListener("keydown", h);
|
|
793
|
-
}, [open, onClose, close]);
|
|
794
|
-
if (!open) return null;
|
|
795
|
-
return createPortal2(
|
|
796
|
-
/* @__PURE__ */ jsxs6(LayerProvider, { zIndex, children: [
|
|
797
|
-
/* @__PURE__ */ jsx8("div", { className: "fd-scrim" + (closing ? " is-closing" : ""), style: { display: "block", zIndex: zIndex - LAYER_STEP }, onClick: close }),
|
|
798
|
-
/* @__PURE__ */ jsxs6("aside", { className: ["fd-drawer", closing ? "is-closing" : "", className].filter(Boolean).join(" "), role: "dialog", "aria-modal": "true", ...rest, style: { zIndex }, children: [
|
|
799
|
-
/* @__PURE__ */ jsxs6("div", { className: "fd-card-head", style: { flex: "none" }, children: [
|
|
800
|
-
/* @__PURE__ */ jsx8("span", { className: "fd-card-head-title", title: truncationTitle(title), children: title }),
|
|
801
|
-
onClose ? /* @__PURE__ */ jsx8("button", { type: "button", className: "fd-btn-icon", "aria-label": "Close", onClick: close, children: /* @__PURE__ */ jsx8("i", { className: "ph ph-x" }) }) : null
|
|
802
|
-
] }),
|
|
803
|
-
/* @__PURE__ */ jsx8("div", { style: { flex: "1 1 auto", minHeight: 0, overflow: "auto", padding: 20 }, children }),
|
|
804
|
-
footer ? /* @__PURE__ */ jsx8("div", { className: "fd-card-foot", style: { flex: "none" }, children: typeof footer === "function" ? footer(close) : footer }) : null
|
|
805
|
-
] })
|
|
806
|
-
] }),
|
|
807
|
-
document.body
|
|
808
|
-
);
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
// src/components/surfaces/Modal.tsx
|
|
812
|
-
import * as React7 from "react";
|
|
813
|
-
import { createPortal as createPortal3 } from "react-dom";
|
|
814
777
|
|
|
815
778
|
// src/kits/useFocusTrap.ts
|
|
816
|
-
import * as
|
|
779
|
+
import * as React5 from "react";
|
|
817
780
|
var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
818
781
|
function getFocusable(container) {
|
|
819
782
|
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
820
783
|
}
|
|
821
784
|
function useFocusTrap(containerRef, active) {
|
|
822
|
-
|
|
785
|
+
React5.useEffect(() => {
|
|
823
786
|
if (!active) return;
|
|
824
787
|
const container = containerRef.current;
|
|
825
788
|
if (!container) return;
|
|
@@ -855,7 +818,46 @@ function useFocusTrap(containerRef, active) {
|
|
|
855
818
|
}, [active, containerRef]);
|
|
856
819
|
}
|
|
857
820
|
|
|
821
|
+
// src/components/surfaces/Drawer.tsx
|
|
822
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
823
|
+
function Drawer({ open = true, title, onClose, footer, children, className = "", ...rest }) {
|
|
824
|
+
const zIndex = useOverlayLayer(open);
|
|
825
|
+
const asideRef = React6.useRef(null);
|
|
826
|
+
useFocusTrap(asideRef, !!open);
|
|
827
|
+
const [closing, setClosing] = React6.useState(false);
|
|
828
|
+
const close = React6.useCallback(() => {
|
|
829
|
+
if (!onClose) return;
|
|
830
|
+
setClosing(true);
|
|
831
|
+
setTimeout(onClose, 210);
|
|
832
|
+
}, [onClose]);
|
|
833
|
+
React6.useEffect(() => {
|
|
834
|
+
if (!open || !onClose) return;
|
|
835
|
+
const h = (e) => {
|
|
836
|
+
if (e.key === "Escape") close();
|
|
837
|
+
};
|
|
838
|
+
document.addEventListener("keydown", h);
|
|
839
|
+
return () => document.removeEventListener("keydown", h);
|
|
840
|
+
}, [open, onClose, close]);
|
|
841
|
+
if (!open) return null;
|
|
842
|
+
return createPortal2(
|
|
843
|
+
/* @__PURE__ */ jsxs6(LayerProvider, { zIndex, children: [
|
|
844
|
+
/* @__PURE__ */ jsx8("div", { className: "fd-scrim" + (closing ? " is-closing" : ""), style: { display: "block", zIndex: zIndex - LAYER_STEP }, onClick: close }),
|
|
845
|
+
/* @__PURE__ */ jsxs6("aside", { ref: asideRef, className: ["fd-drawer", closing ? "is-closing" : "", className].filter(Boolean).join(" "), role: "dialog", "aria-modal": "true", ...rest, style: { zIndex }, children: [
|
|
846
|
+
/* @__PURE__ */ jsxs6("div", { className: "fd-card-head", style: { flex: "none" }, children: [
|
|
847
|
+
/* @__PURE__ */ jsx8("span", { className: "fd-card-head-title", title: truncationTitle(title), children: title }),
|
|
848
|
+
onClose ? /* @__PURE__ */ jsx8("button", { type: "button", className: "fd-btn-icon", "aria-label": "Close", onClick: close, children: /* @__PURE__ */ jsx8("i", { className: "ph ph-x" }) }) : null
|
|
849
|
+
] }),
|
|
850
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: "1 1 auto", minHeight: 0, overflow: "auto", padding: 20 }, children }),
|
|
851
|
+
footer ? /* @__PURE__ */ jsx8("div", { className: "fd-card-foot", style: { flex: "none" }, children: typeof footer === "function" ? footer(close) : footer }) : null
|
|
852
|
+
] })
|
|
853
|
+
] }),
|
|
854
|
+
document.body
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
858
|
// src/components/surfaces/Modal.tsx
|
|
859
|
+
import * as React7 from "react";
|
|
860
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
859
861
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
860
862
|
function Modal({ open = true, title, description, onClose, footer, wide = false, children, className = "", ...rest }) {
|
|
861
863
|
const [closing, setClosing] = React7.useState(false);
|
|
@@ -7060,14 +7062,14 @@ function AccountMenu({
|
|
|
7060
7062
|
className = "",
|
|
7061
7063
|
...rest
|
|
7062
7064
|
}) {
|
|
7063
|
-
const { user, roles, can: can2, signOut: ctxSignOut, demo } = useSessionContext();
|
|
7065
|
+
const { user, roles, can: can2, signOut: ctxSignOut, demo, pending } = useSessionContext();
|
|
7064
7066
|
const [open, setOpen] = React43.useState(false);
|
|
7065
7067
|
const [switching, setSwitching] = React43.useState(false);
|
|
7066
7068
|
const [signingOut, setSigningOut] = React43.useState(false);
|
|
7067
7069
|
const [signOutError, setSignOutError] = React43.useState(null);
|
|
7068
7070
|
const ref = React43.useRef(null);
|
|
7069
|
-
const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
|
|
7070
|
-
const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
|
|
7071
|
+
const visibleLinks = links.filter((l) => !l.perm || !pending && can2(l.perm));
|
|
7072
|
+
const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || !pending && can2(l.perm)) })).filter((g) => g.links.length);
|
|
7071
7073
|
const closeMenu = () => {
|
|
7072
7074
|
setOpen(false);
|
|
7073
7075
|
setSignOutError(null);
|
|
@@ -10379,6 +10381,7 @@ function GatePending({ compact: compact3 = false, className = "" }) {
|
|
|
10379
10381
|
"div",
|
|
10380
10382
|
{
|
|
10381
10383
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
10384
|
+
role: "status",
|
|
10382
10385
|
style: {
|
|
10383
10386
|
gap: 10,
|
|
10384
10387
|
alignItems: "flex-start",
|
|
@@ -10428,14 +10431,14 @@ function FeatureGate({
|
|
|
10428
10431
|
bypassPerm = "flags.manage"
|
|
10429
10432
|
}) {
|
|
10430
10433
|
SessionKit.useSession();
|
|
10431
|
-
const { can: can2 } = useSessionContext();
|
|
10434
|
+
const { can: can2, pending } = useSessionContext();
|
|
10432
10435
|
const rt = useFeatureStatus(flag);
|
|
10433
10436
|
if (!SessionKit.isEnabled(flag)) return fallback;
|
|
10434
10437
|
if (rt.complete || rt.mode === "test") return children;
|
|
10435
10438
|
if (!preview) return fallback;
|
|
10436
10439
|
const f = SessionKit.findFlag(flag) || {};
|
|
10437
10440
|
const missing = rt.missing || [];
|
|
10438
|
-
const canBypass = bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
|
|
10441
|
+
const canBypass = pending ? false : bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
|
|
10439
10442
|
return /* @__PURE__ */ jsx77(
|
|
10440
10443
|
ComingSoon,
|
|
10441
10444
|
{
|
|
@@ -10455,7 +10458,10 @@ function FeatureGate({
|
|
|
10455
10458
|
);
|
|
10456
10459
|
}
|
|
10457
10460
|
function PermissionHint({ perm, children }) {
|
|
10458
|
-
const { can: can2 } = useSessionContext();
|
|
10461
|
+
const { can: can2, pending } = useSessionContext();
|
|
10462
|
+
if (pending) {
|
|
10463
|
+
return /* @__PURE__ */ jsx77("span", { title: "Access can't be verified right now", style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" }, "aria-disabled": "true", children: /* @__PURE__ */ jsx77("span", { style: { pointerEvents: "none" }, children }) });
|
|
10464
|
+
}
|
|
10459
10465
|
if (can2(perm)) return children;
|
|
10460
10466
|
return /* @__PURE__ */ jsx77(
|
|
10461
10467
|
"span",
|