@stigmer/react 3.0.5 → 3.0.7-dev.20260611143057
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/agent/AgentDetailView.d.ts.map +1 -1
- package/agent/AgentDetailView.js +1 -1
- package/agent/AgentDetailView.js.map +1 -1
- package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
- package/agent-instance/AgentInstanceDetailPanel.js +2 -13
- package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
- package/agent-instance/AgentInstanceList.d.ts.map +1 -1
- package/agent-instance/AgentInstanceList.js +2 -13
- package/agent-instance/AgentInstanceList.js.map +1 -1
- package/agent-instance/CreateAgentInstanceDialog.d.ts.map +1 -1
- package/agent-instance/CreateAgentInstanceDialog.js +1 -1
- package/agent-instance/CreateAgentInstanceDialog.js.map +1 -1
- package/composer/SessionComposer.d.ts +14 -0
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +15 -9
- package/composer/SessionComposer.js.map +1 -1
- package/index.d.ts +3 -3
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/library/InstanceVisibilitySelector.d.ts +30 -23
- package/library/InstanceVisibilitySelector.d.ts.map +1 -1
- package/library/InstanceVisibilitySelector.js +22 -145
- package/library/InstanceVisibilitySelector.js.map +1 -1
- package/library/ResourceVisibilityControl.d.ts +23 -6
- package/library/ResourceVisibilityControl.d.ts.map +1 -1
- package/library/ResourceVisibilityControl.js +38 -9
- package/library/ResourceVisibilityControl.js.map +1 -1
- package/library/ScopeToggle.d.ts +1 -1
- package/library/ScopeToggle.js +1 -1
- package/library/VisibilityOptionRow.d.ts +52 -0
- package/library/VisibilityOptionRow.d.ts.map +1 -0
- package/library/VisibilityOptionRow.js +92 -0
- package/library/VisibilityOptionRow.js.map +1 -0
- package/library/VisibilitySelector.d.ts +98 -0
- package/library/VisibilitySelector.d.ts.map +1 -0
- package/library/VisibilitySelector.js +193 -0
- package/library/VisibilitySelector.js.map +1 -0
- package/library/index.d.ts +4 -2
- package/library/index.d.ts.map +1 -1
- package/library/index.js +2 -1
- package/library/index.js.map +1 -1
- package/library/useUpdateVisibility.d.ts +5 -4
- package/library/useUpdateVisibility.d.ts.map +1 -1
- package/library/useUpdateVisibility.js +5 -4
- package/library/useUpdateVisibility.js.map +1 -1
- package/library/visibilityLevels.d.ts +96 -0
- package/library/visibilityLevels.d.ts.map +1 -0
- package/library/visibilityLevels.js +97 -0
- package/library/visibilityLevels.js.map +1 -0
- package/mcp-server/McpServerDetailView.d.ts +1 -11
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +3 -6
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/package.json +4 -4
- package/resource-detail/types.d.ts +1 -1
- package/session/NewSessionViewer.d.ts +32 -1
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +20 -9
- package/session/NewSessionViewer.js.map +1 -1
- package/session/SessionViewer.d.ts +24 -1
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +18 -12
- package/session/SessionViewer.js.map +1 -1
- package/session/audience.d.ts +21 -0
- package/session/audience.d.ts.map +1 -0
- package/session/audience.js +2 -0
- package/session/audience.js.map +1 -0
- package/session/index.d.ts +2 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js.map +1 -1
- package/session/runtime-env.d.ts +47 -0
- package/session/runtime-env.d.ts.map +1 -0
- package/session/runtime-env.js +20 -0
- package/session/runtime-env.js.map +1 -0
- package/session/useNewSessionFlow.d.ts +25 -0
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +20 -8
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSessionPageFlow.d.ts +27 -2
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +34 -13
- package/session/useSessionPageFlow.js.map +1 -1
- package/skill/SkillDetailView.d.ts.map +1 -1
- package/skill/SkillDetailView.js +1 -1
- package/skill/SkillDetailView.js.map +1 -1
- package/src/agent/AgentDetailView.tsx +1 -0
- package/src/agent-instance/AgentInstanceDetailPanel.tsx +7 -32
- package/src/agent-instance/AgentInstanceList.tsx +7 -32
- package/src/agent-instance/CreateAgentInstanceDialog.tsx +1 -0
- package/src/composer/SessionComposer.tsx +30 -8
- package/src/composer/__tests__/SessionComposer-lockAgent.test.tsx +150 -0
- package/src/index.ts +10 -2
- package/src/library/InstanceVisibilitySelector.tsx +44 -283
- package/src/library/ResourceVisibilityControl.tsx +54 -8
- package/src/library/ScopeToggle.tsx +1 -1
- package/src/library/VisibilityOptionRow.tsx +244 -0
- package/src/library/VisibilitySelector.tsx +436 -0
- package/src/library/__tests__/VisibilitySelector.test.tsx +256 -0
- package/src/library/index.ts +13 -2
- package/src/library/useUpdateVisibility.ts +5 -4
- package/src/library/visibilityLevels.ts +174 -0
- package/src/mcp-server/McpServerDetailView.tsx +10 -35
- package/src/resource-detail/types.ts +1 -1
- package/src/session/NewSessionViewer.tsx +61 -12
- package/src/session/SessionViewer.tsx +51 -15
- package/src/session/__tests__/audienceWiring.test.tsx +274 -0
- package/src/session/__tests__/useNewSessionFlow.test.tsx +122 -0
- package/src/session/__tests__/useSessionPageFlow.runtimeEnv.test.tsx +170 -0
- package/src/session/audience.ts +20 -0
- package/src/session/index.ts +3 -0
- package/src/session/runtime-env.ts +57 -0
- package/src/session/useNewSessionFlow.ts +44 -9
- package/src/session/useSessionPageFlow.ts +65 -17
- package/src/skill/SkillDetailView.tsx +1 -0
- package/src/workflow/WorkflowDetailView.tsx +1 -0
- package/src/workflow/instance/CreateWorkflowInstanceDialog.tsx +1 -0
- package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +7 -32
- package/src/workflow/instance/WorkflowInstanceList.tsx +7 -32
- package/styles.css +1 -1
- package/workflow/WorkflowDetailView.d.ts.map +1 -1
- package/workflow/WorkflowDetailView.js +1 -1
- package/workflow/WorkflowDetailView.js.map +1 -1
- package/workflow/instance/CreateWorkflowInstanceDialog.d.ts.map +1 -1
- package/workflow/instance/CreateWorkflowInstanceDialog.js +1 -1
- package/workflow/instance/CreateWorkflowInstanceDialog.js.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.js +2 -13
- package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
- package/workflow/instance/WorkflowInstanceList.d.ts.map +1 -1
- package/workflow/instance/WorkflowInstanceList.js +2 -13
- package/workflow/instance/WorkflowInstanceList.js.map +1 -1
- package/library/VisibilityToggle.d.ts +0 -53
- package/library/VisibilityToggle.d.ts.map +0 -1
- package/library/VisibilityToggle.js +0 -100
- package/library/VisibilityToggle.js.map +0 -1
- package/src/library/VisibilityToggle.tsx +0 -280
|
@@ -8,6 +8,13 @@ export interface ResourceVisibilityControlProps {
|
|
|
8
8
|
readonly resourceId: string;
|
|
9
9
|
/** Current visibility of the resource. */
|
|
10
10
|
readonly visibility: ApiResourceVisibility;
|
|
11
|
+
/**
|
|
12
|
+
* Slug of the organization that OWNS the resource (`metadata.org`).
|
|
13
|
+
* Used to look up whether the org operates an IdentityProvider, which
|
|
14
|
+
* gates the Platform option for blueprints. When omitted, Platform is
|
|
15
|
+
* simply not offered (the other levels need no org context).
|
|
16
|
+
*/
|
|
17
|
+
readonly org?: string;
|
|
11
18
|
/**
|
|
12
19
|
* Called after a successful visibility change so the host can refresh the
|
|
13
20
|
* resource (e.g. `refetch`) and reflect the new state.
|
|
@@ -21,15 +28,25 @@ export interface ResourceVisibilityControlProps {
|
|
|
21
28
|
*
|
|
22
29
|
* Behavior:
|
|
23
30
|
* - Always renders a legible state: a read-only {@link VisibilityBadge}
|
|
24
|
-
* (
|
|
31
|
+
* (all four levels) is shown to viewers without `can_edit` and while the
|
|
25
32
|
* permission check is in flight — never a silent blank.
|
|
26
|
-
* - Upgrades to the interactive {@link
|
|
33
|
+
* - Upgrades to the interactive {@link VisibilitySelector} for users with
|
|
27
34
|
* `can_edit`, persisting changes via {@link useUpdateVisibility} and invoking
|
|
28
35
|
* {@link ResourceVisibilityControlProps.onChanged} on success.
|
|
29
36
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
37
|
+
* Offered levels are kind- and context-aware (`visibilityLevels.ts`):
|
|
38
|
+
* - Blueprints (agent/workflow/skill/mcp_server): Private / Organization /
|
|
39
|
+
* Public, plus Platform when the deployment is `cloud` AND the owning org
|
|
40
|
+
* operates an IdentityProvider (checked via {@link useSsoProvider}, the
|
|
41
|
+
* only permission-free IdP lookup — blueprint owners editing visibility
|
|
42
|
+
* are not necessarily org admins). In `local` mode (OSS Go backend) the
|
|
43
|
+
* set collapses to Private / Public.
|
|
44
|
+
* - Instances: Private / Organization / Public — platform is excluded by
|
|
45
|
+
* design to preserve tenant isolation.
|
|
46
|
+
*
|
|
47
|
+
* The backend remains the enforcer (`ValidateVisibilityStep` rejects
|
|
48
|
+
* platform without an IdP); the gate here only prevents offering an option
|
|
49
|
+
* that is guaranteed to fail.
|
|
33
50
|
*/
|
|
34
|
-
export declare function ResourceVisibilityControl({ kind, resourceId, visibility, onChanged, className, }: ResourceVisibilityControlProps): import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
export declare function ResourceVisibilityControl({ kind, resourceId, visibility, org, onChanged, className, }: ResourceVisibilityControlProps): import("react/jsx-runtime").JSX.Element;
|
|
35
52
|
//# sourceMappingURL=ResourceVisibilityControl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResourceVisibilityControl.d.ts","sourceRoot":"","sources":["../../src/library/ResourceVisibilityControl.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wDAAwD,CAAC;
|
|
1
|
+
{"version":3,"file":"ResourceVisibilityControl.d.ts","sourceRoot":"","sources":["../../src/library/ResourceVisibilityControl.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wDAAwD,CAAC;AASpG,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAsB/B,mDAAmD;AACnD,MAAM,WAAW,8BAA8B;IAC7C,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,IAAI,EACJ,UAAU,EACV,UAAU,EACV,GAAG,EACH,SAAS,EACT,SAAS,GACV,EAAE,8BAA8B,2CAmDhC"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback } from "react";
|
|
4
|
+
import { useDeploymentMode } from "../deployment-mode";
|
|
4
5
|
import { PermissionGate } from "../iam-policy/PermissionGate";
|
|
5
|
-
import {
|
|
6
|
+
import { useSsoProvider } from "../identity-provider/useSsoProvider";
|
|
7
|
+
import { VisibilityBadge, VisibilitySelector } from "./VisibilitySelector";
|
|
8
|
+
import { blueprintVisibilityLevels, INSTANCE_VISIBILITY_LEVELS, } from "./visibilityLevels";
|
|
6
9
|
import { useUpdateVisibility, } from "./useUpdateVisibility";
|
|
7
10
|
/**
|
|
8
11
|
* Maps a {@link VisibilityResourceKind} (which mirrors the SDK method namespace,
|
|
@@ -18,23 +21,49 @@ const FGA_KIND = {
|
|
|
18
21
|
agentInstance: "agent_instance",
|
|
19
22
|
workflowInstance: "workflow_instance",
|
|
20
23
|
};
|
|
24
|
+
const INSTANCE_KINDS = new Set([
|
|
25
|
+
"agentInstance",
|
|
26
|
+
"workflowInstance",
|
|
27
|
+
]);
|
|
21
28
|
/**
|
|
22
29
|
* Single source of truth for the resource-visibility control in detail headers.
|
|
23
30
|
*
|
|
24
31
|
* Behavior:
|
|
25
32
|
* - Always renders a legible state: a read-only {@link VisibilityBadge}
|
|
26
|
-
* (
|
|
33
|
+
* (all four levels) is shown to viewers without `can_edit` and while the
|
|
27
34
|
* permission check is in flight — never a silent blank.
|
|
28
|
-
* - Upgrades to the interactive {@link
|
|
35
|
+
* - Upgrades to the interactive {@link VisibilitySelector} for users with
|
|
29
36
|
* `can_edit`, persisting changes via {@link useUpdateVisibility} and invoking
|
|
30
37
|
* {@link ResourceVisibilityControlProps.onChanged} on success.
|
|
31
38
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
39
|
+
* Offered levels are kind- and context-aware (`visibilityLevels.ts`):
|
|
40
|
+
* - Blueprints (agent/workflow/skill/mcp_server): Private / Organization /
|
|
41
|
+
* Public, plus Platform when the deployment is `cloud` AND the owning org
|
|
42
|
+
* operates an IdentityProvider (checked via {@link useSsoProvider}, the
|
|
43
|
+
* only permission-free IdP lookup — blueprint owners editing visibility
|
|
44
|
+
* are not necessarily org admins). In `local` mode (OSS Go backend) the
|
|
45
|
+
* set collapses to Private / Public.
|
|
46
|
+
* - Instances: Private / Organization / Public — platform is excluded by
|
|
47
|
+
* design to preserve tenant isolation.
|
|
48
|
+
*
|
|
49
|
+
* The backend remains the enforcer (`ValidateVisibilityStep` rejects
|
|
50
|
+
* platform without an IdP); the gate here only prevents offering an option
|
|
51
|
+
* that is guaranteed to fail.
|
|
35
52
|
*/
|
|
36
|
-
export function ResourceVisibilityControl({ kind, resourceId, visibility, onChanged, className, }) {
|
|
53
|
+
export function ResourceVisibilityControl({ kind, resourceId, visibility, org, onChanged, className, }) {
|
|
37
54
|
const { updateVisibility, isPending } = useUpdateVisibility(kind, resourceId);
|
|
55
|
+
const deploymentMode = useDeploymentMode();
|
|
56
|
+
const isInstance = INSTANCE_KINDS.has(kind);
|
|
57
|
+
// The IdP lookup only matters for blueprints in cloud mode; passing null
|
|
58
|
+
// makes the hook a stable no-op everywhere else.
|
|
59
|
+
const idpLookupOrg = !isInstance && deploymentMode === "cloud" ? (org ?? null) : null;
|
|
60
|
+
const { ssoProvider } = useSsoProvider(idpLookupOrg);
|
|
61
|
+
const options = isInstance
|
|
62
|
+
? INSTANCE_VISIBILITY_LEVELS
|
|
63
|
+
: blueprintVisibilityLevels({
|
|
64
|
+
deploymentMode,
|
|
65
|
+
hasIdentityProvider: ssoProvider !== null,
|
|
66
|
+
});
|
|
38
67
|
const handleChange = useCallback(async (next) => {
|
|
39
68
|
try {
|
|
40
69
|
await updateVisibility(next);
|
|
@@ -42,11 +71,11 @@ export function ResourceVisibilityControl({ kind, resourceId, visibility, onChan
|
|
|
42
71
|
}
|
|
43
72
|
catch {
|
|
44
73
|
// The RPC error is captured in useUpdateVisibility's `error` state;
|
|
45
|
-
// swallow here so the
|
|
74
|
+
// swallow here so the selector's promise settles without an unhandled
|
|
46
75
|
// rejection. Surfacing a toast is the host app's concern.
|
|
47
76
|
}
|
|
48
77
|
}, [updateVisibility, onChanged]);
|
|
49
78
|
const badge = _jsx(VisibilityBadge, { visibility: visibility, className: className });
|
|
50
|
-
return (_jsx(PermissionGate, { resource: { kind: FGA_KIND[kind], id: resourceId }, relation: "can_edit", fallback: badge, loading: badge, children: _jsx(
|
|
79
|
+
return (_jsx(PermissionGate, { resource: { kind: FGA_KIND[kind], id: resourceId }, relation: "can_edit", fallback: badge, loading: badge, children: _jsx(VisibilitySelector, { visibility: visibility, options: options, onVisibilityChange: handleChange, isPending: isPending, ariaLabel: isInstance ? "Instance visibility" : "Resource visibility", className: className }) }));
|
|
51
80
|
}
|
|
52
81
|
//# sourceMappingURL=ResourceVisibilityControl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResourceVisibilityControl.js","sourceRoot":"","sources":["../../src/library/ResourceVisibilityControl.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"ResourceVisibilityControl.js","sourceRoot":"","sources":["../../src/library/ResourceVisibilityControl.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EACL,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,GAEpB,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,QAAQ,GAA2C;IACvD,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,OAAO;IACd,SAAS,EAAE,YAAY;IACvB,aAAa,EAAE,gBAAgB;IAC/B,gBAAgB,EAAE,mBAAmB;CACtC,CAAC;AAEF,MAAM,cAAc,GAAwC,IAAI,GAAG,CAAC;IAClE,eAAe;IACf,kBAAkB;CACnB,CAAC,CAAC;AA0BH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,yBAAyB,CAAC,EACxC,IAAI,EACJ,UAAU,EACV,UAAU,EACV,GAAG,EACH,SAAS,EACT,SAAS,GACsB;IAC/B,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,mBAAmB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9E,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAC;IAE3C,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5C,yEAAyE;IACzE,iDAAiD;IACjD,MAAM,YAAY,GAChB,CAAC,UAAU,IAAI,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnE,MAAM,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IAErD,MAAM,OAAO,GAAG,UAAU;QACxB,CAAC,CAAC,0BAA0B;QAC5B,CAAC,CAAC,yBAAyB,CAAC;YACxB,cAAc;YACd,mBAAmB,EAAE,WAAW,KAAK,IAAI;SAC1C,CAAC,CAAC;IAEP,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,IAA2B,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC7B,SAAS,EAAE,EAAE,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;YACpE,sEAAsE;YACtE,0DAA0D;QAC5D,CAAC;IACH,CAAC,EACD,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAC9B,CAAC;IAEF,MAAM,KAAK,GAAG,KAAC,eAAe,IAAC,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,GAAI,CAAC;IAEhF,OAAO,CACL,KAAC,cAAc,IACb,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,EAClD,QAAQ,EAAC,UAAU,EACnB,QAAQ,EAAE,KAAK,EACf,OAAO,EAAE,KAAK,YAEd,KAAC,kBAAkB,IACjB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,YAAY,EAChC,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,qBAAqB,EACrE,SAAS,EAAE,SAAS,GACpB,GACa,CAClB,CAAC;AACJ,CAAC"}
|
package/library/ScopeToggle.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface ScopeToggleProps {
|
|
|
22
22
|
*
|
|
23
23
|
* Renders as a WAI-ARIA Radio Group with roving tabindex and
|
|
24
24
|
* arrow-key navigation. Follows the same visual pattern as
|
|
25
|
-
* {@link
|
|
25
|
+
* {@link VisibilitySelector}.
|
|
26
26
|
*
|
|
27
27
|
* The component is controlled — the consumer owns the `value` state
|
|
28
28
|
* and handles persistence (e.g., localStorage).
|
package/library/ScopeToggle.js
CHANGED
|
@@ -22,7 +22,7 @@ const OPTIONS = [
|
|
|
22
22
|
*
|
|
23
23
|
* Renders as a WAI-ARIA Radio Group with roving tabindex and
|
|
24
24
|
* arrow-key navigation. Follows the same visual pattern as
|
|
25
|
-
* {@link
|
|
25
|
+
* {@link VisibilitySelector}.
|
|
26
26
|
*
|
|
27
27
|
* The component is controlled — the consumer owns the `value` state
|
|
28
28
|
* and handles persistence (e.g., localStorage).
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { VisibilityLevelOption } from "./visibilityLevels";
|
|
2
|
+
/** Color treatment key shared by every visibility surface. */
|
|
3
|
+
export type VisibilityTone = VisibilityLevelOption["tone"];
|
|
4
|
+
/** Base classes for the visibility chip (badge + selector trigger). */
|
|
5
|
+
export declare const VISIBILITY_CHIP_CLASS = "inline-flex shrink-0 items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground";
|
|
6
|
+
/** Props for {@link VisibilityOptionRow}. */
|
|
7
|
+
export interface VisibilityOptionRowProps {
|
|
8
|
+
/** The level this row represents. */
|
|
9
|
+
readonly option: VisibilityLevelOption;
|
|
10
|
+
/** Whether this row is the resource's current visibility. */
|
|
11
|
+
readonly isSelected: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* ARIA role for the row. `"option"` inside the popover listbox,
|
|
14
|
+
* `"radio"` inside the create-mode radiogroup — the matching selection
|
|
15
|
+
* attribute (`aria-selected` / `aria-checked`) is applied automatically.
|
|
16
|
+
*/
|
|
17
|
+
readonly role: "option" | "radio";
|
|
18
|
+
/** Visually highlighted by keyboard/pointer navigation (popover only). */
|
|
19
|
+
readonly isHighlighted?: boolean;
|
|
20
|
+
/** Disables interaction (e.g. while a change is in flight). */
|
|
21
|
+
readonly disabled?: boolean;
|
|
22
|
+
/** Roving-tabindex value; the focused row is `0`, the rest `-1`. */
|
|
23
|
+
readonly tabIndex?: number;
|
|
24
|
+
/** Fires when the row is activated (click / Enter / Space). */
|
|
25
|
+
readonly onSelect: () => void;
|
|
26
|
+
/** Pointer hover, used to sync the keyboard highlight. */
|
|
27
|
+
readonly onMouseEnter?: () => void;
|
|
28
|
+
/** Keydown handler owned by the parent for roving focus. */
|
|
29
|
+
readonly onKeyDown?: (e: React.KeyboardEvent<HTMLButtonElement>) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A single visibility level rendered as a left-aligned row: tone icon,
|
|
33
|
+
* label, one-line description, and a check when current. Shared by the
|
|
34
|
+
* {@link VisibilitySelector} popover and its create-mode inline list so
|
|
35
|
+
* option presentation has exactly one source.
|
|
36
|
+
*/
|
|
37
|
+
export declare const VisibilityOptionRow: import("react").ForwardRefExoticComponent<VisibilityOptionRowProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
38
|
+
/** Selected-segment / active-tone treatment (also used by the inline confirm). */
|
|
39
|
+
export declare const SELECTED_STYLES: Record<VisibilityTone, string>;
|
|
40
|
+
/** Inline-confirm (escalation prompt) treatment, keyed by tone. */
|
|
41
|
+
export declare const PROMPT_STYLES: Record<VisibilityTone, {
|
|
42
|
+
container: string;
|
|
43
|
+
text: string;
|
|
44
|
+
confirm: string;
|
|
45
|
+
cancel: string;
|
|
46
|
+
}>;
|
|
47
|
+
/** Icon for a visibility tone; shared by the row, badge, and trigger. */
|
|
48
|
+
export declare function VisibilityIcon({ tone, className, }: {
|
|
49
|
+
readonly tone: VisibilityTone;
|
|
50
|
+
readonly className?: string;
|
|
51
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
52
|
+
//# sourceMappingURL=VisibilityOptionRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VisibilityOptionRow.d.ts","sourceRoot":"","sources":["../../src/library/VisibilityOptionRow.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,8DAA8D;AAC9D,MAAM,MAAM,cAAc,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAO3D,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,4HACyF,CAAC;AAQ5H,6CAA6C;AAC7C,MAAM,WAAW,wBAAwB;IACvC,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAClC,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,wHAuD9B,CAAC;AAMH,kFAAkF;AAClF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAQ1D,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,aAAa,EAAE,MAAM,CAChC,cAAc,EACd;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAuCrE,CAAC;AAMF,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,SAAS,GACV,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,2CAWA"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
import { cn } from "@stigmer/theme";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Chip — the read-only badge and the editable trigger share this base so the
|
|
7
|
+
// two states are visually identical apart from the trigger's caret affordance.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
/** Base classes for the visibility chip (badge + selector trigger). */
|
|
10
|
+
export const VISIBILITY_CHIP_CLASS = "inline-flex shrink-0 items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground";
|
|
11
|
+
/**
|
|
12
|
+
* A single visibility level rendered as a left-aligned row: tone icon,
|
|
13
|
+
* label, one-line description, and a check when current. Shared by the
|
|
14
|
+
* {@link VisibilitySelector} popover and its create-mode inline list so
|
|
15
|
+
* option presentation has exactly one source.
|
|
16
|
+
*/
|
|
17
|
+
export const VisibilityOptionRow = forwardRef(function VisibilityOptionRow({ option, isSelected, role, isHighlighted, disabled, tabIndex, onSelect, onMouseEnter, onKeyDown, }, ref) {
|
|
18
|
+
const selectionAttr = role === "radio"
|
|
19
|
+
? { "aria-checked": isSelected }
|
|
20
|
+
: { "aria-selected": isSelected };
|
|
21
|
+
return (_jsxs("button", { ref: ref, type: "button", role: role, ...selectionAttr, tabIndex: tabIndex, disabled: disabled, onClick: onSelect, onMouseEnter: onMouseEnter, onKeyDown: onKeyDown, className: cn("flex w-full items-start gap-2 rounded-md px-2.5 py-2 text-left transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50", isHighlighted ? "bg-accent text-foreground" : "hover:bg-accent-hover"), children: [_jsx(VisibilityIcon, { tone: option.tone, className: "mt-0.5 size-3.5 shrink-0 text-muted-foreground" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block text-xs font-medium text-foreground", children: option.label }), _jsx("span", { className: "block text-[0.65rem] leading-snug text-muted-foreground", children: option.description })] }), isSelected && _jsx(CheckIcon, { className: "mt-0.5 size-3.5 shrink-0 text-primary" })] }));
|
|
22
|
+
});
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Tone styling — one row per visibility tone, keyed by VisibilityLevelOption
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
/** Selected-segment / active-tone treatment (also used by the inline confirm). */
|
|
27
|
+
export const SELECTED_STYLES = {
|
|
28
|
+
private: "bg-amber-50 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300",
|
|
29
|
+
org: "bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300",
|
|
30
|
+
platform: "bg-violet-100 text-violet-800 dark:bg-violet-900/40 dark:text-violet-300",
|
|
31
|
+
public: "bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-300",
|
|
32
|
+
};
|
|
33
|
+
/** Inline-confirm (escalation prompt) treatment, keyed by tone. */
|
|
34
|
+
export const PROMPT_STYLES = {
|
|
35
|
+
// Private never escalates, but the row keeps the Record total.
|
|
36
|
+
private: {
|
|
37
|
+
container: "border-amber-200 bg-amber-50 dark:border-amber-800/50 dark:bg-amber-950/30",
|
|
38
|
+
text: "text-amber-800 dark:text-amber-200",
|
|
39
|
+
confirm: "bg-amber-600 hover:bg-amber-700 dark:bg-amber-600 dark:hover:bg-amber-500",
|
|
40
|
+
cancel: "text-amber-700 hover:text-amber-900 dark:text-amber-300 dark:hover:text-amber-100",
|
|
41
|
+
},
|
|
42
|
+
org: {
|
|
43
|
+
container: "border-blue-200 bg-blue-50 dark:border-blue-800/50 dark:bg-blue-950/30",
|
|
44
|
+
text: "text-blue-800 dark:text-blue-200",
|
|
45
|
+
confirm: "bg-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-500",
|
|
46
|
+
cancel: "text-blue-700 hover:text-blue-900 dark:text-blue-300 dark:hover:text-blue-100",
|
|
47
|
+
},
|
|
48
|
+
platform: {
|
|
49
|
+
container: "border-violet-200 bg-violet-50 dark:border-violet-800/50 dark:bg-violet-950/30",
|
|
50
|
+
text: "text-violet-800 dark:text-violet-200",
|
|
51
|
+
confirm: "bg-violet-600 hover:bg-violet-700 dark:bg-violet-600 dark:hover:bg-violet-500",
|
|
52
|
+
cancel: "text-violet-700 hover:text-violet-900 dark:text-violet-300 dark:hover:text-violet-100",
|
|
53
|
+
},
|
|
54
|
+
public: {
|
|
55
|
+
container: "border-emerald-200 bg-emerald-50 dark:border-emerald-800/50 dark:bg-emerald-950/30",
|
|
56
|
+
text: "text-emerald-800 dark:text-emerald-200",
|
|
57
|
+
confirm: "bg-emerald-600 hover:bg-emerald-700 dark:bg-emerald-600 dark:hover:bg-emerald-500",
|
|
58
|
+
cancel: "text-emerald-700 hover:text-emerald-900 dark:text-emerald-300 dark:hover:text-emerald-100",
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Icons — inline SVGs following the SDK pattern (no icon library dependency)
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
/** Icon for a visibility tone; shared by the row, badge, and trigger. */
|
|
65
|
+
export function VisibilityIcon({ tone, className, }) {
|
|
66
|
+
switch (tone) {
|
|
67
|
+
case "org":
|
|
68
|
+
return _jsx(UsersIcon, { className: className });
|
|
69
|
+
case "platform":
|
|
70
|
+
return _jsx(BuildingsIcon, { className: className });
|
|
71
|
+
case "public":
|
|
72
|
+
return _jsx(GlobeIcon, { className: className });
|
|
73
|
+
default:
|
|
74
|
+
return _jsx(LockIcon, { className: className });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function LockIcon({ className }) {
|
|
78
|
+
return (_jsxs("svg", { className: className, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("rect", { x: "3.5", y: "7", width: "9", height: "7", rx: "1.5" }), _jsx("path", { d: "M5.5 7V5a2.5 2.5 0 0 1 5 0v2" })] }));
|
|
79
|
+
}
|
|
80
|
+
function UsersIcon({ className }) {
|
|
81
|
+
return (_jsxs("svg", { className: className, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "6", cy: "5", r: "2.5" }), _jsx("path", { d: "M2 13c0-2.21 1.79-4 4-4s4 1.79 4 4" }), _jsx("circle", { cx: "11.5", cy: "5.5", r: "2" }), _jsx("path", { d: "M14 13c0-1.66-1.12-3-2.5-3-.5 0-1 .14-1.4.4" })] }));
|
|
82
|
+
}
|
|
83
|
+
function BuildingsIcon({ className }) {
|
|
84
|
+
return (_jsxs("svg", { className: className, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M2 14V4.5L6.5 2v12" }), _jsx("path", { d: "M6.5 6.5 14 8.5V14" }), _jsx("path", { d: "M2 14h12" }), _jsx("path", { d: "M4.25 6h.01M4.25 8.5h.01M4.25 11h.01M10.5 10.5h.01M10.5 12.5h.01" })] }));
|
|
85
|
+
}
|
|
86
|
+
function GlobeIcon({ className }) {
|
|
87
|
+
return (_jsxs("svg", { className: className, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "8", cy: "8", r: "6" }), _jsx("path", { d: "M2 8h12" }), _jsx("path", { d: "M8 2c1.66 1.46 2.6 3.63 2.6 6s-.94 4.54-2.6 6c-1.66-1.46-2.6-3.63-2.6-6s.94-4.54 2.6-6Z" })] }));
|
|
88
|
+
}
|
|
89
|
+
function CheckIcon({ className }) {
|
|
90
|
+
return (_jsx("svg", { className: className, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M3 8.5 6.5 12 13 4.5" }) }));
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=VisibilityOptionRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VisibilityOptionRow.js","sourceRoot":"","sources":["../../src/library/VisibilityOptionRow.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAMpC,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,8EAA8E;AAE9E,uEAAuE;AACvE,MAAM,CAAC,MAAM,qBAAqB,GAChC,yHAAyH,CAAC;AAkC5H;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAG3C,SAAS,mBAAmB,CAC5B,EACE,MAAM,EACN,UAAU,EACV,IAAI,EACJ,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,SAAS,GACV,EACD,GAAG;IAEH,MAAM,aAAa,GACjB,IAAI,KAAK,OAAO;QACd,CAAC,CAAC,EAAE,cAAc,EAAE,UAAU,EAAE;QAChC,CAAC,CAAC,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC;IAEtC,OAAO,CACL,kBACE,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,QAAQ,EACb,IAAI,EAAE,IAAI,KACN,aAAa,EACjB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,QAAQ,EACjB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,EAAE,CACX,kFAAkF,EAClF,yEAAyE,EACzE,kDAAkD,EAClD,aAAa,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,uBAAuB,CACtE,aAED,KAAC,cAAc,IACb,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,SAAS,EAAC,gDAAgD,GAC1D,EACF,gBAAM,SAAS,EAAC,gBAAgB,aAC9B,eAAM,SAAS,EAAC,2CAA2C,YACxD,MAAM,CAAC,KAAK,GACR,EACP,eAAM,SAAS,EAAC,yDAAyD,YACtE,MAAM,CAAC,WAAW,GACd,IACF,EACN,UAAU,IAAI,KAAC,SAAS,IAAC,SAAS,EAAC,uCAAuC,GAAG,IACvE,CACV,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAE9E,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAmC;IAC7D,OAAO,EACL,qEAAqE;IACvE,GAAG,EAAE,kEAAkE;IACvE,QAAQ,EACN,0EAA0E;IAC5E,MAAM,EACJ,8EAA8E;CACjF,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,MAAM,aAAa,GAGtB;IACF,+DAA+D;IAC/D,OAAO,EAAE;QACP,SAAS,EACP,4EAA4E;QAC9E,IAAI,EAAE,oCAAoC;QAC1C,OAAO,EACL,2EAA2E;QAC7E,MAAM,EACJ,mFAAmF;KACtF;IACD,GAAG,EAAE;QACH,SAAS,EACP,wEAAwE;QAC1E,IAAI,EAAE,kCAAkC;QACxC,OAAO,EACL,uEAAuE;QACzE,MAAM,EACJ,+EAA+E;KAClF;IACD,QAAQ,EAAE;QACR,SAAS,EACP,gFAAgF;QAClF,IAAI,EAAE,sCAAsC;QAC5C,OAAO,EACL,+EAA+E;QACjF,MAAM,EACJ,uFAAuF;KAC1F;IACD,MAAM,EAAE;QACN,SAAS,EACP,oFAAoF;QACtF,IAAI,EAAE,wCAAwC;QAC9C,OAAO,EACL,mFAAmF;QACrF,MAAM,EACJ,2FAA2F;KAC9F;CACF,CAAC;AAEF,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAE9E,yEAAyE;AACzE,MAAM,UAAU,cAAc,CAAC,EAC7B,IAAI,EACJ,SAAS,GAIV;IACC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,KAAK;YACR,OAAO,KAAC,SAAS,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QAC7C,KAAK,UAAU;YACb,OAAO,KAAC,aAAa,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QACjD,KAAK,QAAQ;YACX,OAAO,KAAC,SAAS,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;QAC7C;YACE,OAAO,KAAC,QAAQ,IAAC,SAAS,EAAE,SAAS,GAAI,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,EAAE,SAAS,EAAmC;IAC9D,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,EAAE,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,KAAK,EAAC,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,iBAAa,MAAM,aAChK,eAAM,CAAC,EAAC,KAAK,EAAC,CAAC,EAAC,GAAG,EAAC,KAAK,EAAC,GAAG,EAAC,MAAM,EAAC,GAAG,EAAC,EAAE,EAAC,KAAK,GAAG,EACpD,eAAM,CAAC,EAAC,8BAA8B,GAAG,IACrC,CACP,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,SAAS,EAAmC;IAC/D,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,EAAE,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,KAAK,EAAC,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,iBAAa,MAAM,aAChK,iBAAQ,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,CAAC,EAAC,KAAK,GAAG,EAChC,eAAM,CAAC,EAAC,oCAAoC,GAAG,EAC/C,iBAAQ,EAAE,EAAC,MAAM,EAAC,EAAE,EAAC,KAAK,EAAC,CAAC,EAAC,GAAG,GAAG,EACnC,eAAM,CAAC,EAAC,6CAA6C,GAAG,IACpD,CACP,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,EAAE,SAAS,EAAmC;IACnE,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,EAAE,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,KAAK,EAAC,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,iBAAa,MAAM,aAChK,eAAM,CAAC,EAAC,oBAAoB,GAAG,EAC/B,eAAM,CAAC,EAAC,oBAAoB,GAAG,EAC/B,eAAM,CAAC,EAAC,UAAU,GAAG,EACrB,eAAM,CAAC,EAAC,kEAAkE,GAAG,IACzE,CACP,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,SAAS,EAAmC;IAC/D,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,EAAE,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,KAAK,EAAC,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,iBAAa,MAAM,aAChK,iBAAQ,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,CAAC,EAAC,GAAG,GAAG,EAC9B,eAAM,CAAC,EAAC,SAAS,GAAG,EACpB,eAAM,CAAC,EAAC,yFAAyF,GAAG,IAChG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,SAAS,EAAmC;IAC/D,OAAO,CACL,cAAK,SAAS,EAAE,SAAS,EAAE,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,GAAG,EAAC,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,iBAAa,MAAM,YAC9J,eAAM,CAAC,EAAC,sBAAsB,GAAG,GAC7B,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
2
|
+
import { type VisibilityLevelOption } from "./visibilityLevels";
|
|
3
|
+
/** How the selector presents itself and how it confirms escalations. */
|
|
4
|
+
export type VisibilitySelectorMode = "manage" | "create";
|
|
5
|
+
/** Props for {@link VisibilitySelector}. */
|
|
6
|
+
export interface VisibilitySelectorProps {
|
|
7
|
+
/** Current visibility of the resource. */
|
|
8
|
+
readonly visibility: ApiResourceVisibility;
|
|
9
|
+
/**
|
|
10
|
+
* Levels to offer, in escalation order (least to most exposed). Selecting
|
|
11
|
+
* a level later in the list than the current one is an escalation and is
|
|
12
|
+
* confirmed by severity (see {@link mode}); de-escalation applies
|
|
13
|
+
* immediately (revoking access is always safe).
|
|
14
|
+
*/
|
|
15
|
+
readonly options: readonly VisibilityLevelOption[];
|
|
16
|
+
/** Called when the user selects (and, for escalations, confirms) a level. */
|
|
17
|
+
readonly onVisibilityChange: (v: ApiResourceVisibility) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Presentation + confirmation mode.
|
|
20
|
+
*
|
|
21
|
+
* - `"manage"` (default) — a compact current-state chip opens a popover
|
|
22
|
+
* ladder of levels. Escalations are confirmed by severity: a light
|
|
23
|
+
* inline prompt for levels carrying {@link VisibilityLevelOption.confirmPrompt}
|
|
24
|
+
* (e.g. Organization), and a blocking modal for levels carrying
|
|
25
|
+
* {@link VisibilityLevelOption.confirmDialog} (Platform, Public). This is
|
|
26
|
+
* the live-resource case.
|
|
27
|
+
* - `"create"` — an inline radio list that applies immediately, with no
|
|
28
|
+
* escalation confirmation. Used to pick an initial value while creating
|
|
29
|
+
* a resource (typically inside a native `<dialog>`, where a portaled
|
|
30
|
+
* popover would render beneath the modal's top layer).
|
|
31
|
+
*
|
|
32
|
+
* @default "manage"
|
|
33
|
+
*/
|
|
34
|
+
readonly mode?: VisibilitySelectorMode;
|
|
35
|
+
/** Shows a spinner/disabled state while the RPC is in flight. */
|
|
36
|
+
readonly isPending?: boolean;
|
|
37
|
+
/** Disables all interaction (e.g., when the user lacks can_edit). */
|
|
38
|
+
readonly disabled?: boolean;
|
|
39
|
+
/** Accessible name for the control. Defaults to "Resource visibility". */
|
|
40
|
+
readonly ariaLabel?: string;
|
|
41
|
+
/** Additional CSS classes applied to the root element. */
|
|
42
|
+
readonly className?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The single control for resource visibility across blueprints AND
|
|
46
|
+
* instances. Offered levels are pure data ({@link VisibilityLevelOption});
|
|
47
|
+
* per-kind level sets live in `visibilityLevels.ts`, so this component
|
|
48
|
+
* carries no kind-specific logic.
|
|
49
|
+
*
|
|
50
|
+
* In `"manage"` mode it renders a current-state chip (icon + label + caret)
|
|
51
|
+
* that opens a popover listing each offered level with its own description —
|
|
52
|
+
* scaling cleanly to four levels without the layout shift of a segmented
|
|
53
|
+
* control, and explaining every choice at a glance (Recognition over
|
|
54
|
+
* Recall). Escalation is confirmed in proportion to how far access expands:
|
|
55
|
+
* de-escalation applies instantly, an Organization escalation shows a light
|
|
56
|
+
* inline prompt, and Platform/Public escalations open a blocking
|
|
57
|
+
* {@link ConfirmDialog} that names the exact audience. Confirmation is owned
|
|
58
|
+
* here so every consumer — blueprint detail, instance detail, and any
|
|
59
|
+
* standalone embed — behaves identically.
|
|
60
|
+
*
|
|
61
|
+
* In `"create"` mode it renders an inline radio list that applies
|
|
62
|
+
* immediately (initial value selection has no escalation semantics).
|
|
63
|
+
*
|
|
64
|
+
* If the current visibility is not among the offered options (e.g. a
|
|
65
|
+
* platform-shared blueprint whose org no longer operates an
|
|
66
|
+
* IdentityProvider), its canonical option is rendered in place so the
|
|
67
|
+
* state stays legible and the user can still move to an offered level.
|
|
68
|
+
*
|
|
69
|
+
* All visual properties flow through `--stgm-*` design tokens; portaled
|
|
70
|
+
* content targets the {@link useStigmerPortalContainer} so it inherits the
|
|
71
|
+
* active theme.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```tsx
|
|
75
|
+
* <VisibilitySelector
|
|
76
|
+
* visibility={agent.metadata.visibility}
|
|
77
|
+
* options={blueprintVisibilityLevels({ deploymentMode, hasIdentityProvider })}
|
|
78
|
+
* onVisibilityChange={updateVisibility}
|
|
79
|
+
* isPending={isPending}
|
|
80
|
+
* />
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function VisibilitySelector({ visibility, options, onVisibilityChange, mode, isPending, disabled, ariaLabel, className, }: VisibilitySelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
84
|
+
/**
|
|
85
|
+
* Read-only visibility indicator with a matching icon, covering all four
|
|
86
|
+
* levels (Private / Organization / Platform / Public).
|
|
87
|
+
*
|
|
88
|
+
* Rendered wherever the interactive {@link VisibilitySelector} is not
|
|
89
|
+
* available — for viewers who lack `can_edit`, and while a permission check
|
|
90
|
+
* is in flight — so a resource's visibility is always legible rather than
|
|
91
|
+
* silently blank. Shares the chip styling with the selector trigger so the
|
|
92
|
+
* read-only and editable states are visually consistent.
|
|
93
|
+
*/
|
|
94
|
+
export declare function VisibilityBadge({ visibility, className, }: {
|
|
95
|
+
readonly visibility: ApiResourceVisibility;
|
|
96
|
+
readonly className?: string;
|
|
97
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
98
|
+
//# sourceMappingURL=VisibilitySelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VisibilitySelector.d.ts","sourceRoot":"","sources":["../../src/library/VisibilitySelector.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wDAAwD,CAAC;AAU/F,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAE5B,wEAAwE;AACxE,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEzD,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,6EAA6E;IAC7E,QAAQ,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAChE;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,sBAAsB,CAAC;IACvC,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,UAAU,EACV,OAAO,EACP,kBAAkB,EAClB,IAAe,EACf,SAAiB,EACjB,QAAgB,EAChB,SAAiC,EACjC,SAAS,GACV,EAAE,uBAAuB,2CAyRzB;AAmBD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,SAAS,GACV,EAAE;IACD,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,2CAQA"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { Popover } from "@base-ui/react/popover";
|
|
5
|
+
import { cn } from "@stigmer/theme";
|
|
6
|
+
import { useStigmerPortalContainer } from "../portal-container";
|
|
7
|
+
import { ConfirmDialog } from "../resource-detail/ConfirmDialog";
|
|
8
|
+
import { useConfirmAction } from "../resource-detail/useConfirmAction";
|
|
9
|
+
import { PROMPT_STYLES, VISIBILITY_CHIP_CLASS, VisibilityIcon, VisibilityOptionRow, } from "./VisibilityOptionRow";
|
|
10
|
+
import { visibilityOption, } from "./visibilityLevels";
|
|
11
|
+
/**
|
|
12
|
+
* The single control for resource visibility across blueprints AND
|
|
13
|
+
* instances. Offered levels are pure data ({@link VisibilityLevelOption});
|
|
14
|
+
* per-kind level sets live in `visibilityLevels.ts`, so this component
|
|
15
|
+
* carries no kind-specific logic.
|
|
16
|
+
*
|
|
17
|
+
* In `"manage"` mode it renders a current-state chip (icon + label + caret)
|
|
18
|
+
* that opens a popover listing each offered level with its own description —
|
|
19
|
+
* scaling cleanly to four levels without the layout shift of a segmented
|
|
20
|
+
* control, and explaining every choice at a glance (Recognition over
|
|
21
|
+
* Recall). Escalation is confirmed in proportion to how far access expands:
|
|
22
|
+
* de-escalation applies instantly, an Organization escalation shows a light
|
|
23
|
+
* inline prompt, and Platform/Public escalations open a blocking
|
|
24
|
+
* {@link ConfirmDialog} that names the exact audience. Confirmation is owned
|
|
25
|
+
* here so every consumer — blueprint detail, instance detail, and any
|
|
26
|
+
* standalone embed — behaves identically.
|
|
27
|
+
*
|
|
28
|
+
* In `"create"` mode it renders an inline radio list that applies
|
|
29
|
+
* immediately (initial value selection has no escalation semantics).
|
|
30
|
+
*
|
|
31
|
+
* If the current visibility is not among the offered options (e.g. a
|
|
32
|
+
* platform-shared blueprint whose org no longer operates an
|
|
33
|
+
* IdentityProvider), its canonical option is rendered in place so the
|
|
34
|
+
* state stays legible and the user can still move to an offered level.
|
|
35
|
+
*
|
|
36
|
+
* All visual properties flow through `--stgm-*` design tokens; portaled
|
|
37
|
+
* content targets the {@link useStigmerPortalContainer} so it inherits the
|
|
38
|
+
* active theme.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <VisibilitySelector
|
|
43
|
+
* visibility={agent.metadata.visibility}
|
|
44
|
+
* options={blueprintVisibilityLevels({ deploymentMode, hasIdentityProvider })}
|
|
45
|
+
* onVisibilityChange={updateVisibility}
|
|
46
|
+
* isPending={isPending}
|
|
47
|
+
* />
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function VisibilitySelector({ visibility, options, onVisibilityChange, mode = "manage", isPending = false, disabled = false, ariaLabel = "Resource visibility", className, }) {
|
|
51
|
+
const portalContainer = useStigmerPortalContainer();
|
|
52
|
+
const { confirmState, confirm, handleConfirm, handleCancel } = useConfirmAction();
|
|
53
|
+
const [open, setOpen] = useState(false);
|
|
54
|
+
// The Organization-style escalation awaiting its light inline confirm.
|
|
55
|
+
const [pendingInline, setPendingInline] = useState(null);
|
|
56
|
+
const [highlightIdx, setHighlightIdx] = useState(-1);
|
|
57
|
+
const optionRefs = useRef([]);
|
|
58
|
+
const effectivelyDisabled = disabled || isPending;
|
|
59
|
+
// Keep the current state legible even when it is not offerable in the
|
|
60
|
+
// current context: render its canonical option as an extra row.
|
|
61
|
+
const effectiveOptions = useMemo(() => {
|
|
62
|
+
if (options.some((o) => o.value === visibility))
|
|
63
|
+
return options;
|
|
64
|
+
return [...options, visibilityOption(visibility)];
|
|
65
|
+
}, [options, visibility]);
|
|
66
|
+
const isEscalation = useCallback((target) => {
|
|
67
|
+
const values = effectiveOptions.map((o) => o.value);
|
|
68
|
+
return values.indexOf(target) > values.indexOf(visibility);
|
|
69
|
+
}, [effectiveOptions, visibility]);
|
|
70
|
+
const apply = useCallback((value) => {
|
|
71
|
+
setOpen(false);
|
|
72
|
+
setPendingInline(null);
|
|
73
|
+
onVisibilityChange(value);
|
|
74
|
+
}, [onVisibilityChange]);
|
|
75
|
+
const handleSelect = useCallback((option) => {
|
|
76
|
+
const value = option.value;
|
|
77
|
+
if (value === visibility) {
|
|
78
|
+
setPendingInline(null);
|
|
79
|
+
setOpen(false);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// De-escalation (and create mode) never confirm — narrowing access is
|
|
83
|
+
// always safe, and an initial pick has no escalation semantics.
|
|
84
|
+
if (mode === "create" || !isEscalation(value)) {
|
|
85
|
+
apply(value);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (option.confirmDialog) {
|
|
89
|
+
setOpen(false);
|
|
90
|
+
setPendingInline(null);
|
|
91
|
+
void confirm({
|
|
92
|
+
title: option.confirmDialog.title,
|
|
93
|
+
description: option.confirmDialog.description,
|
|
94
|
+
confirmLabel: `Make ${option.label}`,
|
|
95
|
+
// Exposure is reversible, so this is a primary (not destructive)
|
|
96
|
+
// confirmation; the audience-naming copy carries the caution.
|
|
97
|
+
variant: "default",
|
|
98
|
+
}).then((ok) => {
|
|
99
|
+
if (ok)
|
|
100
|
+
onVisibilityChange(value);
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (option.confirmPrompt) {
|
|
105
|
+
setPendingInline(value);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
apply(value);
|
|
109
|
+
}, [visibility, mode, isEscalation, apply, confirm, onVisibilityChange]);
|
|
110
|
+
const moveFocus = useCallback((from, delta) => {
|
|
111
|
+
const count = effectiveOptions.length;
|
|
112
|
+
const next = (from + delta + count) % count;
|
|
113
|
+
setHighlightIdx(next);
|
|
114
|
+
optionRefs.current[next]?.focus();
|
|
115
|
+
}, [effectiveOptions.length]);
|
|
116
|
+
const handleRowKeyDown = useCallback((e, index) => {
|
|
117
|
+
switch (e.key) {
|
|
118
|
+
case "ArrowDown":
|
|
119
|
+
case "ArrowRight":
|
|
120
|
+
e.preventDefault();
|
|
121
|
+
moveFocus(index, 1);
|
|
122
|
+
break;
|
|
123
|
+
case "ArrowUp":
|
|
124
|
+
case "ArrowLeft":
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
moveFocus(index, -1);
|
|
127
|
+
break;
|
|
128
|
+
case "Home":
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
setHighlightIdx(0);
|
|
131
|
+
optionRefs.current[0]?.focus();
|
|
132
|
+
break;
|
|
133
|
+
case "End": {
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
const last = effectiveOptions.length - 1;
|
|
136
|
+
setHighlightIdx(last);
|
|
137
|
+
optionRefs.current[last]?.focus();
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}, [moveFocus, effectiveOptions.length]);
|
|
142
|
+
// On open, focus the current level so keyboard users land on a sensible row.
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (!open) {
|
|
145
|
+
setPendingInline(null);
|
|
146
|
+
setHighlightIdx(-1);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const current = effectiveOptions.findIndex((o) => o.value === visibility);
|
|
150
|
+
const start = current >= 0 ? current : 0;
|
|
151
|
+
setHighlightIdx(start);
|
|
152
|
+
const raf = requestAnimationFrame(() => optionRefs.current[start]?.focus());
|
|
153
|
+
return () => cancelAnimationFrame(raf);
|
|
154
|
+
}, [open, effectiveOptions, visibility]);
|
|
155
|
+
const dialog = (_jsx(ConfirmDialog, { state: confirmState, onConfirm: handleConfirm, onCancel: handleCancel }));
|
|
156
|
+
const renderRows = (role) => effectiveOptions.map((option, index) => (_jsx(VisibilityOptionRow, { ref: (el) => {
|
|
157
|
+
optionRefs.current[index] = el;
|
|
158
|
+
}, option: option, role: role, isSelected: visibility === option.value, isHighlighted: role === "option" && highlightIdx === index, tabIndex: role === "radio"
|
|
159
|
+
? visibility === option.value
|
|
160
|
+
? 0
|
|
161
|
+
: -1
|
|
162
|
+
: highlightIdx === index
|
|
163
|
+
? 0
|
|
164
|
+
: -1, disabled: effectivelyDisabled, onSelect: () => handleSelect(option), onMouseEnter: role === "option" ? () => setHighlightIdx(index) : undefined, onKeyDown: (e) => handleRowKeyDown(e, index) }, option.value)));
|
|
165
|
+
// ---- Create mode: inline radio list, applies immediately ---------------
|
|
166
|
+
if (mode === "create") {
|
|
167
|
+
return (_jsx("div", { role: "radiogroup", "aria-label": ariaLabel, "aria-disabled": effectivelyDisabled || undefined, className: cn("flex flex-col gap-0.5 rounded-md border border-border p-1", effectivelyDisabled && "pointer-events-none opacity-50", className), children: renderRows("radio") }));
|
|
168
|
+
}
|
|
169
|
+
// ---- Manage mode: current-state chip + popover ladder ------------------
|
|
170
|
+
const current = visibilityOption(visibility);
|
|
171
|
+
const pendingOption = pendingInline !== null
|
|
172
|
+
? effectiveOptions.find((o) => o.value === pendingInline)
|
|
173
|
+
: undefined;
|
|
174
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Popover.Root, { open: open, onOpenChange: setOpen, children: [_jsxs(Popover.Trigger, { disabled: effectivelyDisabled, "aria-label": `${ariaLabel}: ${current.label}`, className: cn(VISIBILITY_CHIP_CLASS, "transition-colors hover:bg-accent-hover hover:text-foreground", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50", className), children: [isPending ? (_jsx("span", { className: "inline-block size-2.5 animate-spin rounded-full border-2 border-current border-t-transparent", "aria-hidden": "true" })) : (_jsx(VisibilityIcon, { tone: current.tone, className: "size-2.5" })), current.label, _jsx(CaretIcon, {})] }), _jsx(Popover.Portal, { container: portalContainer, children: _jsx(Popover.Positioner, { sideOffset: 4, align: "start", children: _jsxs(Popover.Popup, { role: "listbox", "aria-label": ariaLabel, className: cn("z-popover w-72 rounded-lg border border-border bg-popover p-1 shadow-md", "text-popover-foreground animate-in fade-in-0 zoom-in-95"), children: [renderRows("option"), pendingOption?.confirmPrompt && (_jsxs("div", { role: "alert", className: cn("mt-1 flex items-center gap-2 rounded-md border px-2.5 py-1.5", PROMPT_STYLES[pendingOption.tone].container), children: [_jsx("span", { className: cn("flex-1 text-[0.65rem] leading-snug", PROMPT_STYLES[pendingOption.tone].text), children: pendingOption.confirmPrompt }), _jsx("button", { type: "button", onClick: () => setPendingInline(null), className: cn("rounded px-2 py-0.5 text-[0.65rem] font-medium", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", PROMPT_STYLES[pendingOption.tone].cancel), children: "Cancel" }), _jsx("button", { type: "button", onClick: () => apply(pendingOption.value), className: cn("rounded px-2 py-0.5 text-[0.65rem] font-medium text-white", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", PROMPT_STYLES[pendingOption.tone].confirm), children: "Confirm" })] }))] }) }) })] }), dialog] }));
|
|
175
|
+
}
|
|
176
|
+
function CaretIcon() {
|
|
177
|
+
return (_jsx("svg", { className: "size-2.5 shrink-0 text-muted-foreground", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M3 4.5 6 7.5 9 4.5" }) }));
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Read-only visibility indicator with a matching icon, covering all four
|
|
181
|
+
* levels (Private / Organization / Platform / Public).
|
|
182
|
+
*
|
|
183
|
+
* Rendered wherever the interactive {@link VisibilitySelector} is not
|
|
184
|
+
* available — for viewers who lack `can_edit`, and while a permission check
|
|
185
|
+
* is in flight — so a resource's visibility is always legible rather than
|
|
186
|
+
* silently blank. Shares the chip styling with the selector trigger so the
|
|
187
|
+
* read-only and editable states are visually consistent.
|
|
188
|
+
*/
|
|
189
|
+
export function VisibilityBadge({ visibility, className, }) {
|
|
190
|
+
const option = visibilityOption(visibility);
|
|
191
|
+
return (_jsxs("span", { className: cn(VISIBILITY_CHIP_CLASS, className), children: [_jsx(VisibilityIcon, { tone: option.tone, className: "size-2.5" }), option.label] }));
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=VisibilitySelector.js.map
|