ionbase-ui 0.21.0 → 0.24.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/components/AgentStop.d.ts +58 -0
- package/dist/components/AgentStop.d.ts.map +1 -0
- package/dist/components/AgentStop.js +82 -0
- package/dist/components/AgentStop.js.map +1 -0
- package/dist/components/ApprovalGate.d.ts +72 -0
- package/dist/components/ApprovalGate.d.ts.map +1 -0
- package/dist/components/ApprovalGate.js +68 -0
- package/dist/components/ApprovalGate.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/figma-descriptions.json +147 -0
- package/dist/figma-map.json +2049 -0
- package/dist/meta/AgentStop.json +164 -0
- package/dist/meta/ApprovalGate.json +255 -0
- package/dist/meta/Avatar.json +2 -2
- package/dist/meta/AvatarGroup.json +2 -2
- package/dist/meta/PhoneInput.json +36 -36
- package/dist/meta/components.json +460 -41
- package/dist/meta/contrast.json +828 -14
- package/dist/meta/index.json +37 -5
- package/dist/meta/patterns/index.json +1 -1
- package/dist/styles/agent-stop.css +109 -0
- package/dist/styles/approval-gate.css +181 -0
- package/dist/styles/index.css +30 -0
- package/llms.txt +6 -2
- package/package.json +6 -3
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type AgentStopSize = 'sm' | 'md' | 'lg';
|
|
3
|
+
export interface AgentStopProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type' | 'children'> {
|
|
4
|
+
/** Called when the user asks the run to stop. */
|
|
5
|
+
onStop: () => void;
|
|
6
|
+
/**
|
|
7
|
+
* The request is in flight. The control stays visible and keeps its place;
|
|
8
|
+
* it does not disappear while the thing it cancels is still running.
|
|
9
|
+
*/
|
|
10
|
+
isStopping?: boolean;
|
|
11
|
+
/** Visible label. */
|
|
12
|
+
label?: string;
|
|
13
|
+
/** Visible label once `isStopping` is set. */
|
|
14
|
+
stoppingLabel?: string;
|
|
15
|
+
size?: AgentStopSize;
|
|
16
|
+
/**
|
|
17
|
+
* Bind Escape, at the document, to stop the run.
|
|
18
|
+
*
|
|
19
|
+
* Off by default and deliberately so: Escape already means "dismiss the
|
|
20
|
+
* thing in front of me" to every modal, popover and menu in this system, and
|
|
21
|
+
* a document-level handler would cancel a background run when the user meant
|
|
22
|
+
* to close a dialog. Turn it on only where the run IS the foreground task.
|
|
23
|
+
*/
|
|
24
|
+
stopOnEscape?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* AgentStop — the always-visible way to end a run.
|
|
28
|
+
*
|
|
29
|
+
* NOT OPTIONAL, AND NOT BEHIND A MENU. A user who cannot stop an agent is
|
|
30
|
+
* watching it, not supervising it. Human oversight of an automated process is
|
|
31
|
+
* a compliance surface in regulated contexts, not a UX preference, and the
|
|
32
|
+
* control that provides it has to be present and reachable at the moment it is
|
|
33
|
+
* wanted — not two clicks into an overflow menu.
|
|
34
|
+
*
|
|
35
|
+
* WHY IT IS NOT JUST `<Button variant="destructive">`
|
|
36
|
+
*
|
|
37
|
+
* Three things it owns that a Button does not:
|
|
38
|
+
*
|
|
39
|
+
* It keeps its place while stopping. A control that vanishes the instant it
|
|
40
|
+
* is pressed leaves the user unsure whether the press registered, and the
|
|
41
|
+
* run is usually still going. It stays, relabels, and disables — the layout
|
|
42
|
+
* does not move.
|
|
43
|
+
*
|
|
44
|
+
* It announces. The label change is only announced to a screen reader if the
|
|
45
|
+
* button happens to hold focus, which it usually does not when a run was
|
|
46
|
+
* started elsewhere. A polite live region says "Stopping" once.
|
|
47
|
+
*
|
|
48
|
+
* It is not destructive-red. Stopping is a normal, expected, reversible-in-
|
|
49
|
+
* spirit action — you can run it again. Colouring it like `delete` teaches
|
|
50
|
+
* hesitation about the one control that must never be hesitated over.
|
|
51
|
+
*
|
|
52
|
+
* WHAT IT DOES NOT DO. It does not stop anything. It reports intent; the
|
|
53
|
+
* caller aborts the request, closes the stream and settles the state. A stop
|
|
54
|
+
* button that resolves optimistically while tokens keep arriving is worse than
|
|
55
|
+
* none, because it lies about a guarantee the user is relying on.
|
|
56
|
+
*/
|
|
57
|
+
export declare const AgentStop: React.ForwardRefExoticComponent<AgentStopProps & React.RefAttributes<HTMLButtonElement>>;
|
|
58
|
+
//# sourceMappingURL=AgentStop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentStop.d.ts","sourceRoot":"","sources":["../../src/components/AgentStop.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAEvE,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/C,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAC7C,MAAM,GAAG,UAAU,CACpB;IACC,iDAAiD;IACjD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAiBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,SAAS,0FAiFrB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useEffect, useRef, useState } from 'react';
|
|
4
|
+
/** A square, not a glyph with meaning to learn. Universal stop. */
|
|
5
|
+
const StopGlyph = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("rect", { x: "6", y: "6", width: "12", height: "12", rx: "1.5", fill: "currentColor", stroke: "none" }) }));
|
|
6
|
+
/**
|
|
7
|
+
* AgentStop — the always-visible way to end a run.
|
|
8
|
+
*
|
|
9
|
+
* NOT OPTIONAL, AND NOT BEHIND A MENU. A user who cannot stop an agent is
|
|
10
|
+
* watching it, not supervising it. Human oversight of an automated process is
|
|
11
|
+
* a compliance surface in regulated contexts, not a UX preference, and the
|
|
12
|
+
* control that provides it has to be present and reachable at the moment it is
|
|
13
|
+
* wanted — not two clicks into an overflow menu.
|
|
14
|
+
*
|
|
15
|
+
* WHY IT IS NOT JUST `<Button variant="destructive">`
|
|
16
|
+
*
|
|
17
|
+
* Three things it owns that a Button does not:
|
|
18
|
+
*
|
|
19
|
+
* It keeps its place while stopping. A control that vanishes the instant it
|
|
20
|
+
* is pressed leaves the user unsure whether the press registered, and the
|
|
21
|
+
* run is usually still going. It stays, relabels, and disables — the layout
|
|
22
|
+
* does not move.
|
|
23
|
+
*
|
|
24
|
+
* It announces. The label change is only announced to a screen reader if the
|
|
25
|
+
* button happens to hold focus, which it usually does not when a run was
|
|
26
|
+
* started elsewhere. A polite live region says "Stopping" once.
|
|
27
|
+
*
|
|
28
|
+
* It is not destructive-red. Stopping is a normal, expected, reversible-in-
|
|
29
|
+
* spirit action — you can run it again. Colouring it like `delete` teaches
|
|
30
|
+
* hesitation about the one control that must never be hesitated over.
|
|
31
|
+
*
|
|
32
|
+
* WHAT IT DOES NOT DO. It does not stop anything. It reports intent; the
|
|
33
|
+
* caller aborts the request, closes the stream and settles the state. A stop
|
|
34
|
+
* button that resolves optimistically while tokens keep arriving is worse than
|
|
35
|
+
* none, because it lies about a guarantee the user is relying on.
|
|
36
|
+
*/
|
|
37
|
+
export const AgentStop = forwardRef(({ onStop, isStopping = false, label = 'Stop', stoppingLabel = 'Stopping…', size = 'md', stopOnEscape = false, className, ...rest }, ref) => {
|
|
38
|
+
/*
|
|
39
|
+
* Announce the transition, not the state. A live region that always holds
|
|
40
|
+
* "Stopping…" is re-read on unrelated updates in some screen readers;
|
|
41
|
+
* writing it once on the edge, and clearing it after, says it exactly once.
|
|
42
|
+
*/
|
|
43
|
+
const [announcement, setAnnouncement] = useState('');
|
|
44
|
+
const wasStopping = useRef(isStopping);
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (isStopping && !wasStopping.current)
|
|
47
|
+
setAnnouncement(stoppingLabel);
|
|
48
|
+
if (!isStopping && wasStopping.current)
|
|
49
|
+
setAnnouncement('');
|
|
50
|
+
wasStopping.current = isStopping;
|
|
51
|
+
}, [isStopping, stoppingLabel]);
|
|
52
|
+
const stopRef = useRef(onStop);
|
|
53
|
+
stopRef.current = onStop;
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!stopOnEscape || isStopping)
|
|
56
|
+
return;
|
|
57
|
+
const onKeyDown = (event) => {
|
|
58
|
+
if (event.key !== 'Escape')
|
|
59
|
+
return;
|
|
60
|
+
// An overlay that is open owns Escape. Do not cancel a run because the
|
|
61
|
+
// user tried to close a dialog on top of it.
|
|
62
|
+
if (event.target?.closest?.('[role="dialog"]'))
|
|
63
|
+
return;
|
|
64
|
+
stopRef.current();
|
|
65
|
+
};
|
|
66
|
+
document.addEventListener('keydown', onKeyDown);
|
|
67
|
+
return () => document.removeEventListener('keydown', onKeyDown);
|
|
68
|
+
}, [stopOnEscape, isStopping]);
|
|
69
|
+
return (_jsxs(_Fragment, { children: [_jsxs("button", { ...rest, ref: ref, type: "button", disabled: isStopping, "data-stopping": isStopping || undefined, onClick: (event) => {
|
|
70
|
+
rest.onClick?.(event);
|
|
71
|
+
if (!event.defaultPrevented)
|
|
72
|
+
onStop();
|
|
73
|
+
}, className: [
|
|
74
|
+
'ion-agent-stop',
|
|
75
|
+
size !== 'md' ? `ion-agent-stop--${size}` : '',
|
|
76
|
+
className || '',
|
|
77
|
+
]
|
|
78
|
+
.filter(Boolean)
|
|
79
|
+
.join(' '), children: [_jsx("span", { className: "ion-agent-stop__glyph", children: _jsx(StopGlyph, {}) }), _jsx("span", { className: "ion-agent-stop__label", children: isStopping ? stoppingLabel : label })] }), _jsx("span", { className: "ion-agent-stop__status ion-visually-hidden", role: "status", "aria-live": "polite", children: announcement })] }));
|
|
80
|
+
});
|
|
81
|
+
AgentStop.displayName = 'AgentStop';
|
|
82
|
+
//# sourceMappingURL=AgentStop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentStop.js","sourceRoot":"","sources":["../../src/components/AgentStop.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type ApprovalGateRisk = 'low' | 'medium' | 'high';
|
|
3
|
+
export type ApprovalGateStatus = 'pending' | 'approved' | 'rejected' | 'expired';
|
|
4
|
+
export interface ApprovalGateProps extends Omit<React.HTMLAttributes<HTMLElement>, 'title' | 'onChange'> {
|
|
5
|
+
/**
|
|
6
|
+
* What is being approved, stated as the action and its object — "Delete 14
|
|
7
|
+
* projects", not "Confirm action". Required: it is the region's accessible
|
|
8
|
+
* name, and a decision the user cannot name is not a decision.
|
|
9
|
+
*/
|
|
10
|
+
title: React.ReactNode;
|
|
11
|
+
/** Why it stopped here, and what happens on approval. */
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* How much is at stake. Drives emphasis only — it does NOT change what the
|
|
15
|
+
* component enforces, because the component enforces nothing.
|
|
16
|
+
*/
|
|
17
|
+
risk?: ApprovalGateRisk;
|
|
18
|
+
/** Where the decision has got to. `pending` is the only state with buttons. */
|
|
19
|
+
status?: ApprovalGateStatus;
|
|
20
|
+
onApprove?: () => void;
|
|
21
|
+
onReject?: () => void;
|
|
22
|
+
/**
|
|
23
|
+
* Offer "edit" as a third way out. Omit it when the proposal cannot be
|
|
24
|
+
* amended — an approve/reject pair the user cannot influence is honest;
|
|
25
|
+
* an edit button that discards their edit is not.
|
|
26
|
+
*/
|
|
27
|
+
onEdit?: () => void;
|
|
28
|
+
approveLabel?: string;
|
|
29
|
+
rejectLabel?: string;
|
|
30
|
+
editLabel?: string;
|
|
31
|
+
/** A decision is in flight. Both actions disable; neither disappears. */
|
|
32
|
+
isSubmitting?: boolean;
|
|
33
|
+
/** Shown in place of the actions once the decision is made. */
|
|
34
|
+
resolution?: React.ReactNode;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* ApprovalGate — a proposed action, held until a person decides.
|
|
38
|
+
*
|
|
39
|
+
* The human-in-the-loop control. An agent proposes; this is where a person
|
|
40
|
+
* approves, rejects, or amends before anything happens. In regulated contexts
|
|
41
|
+
* demonstrable human oversight is a compliance surface rather than a nicety,
|
|
42
|
+
* which is why this is a first-class component and not a Modal with two
|
|
43
|
+
* buttons in it.
|
|
44
|
+
*
|
|
45
|
+
* IT ENFORCES NOTHING, AND SAYING SO IS THE POINT
|
|
46
|
+
*
|
|
47
|
+
* This renders a decision. It does not gate execution — the caller does, by not
|
|
48
|
+
* acting until `onApprove` fires. A component that *looked* like it enforced a
|
|
49
|
+
* policy would be the worst possible thing to ship here: teams would rely on a
|
|
50
|
+
* guarantee that lives entirely in their own call site. `risk` changes emphasis
|
|
51
|
+
* and nothing else, for the same reason.
|
|
52
|
+
*
|
|
53
|
+
* NOT A MODAL, DELIBERATELY
|
|
54
|
+
*
|
|
55
|
+
* A modal steals focus and hides the page. But the page is the evidence: the
|
|
56
|
+
* user needs the plan, the diff, the tool call and the context in front of them
|
|
57
|
+
* while deciding. This sits inline, keeps everything visible, and never
|
|
58
|
+
* traps focus — an approval a user was rushed through is not oversight.
|
|
59
|
+
*
|
|
60
|
+
* NEITHER BUTTON IS FOCUSED ON MOUNT. Autofocusing approve turns a decision
|
|
61
|
+
* into an Enter keypress on a page the user has not read. Focus is moved to the
|
|
62
|
+
* region's heading instead, so a screen-reader user lands on what is being
|
|
63
|
+
* asked rather than on the answer.
|
|
64
|
+
*
|
|
65
|
+
* THE RESOLVED STATES ARE NOT DECORATION. `approved`, `rejected` and `expired`
|
|
66
|
+
* replace the actions with what happened, so the record of the decision stays
|
|
67
|
+
* on the page. `expired` exists because an approval request that nobody answers
|
|
68
|
+
* is the common real outcome, and a gate that sits pending for ever is
|
|
69
|
+
* indistinguishable from one that is broken.
|
|
70
|
+
*/
|
|
71
|
+
export declare const ApprovalGate: React.ForwardRefExoticComponent<ApprovalGateProps & React.RefAttributes<HTMLElement>>;
|
|
72
|
+
//# sourceMappingURL=ApprovalGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApprovalGate.d.ts","sourceRoot":"","sources":["../../src/components/ApprovalGate.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAyD,MAAM,OAAO,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AACzD,MAAM,MAAM,kBAAkB,GAC5B,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;AAElD,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EACjC,OAAO,GAAG,UAAU,CACrB;IACC;;;;OAIG;IACH,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;OAGG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC9B;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,YAAY,uFA4HxB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useEffect, useId, useRef, useState } from 'react';
|
|
4
|
+
const ShieldQuestion = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }), _jsx("path", { d: "M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.7M12 16h.01", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] }));
|
|
5
|
+
const STATUS_TEXT = {
|
|
6
|
+
approved: 'Approved',
|
|
7
|
+
rejected: 'Rejected',
|
|
8
|
+
expired: 'Expired without a decision',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* ApprovalGate — a proposed action, held until a person decides.
|
|
12
|
+
*
|
|
13
|
+
* The human-in-the-loop control. An agent proposes; this is where a person
|
|
14
|
+
* approves, rejects, or amends before anything happens. In regulated contexts
|
|
15
|
+
* demonstrable human oversight is a compliance surface rather than a nicety,
|
|
16
|
+
* which is why this is a first-class component and not a Modal with two
|
|
17
|
+
* buttons in it.
|
|
18
|
+
*
|
|
19
|
+
* IT ENFORCES NOTHING, AND SAYING SO IS THE POINT
|
|
20
|
+
*
|
|
21
|
+
* This renders a decision. It does not gate execution — the caller does, by not
|
|
22
|
+
* acting until `onApprove` fires. A component that *looked* like it enforced a
|
|
23
|
+
* policy would be the worst possible thing to ship here: teams would rely on a
|
|
24
|
+
* guarantee that lives entirely in their own call site. `risk` changes emphasis
|
|
25
|
+
* and nothing else, for the same reason.
|
|
26
|
+
*
|
|
27
|
+
* NOT A MODAL, DELIBERATELY
|
|
28
|
+
*
|
|
29
|
+
* A modal steals focus and hides the page. But the page is the evidence: the
|
|
30
|
+
* user needs the plan, the diff, the tool call and the context in front of them
|
|
31
|
+
* while deciding. This sits inline, keeps everything visible, and never
|
|
32
|
+
* traps focus — an approval a user was rushed through is not oversight.
|
|
33
|
+
*
|
|
34
|
+
* NEITHER BUTTON IS FOCUSED ON MOUNT. Autofocusing approve turns a decision
|
|
35
|
+
* into an Enter keypress on a page the user has not read. Focus is moved to the
|
|
36
|
+
* region's heading instead, so a screen-reader user lands on what is being
|
|
37
|
+
* asked rather than on the answer.
|
|
38
|
+
*
|
|
39
|
+
* THE RESOLVED STATES ARE NOT DECORATION. `approved`, `rejected` and `expired`
|
|
40
|
+
* replace the actions with what happened, so the record of the decision stays
|
|
41
|
+
* on the page. `expired` exists because an approval request that nobody answers
|
|
42
|
+
* is the common real outcome, and a gate that sits pending for ever is
|
|
43
|
+
* indistinguishable from one that is broken.
|
|
44
|
+
*/
|
|
45
|
+
export const ApprovalGate = forwardRef(({ title, children, risk = 'medium', status = 'pending', onApprove, onReject, onEdit, approveLabel = 'Approve', rejectLabel = 'Reject', editLabel = 'Edit', isSubmitting = false, resolution, className, ...rest }, ref) => {
|
|
46
|
+
const headingRef = useRef(null);
|
|
47
|
+
// A <section> is only a landmark once it has a name, and the name a
|
|
48
|
+
// reviewer needs is the decision itself.
|
|
49
|
+
const titleId = useId();
|
|
50
|
+
const [announcement, setAnnouncement] = useState('');
|
|
51
|
+
const previous = useRef(status);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (status !== previous.current && status !== 'pending')
|
|
54
|
+
setAnnouncement(STATUS_TEXT[status]);
|
|
55
|
+
previous.current = status;
|
|
56
|
+
}, [status]);
|
|
57
|
+
const pending = status === 'pending';
|
|
58
|
+
return (_jsxs("section", { ...rest, ref: ref, "aria-labelledby": titleId, "data-risk": risk, "data-status": status, className: [
|
|
59
|
+
'ion-approval-gate',
|
|
60
|
+
`ion-approval-gate--${risk}`,
|
|
61
|
+
!pending ? `ion-approval-gate--${status}` : '',
|
|
62
|
+
className || '',
|
|
63
|
+
]
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.join(' '), children: [_jsx("span", { className: "ion-approval-gate__icon", "aria-hidden": "true", children: _jsx(ShieldQuestion, {}) }), _jsxs("div", { className: "ion-approval-gate__body", children: [_jsx("p", { ref: headingRef, id: titleId, tabIndex: -1, className: "ion-approval-gate__title", children: title }), children && (_jsx("div", { className: "ion-approval-gate__detail", children: children })), pending ? (_jsxs("div", { className: "ion-approval-gate__actions", children: [_jsx("button", { type: "button", className: "ion-approval-gate__action ion-approval-gate__action--reject", disabled: isSubmitting || !onReject, onClick: onReject, children: rejectLabel }), onEdit && (_jsx("button", { type: "button", className: "ion-approval-gate__action ion-approval-gate__action--edit", disabled: isSubmitting, onClick: onEdit, children: editLabel })), _jsx("button", { type: "button", className: "ion-approval-gate__action ion-approval-gate__action--approve", disabled: isSubmitting || !onApprove, onClick: onApprove, children: approveLabel })] })) : (_jsx("p", { className: "ion-approval-gate__resolution", children: resolution ?? STATUS_TEXT[status] }))] }), _jsx("span", { className: "ion-approval-gate__status ion-visually-hidden", role: "status", "aria-live": "polite", children: announcement })] }));
|
|
66
|
+
});
|
|
67
|
+
ApprovalGate.displayName = 'ApprovalGate';
|
|
68
|
+
//# sourceMappingURL=ApprovalGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApprovalGate.js","sourceRoot":"","sources":["../../src/components/ApprovalGate.tsx"],"names":[],"mappings":"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"}
|
|
@@ -46,4 +46,8 @@ export { ScrollProgress } from './ScrollProgress.js';
|
|
|
46
46
|
export type { ScrollProgressProps, ScrollProgressSection, } from './ScrollProgress.js';
|
|
47
47
|
export { FullCard } from './FullCard.js';
|
|
48
48
|
export type { FullCardProps, FullCardAlignment, FullCardHeadingLevel, } from './FullCard.js';
|
|
49
|
+
export { AgentStop } from './AgentStop.js';
|
|
50
|
+
export type { AgentStopProps, AgentStopSize } from './AgentStop.js';
|
|
51
|
+
export { ApprovalGate } from './ApprovalGate.js';
|
|
52
|
+
export type { ApprovalGateProps, ApprovalGateRisk, ApprovalGateStatus, } from './ApprovalGate.js';
|
|
49
53
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
package/dist/components/index.js
CHANGED
|
@@ -22,4 +22,6 @@ export { NavItem } from './NavItem.js';
|
|
|
22
22
|
export { Table, TableHead, TableBody, TableRow, TableCell } from './Table.js';
|
|
23
23
|
export { ScrollProgress } from './ScrollProgress.js';
|
|
24
24
|
export { FullCard } from './FullCard.js';
|
|
25
|
+
export { AgentStop } from './AgentStop.js';
|
|
26
|
+
export { ApprovalGate } from './ApprovalGate.js';
|
|
25
27
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAOnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAMzC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOlD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAO3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS5D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAU9E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAOnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAMzC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOlD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAO3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS5D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAU9E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAMzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.24.0",
|
|
3
|
+
"begin": "───── CODE · ionbase-ui ─────",
|
|
4
|
+
"end": "───── end code ─────",
|
|
5
|
+
"blocks": {
|
|
6
|
+
"21:461": {
|
|
7
|
+
"figmaComponent": "Button",
|
|
8
|
+
"component": "Button",
|
|
9
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Button } from 'ionbase-ui';\n<Button variant=\"primary-brand\" size=\"sm\">Label</Button>\n\nPROPERTIES\n Type → variant: Primary Brand=primary-brand, Primary Neutral=primary-neutral, Primary Soft=primary-soft, Secondary=secondary, Tertiary=tertiary, Destructive=destructive, Success=success\n Size → size: Small=sm, Medium=md, Large=lg, XLarge=xl\n State → isDisabled (Disabled only)\n Label → children\n Leading Icon → startIcon\n Trailing Icon → endIcon\n Show Leading Icon → startIcon\n Show Trailing Icon → endIcon\n\nNOTES\n State: Default, Hover, Pressed and Focus are CSS and React Aria — :hover, :focus-visible, data-pressed — not props. Only Disabled is one.\n Leading Icon: wrap in Icon; omit Icon's label, the button text names it\n Trailing Icon: same\n Show Leading Icon: an absent prop is the switch — React needs no Show boolean, so false means omit startIcon\n Show Trailing Icon: same\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/button/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
10
|
+
},
|
|
11
|
+
"623:151": {
|
|
12
|
+
"figmaComponent": "Icon Button",
|
|
13
|
+
"component": "Button",
|
|
14
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Button } from 'ionbase-ui';\n<Button variant=\"primary-brand\" size=\"sm\" aria-label=\"…\" />\n\nPROPERTIES\n Type → variant: Primary Brand=primary-brand, Primary Neutral=primary-neutral, Primary Soft=primary-soft, Secondary=secondary, Tertiary=tertiary, Destructive=destructive, Success=success\n Size → size: Small=sm, Medium=md, Large=lg, XLarge=xl\n State → isDisabled (Disabled only)\n Icon → startIcon\n\nNot a separate component in code: an icon-only Button. It is the one case where aria-label is required, because there is no text to name it.\n\nNOTES\n State: as Button\n Icon: with Icon's own label omitted — the Button's aria-label carries the name\n Shape: Figma draws a square and a circle variant; code has no shape prop. A round icon button is a className, not an API.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/button/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
15
|
+
},
|
|
16
|
+
"80:275": {
|
|
17
|
+
"figmaComponent": "Input",
|
|
18
|
+
"component": "Input",
|
|
19
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Input } from 'ionbase-ui';\n<Input size=\"lg\" label=\"…\" />\n\nPROPERTIES\n Size → size: Small=sm, Medium=md, Large=lg\n State → isInvalid (Invalid only)\n Value → value\n Leading Icon → leadingIcon\n Trailing Icon → trailingIcon\n Show Leading Icon → leadingIcon\n Show Trailing Icon → trailingIcon\n\nNOTES\n State: Hover, Focus and Filled are CSS or content. Disabled is isDisabled, Read-only is isReadOnly — both react-aria props rather than this axis.\n Value: or defaultValue when uncontrolled; Figma's text is placeholder content, not necessarily a value\n Show Leading Icon: false means omit the prop\n Show Trailing Icon: false means omit the prop\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/input/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
20
|
+
},
|
|
21
|
+
"80:372": {
|
|
22
|
+
"figmaComponent": "Input/Phone",
|
|
23
|
+
"component": "PhoneInput",
|
|
24
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { PhoneInput } from 'ionbase-ui';\n<PhoneInput size=\"lg\" label=\"…\" />\n\nPROPERTIES\n Size → size: Small=sm, Medium=md, Large=lg\n Dial Code → dialCode\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/phone-input/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
25
|
+
},
|
|
26
|
+
"82:379": {
|
|
27
|
+
"figmaComponent": "Select",
|
|
28
|
+
"component": "Select",
|
|
29
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Select } from 'ionbase-ui';\n<Select size=\"lg\" label=\"…\" />\n\nPROPERTIES\n Size → size: Small=sm, Medium=md, Large=lg\n State → isInvalid (Invalid only)\n Value → placeholder\n\nNOTES\n State: Hover, Focus and Filled are CSS or content; Disabled is isDisabled\n Value: Figma's text is the collapsed display value. In code that is `placeholder` when nothing is chosen; once something is, the label comes from the `options` array.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/select/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
30
|
+
},
|
|
31
|
+
"87:350": {
|
|
32
|
+
"figmaComponent": "Checkbox",
|
|
33
|
+
"component": "Checkbox",
|
|
34
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Checkbox } from 'ionbase-ui';\n<Checkbox size=\"sm\" intent=\"brand\">Label</Checkbox>\n\nPROPERTIES\n Size → size: Small=sm, Medium=md, Large=lg\n Color → intent: Brand=brand, Neutral=neutral, Danger=danger\n State → isIndeterminate (Indeterminate, Indeterminate-disabled only)\n Label → children\n Show Label → children\n\nNOTES\n State: Checked is `checked`/`defaultChecked`, and the -disabled halves are isDisabled. One Figma axis, three code props, which is why it is not a single mapping.\n Show Label: false means a bare box — and then aria-label becomes required\n Focused: a drawn focus ring. In code it is :focus-visible, which the browser owns.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/checkbox/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
35
|
+
},
|
|
36
|
+
"89:314": {
|
|
37
|
+
"figmaComponent": "Radio",
|
|
38
|
+
"component": "Radio",
|
|
39
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Radio } from 'ionbase-ui';\n<Radio size=\"lg\" intent=\"brand\" value={…}>Label</Radio>\n\nPROPERTIES\n Size → size: Small=sm, Medium=md, Large=lg\n Color → intent: Brand=brand, Neutral=neutral, Danger=danger\n Label → children\n Show Label → children\n\nNOTES\n State: Selected/Unselected is the RadioGroup's value, not a prop on the Radio — a radio cannot own its own selection\n Show Label: false means aria-label is required\n Focused: drawn focus ring; :focus-visible in code\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/radio/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
40
|
+
},
|
|
41
|
+
"88:323": {
|
|
42
|
+
"figmaComponent": "Toggle",
|
|
43
|
+
"component": "Toggle",
|
|
44
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Toggle } from 'ionbase-ui';\n<Toggle size=\"sm\" intent=\"brand\">Label</Toggle>\n\nPROPERTIES\n Size → size: Small=sm, Medium=md, Large=lg\n Color → intent: Brand=brand, Neutral=neutral, Danger=danger\n Label → children\n Show Label → children\n\nNOTES\n State: On/Off is `checked`/`defaultChecked` on the underlying input, not a Toggle prop\n Show Label: false means aria-label is required\n Focused: drawn focus ring; :focus-visible in code\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/toggle/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
45
|
+
},
|
|
46
|
+
"152:73": {
|
|
47
|
+
"figmaComponent": "Badge",
|
|
48
|
+
"component": "Badge",
|
|
49
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Badge } from 'ionbase-ui';\n<Badge intent=\"neutral\">Label</Badge>\n\nPROPERTIES\n Intent → intent: Neutral=neutral, Primary=primary, Success=success, Warning=warning, Error=error, Information=information\n Label → children\n Show Label → children\n Show Dot → dot\n Show Icon → icon\n Swap Icon → icon\n\nNOTES\n Show Icon: false means omit icon; dot wins when both are set\n Size: Figma draws three sizes; code has no size prop. Badge inherits its type from the text it labels — the same call Link makes.\n Shape: Pill and Rounded are one radius token apart and code ships the pill only. Add the prop when a real screen needs both, not before.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/badge/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
50
|
+
},
|
|
51
|
+
"812:1902": {
|
|
52
|
+
"figmaComponent": "Alert",
|
|
53
|
+
"component": "Alert",
|
|
54
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Alert } from 'ionbase-ui';\n<Alert intent=\"information\" emphasis=\"subtle\" layout=\"inline\">Label</Alert>\n\nPROPERTIES\n Intent → intent: Neutral=neutral, Primary=primary, Success=success, Warning=warning, Error=error, Information=information\n Emphasis → emphasis: Subtle=subtle, Solid=solid\n Layout → layout: Inline=inline, Banner=banner\n Title → title\n Show Title → title\n Message → children\n Show Icon → hideIcon\n Show Dismiss → onDismiss\n Show Actions → actions\n\nNOTES\n Show Title: false means omit title\n Show Icon: inverted — Figma's Show Icon false is hideIcon true\n Show Dismiss: the dismiss button appears when a handler is passed; there is no boolean\n Show Actions: an absent prop is the switch\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/alert/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
55
|
+
},
|
|
56
|
+
"820:1655": {
|
|
57
|
+
"figmaComponent": "Toast",
|
|
58
|
+
"component": "Toast",
|
|
59
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Toast } from 'ionbase-ui';\n<Toast intent=\"information\" onDismiss={…} id={…} />\n\nPROPERTIES\n Intent → intent: Neutral=neutral, Primary=primary, Success=success, Warning=warning, Error=error, Information=information\n Title → title\n Show Title → title\n Message → message\n Show Message → message\n Show Action → action\n Show Dismiss → dismissLabel\n\nNOTES\n Show Action: one action only — a second belongs in a Modal\n Show Dismiss: the dismiss control is always rendered; only its label is configurable\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/toast/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
60
|
+
},
|
|
61
|
+
"774:1516": {
|
|
62
|
+
"figmaComponent": "Link",
|
|
63
|
+
"component": "Link",
|
|
64
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Link } from 'ionbase-ui';\n<Link variant=\"inline\">Label</Link>\n\nPROPERTIES\n Type → variant: Inline=inline, Standalone=standalone\n State → isDisabled (Disabled only)\n Label → children\n Leading Icon → startIcon\n Trailing Icon → endIcon\n Show Leading Icon → startIcon\n Show Trailing Icon → endIcon\n\nNOTES\n State: Hover and Focus are CSS; Visited is :visited, which no prop can set\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/link/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
65
|
+
},
|
|
66
|
+
"53:13": {
|
|
67
|
+
"figmaComponent": "Nav Item",
|
|
68
|
+
"component": "NavItem",
|
|
69
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { NavItem } from 'ionbase-ui';\n<NavItem>Label</NavItem>\n\nPROPERTIES\n Label → children\n Icon → icon\n Show Chevron → showChevron\n\nNOTES\n State: Default and Hover are CSS and React Aria's useHover, not props\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/nav-item/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
70
|
+
},
|
|
71
|
+
"82:306": {
|
|
72
|
+
"figmaComponent": "Menu",
|
|
73
|
+
"component": "Menu",
|
|
74
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Menu } from 'ionbase-ui';\n<Menu />\n\nNOTES\n Type: Single and Multi describe how many items may be selected, which is the caller's state. Menu renders the surface and holds no selection of its own.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/menu/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
75
|
+
},
|
|
76
|
+
"639:2634": {
|
|
77
|
+
"figmaComponent": "Menu Item",
|
|
78
|
+
"component": "MenuItem",
|
|
79
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { MenuItem } from 'ionbase-ui';\n<MenuItem>Label</MenuItem>\n\nPROPERTIES\n Status → isSelected (Selected, Selected Primary only)\n Text → children\n Show Icon → icon\n Select Icon → icon\n\nNOTES\n Status: Hover is CSS. Selected Primary is a second selected styling Figma draws and code does not yet ship.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/menu-item/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
80
|
+
},
|
|
81
|
+
"157:126": {
|
|
82
|
+
"figmaComponent": "Tabs",
|
|
83
|
+
"component": "Tabs",
|
|
84
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Tabs } from 'ionbase-ui';\n<Tabs type=\"pill\" orientation=\"horizontal\" aria-label=\"…\" />\n\nPROPERTIES\n Type → type: Pill=pill, Underline=underline\n Orientation → orientation: Horizontal=horizontal, Vertical=vertical\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/tabs/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
85
|
+
},
|
|
86
|
+
"156:259": {
|
|
87
|
+
"figmaComponent": "Tabs Item",
|
|
88
|
+
"component": "TabItem",
|
|
89
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { TabItem } from 'ionbase-ui';\n<TabItem key=\"billing\" title=\"Billing\">Panel content</TabItem>\n\nTabItem is a collection item and takes no props of its own. Type, Size and State belong to the parent Tabs or to its selection state, which is why almost everything here is ignored rather than mapped.\n\nNOTES\n Label: TabItem's label is its `title` collection prop. It is not a typed prop the TypeScript checker can see, so there is nothing here to verify against — see TabItem's contract.\n Type: set on the parent Tabs, not per item\n Size: set on the parent Tabs, not per item\n State: selection is the Tabs collection's state; Disabled is disabledKeys on Tabs\n Show Label: a tab without a label is a tab that cannot be named\n Show Leading Icon: not yet in the code component\n Leading Icon: not yet in the code component\n Show Trailing: not yet in the code component\n Trailing: not yet in the code component\n Focused: drawn focus ring; :focus-visible in code\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/tab-item/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
90
|
+
},
|
|
91
|
+
"174:103": {
|
|
92
|
+
"figmaComponent": "Table Cell",
|
|
93
|
+
"component": "TableCell",
|
|
94
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { TableCell } from 'ionbase-ui';\n<TableCell align=\"leading\" />\n\nPROPERTIES\n Type → header (Header only)\n Align → align: Leading=leading, Trailing=trailing\n Show Divider → showDivider\n Content → children\n Show Content → children\n\nNOTES\n Type: Body is the default <td>\n Density: density is set once on Table and reaches the cell through CSS — a per-cell prop could disagree with its own table\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/table-cell/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
95
|
+
},
|
|
96
|
+
"175:605": {
|
|
97
|
+
"figmaComponent": "Table Row",
|
|
98
|
+
"component": "TableRow",
|
|
99
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { TableRow } from 'ionbase-ui';\n<TableRow />\n\nPROPERTIES\n State → isSelected (Selected, Selected-Hover only)\n Show Selection → selection\n\nNOTES\n State: Hover is CSS\n Show Selection: takes the Checkbox's own props, not a boolean — a selectable row needs checked/onChange wiring\n Density: set once on Table; see Table Cell\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/table-row/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
100
|
+
},
|
|
101
|
+
"74:164": {
|
|
102
|
+
"figmaComponent": "Avatar",
|
|
103
|
+
"component": "Avatar",
|
|
104
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Avatar } from 'ionbase-ui';\n<Avatar size=\"lg\" shape=\"circle\" />\n\nPROPERTIES\n Size → size: Mini=mini, Small=sm, Medium=md, Large=lg\n Shape → shape: Circle=circle, Square=square\n Type → src (Image only)\n Initials → initials\n Icon → icon\n\nNOTES\n Type: code picks by precedence rather than a type prop: src, then initials, then icon. Character means pass initials, Icon means pass icon.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/avatar/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
105
|
+
},
|
|
106
|
+
"74:279": {
|
|
107
|
+
"figmaComponent": "Avatar Group",
|
|
108
|
+
"component": "AvatarGroup",
|
|
109
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { AvatarGroup } from 'ionbase-ui';\n<AvatarGroup size=\"lg\" shape=\"circle\" />\n\nPROPERTIES\n Size → size: Mini=mini, Small=sm, Medium=md, Large=lg\n Shape → shape: Circle=circle, Square=square\n Show Overflow → max\n Show Avatar 3 → children\n Show Avatar 4 → children\n\nNOTES\n Show Overflow: the +N avatar appears when children exceed max\n Show Avatar 3: Figma needs a boolean per slot; React just renders fewer children\n Show Avatar 4: same\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/avatar-group/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
110
|
+
},
|
|
111
|
+
"126:22724": {
|
|
112
|
+
"figmaComponent": "Border",
|
|
113
|
+
"component": "Divider",
|
|
114
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Divider } from 'ionbase-ui';\n<Divider orientation=\"vertical\" />\n\nPROPERTIES\n Style → orientation: Horizontal=horizontal, Vertical=vertical\n\nFigma calls it Border; the code component is Divider, because it renders an <hr> and an <hr> is a thematic break rather than an edge.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/divider/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
115
|
+
},
|
|
116
|
+
"52:21369": {
|
|
117
|
+
"figmaComponent": "Logo-Ionbase",
|
|
118
|
+
"component": "Logo",
|
|
119
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Logo } from 'ionbase-ui';\n<Logo size=\"sm\" wordmark=\"vector\" />\n\nPROPERTIES\n Size → size: Small=sm, Large=lg\n Type → wordmark: Logo=vector, Icon=text\n\nNOTES\n Type: the names invert: Figma's Logo is the serif vector wordmark, Figma's Icon is live Host Grotesk text\n Property: the Name axis renders placeholder text in an unbound colour — leftover debug content, not a real asset. LogoMark covers the no-wordmark case.\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/logo/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
120
|
+
},
|
|
121
|
+
"792:1537": {
|
|
122
|
+
"figmaComponent": "Modal",
|
|
123
|
+
"component": "Modal",
|
|
124
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Modal } from 'ionbase-ui';\n<Modal size=\"sm\" align=\"left\" title={…} />\n\nPROPERTIES\n Size → size: Small=sm, Medium=md, Large=lg, Fullscreen=fullscreen\n Align → align: Left=left, Center=center\n Title → title\n Description → description\n Show Description → description\n Show Close → showClose\n Show Body → children\n Show Footer → footer\n Show Media → media\n Media → media\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/modal/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
125
|
+
},
|
|
126
|
+
"825:1853": {
|
|
127
|
+
"figmaComponent": "Popover",
|
|
128
|
+
"component": "Popover",
|
|
129
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Popover } from 'ionbase-ui';\n<Popover placement=\"bottom\" size=\"sm\">…</Popover>\n\nPROPERTIES\n Placement → placement: Top=top, Bottom=bottom, Left=left, Right=right\n Size → size: Small=sm, Medium=md, Large=lg\n Title → title\n Show Header → title\n Body → content\n Show Body → content\n Show Close → showClose\n Show Footer → footer\n Show Arrow → hideArrow\n\nNOTES\n Show Arrow: inverted — Show Arrow false is hideArrow true\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/popover/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
130
|
+
},
|
|
131
|
+
"801:68": {
|
|
132
|
+
"figmaComponent": "Tooltip",
|
|
133
|
+
"component": "Tooltip",
|
|
134
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Tooltip } from 'ionbase-ui';\n<Tooltip placement=\"top\" label={…}>…</Tooltip>\n\nPROPERTIES\n Placement → placement: Top=top, Bottom=bottom, Left=left, Right=right\n Label → label\n Title → title\n Show Title → title\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/tooltip/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
135
|
+
},
|
|
136
|
+
"592:857": {
|
|
137
|
+
"figmaComponent": "Full Card",
|
|
138
|
+
"component": "FullCard",
|
|
139
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { FullCard } from 'ionbase-ui';\n<FullCard alignment=\"right\" headline={…} />\n\nPROPERTIES\n Row Reverse → alignment: True=left, False=right\n Headline → headline\n Description → description\n Show Description → description\n Eyebrow → eyebrow\n Show Eyebrow → eyebrow\n Actions → actions\n Show Actions → actions\n Media → media\n\nNOTES\n Row Reverse: Figma's boolean reverses the row; the code prop names which side the MEDIA sits on\n Media: pass the screenshot itself — the component draws the frame\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/full-card/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
140
|
+
},
|
|
141
|
+
"69:335": {
|
|
142
|
+
"figmaComponent": "Header",
|
|
143
|
+
"component": "Header",
|
|
144
|
+
"block": "───── CODE · ionbase-ui ─────\nimport { Header } from 'ionbase-ui';\n<Header />\n\nPROPERTIES\n Device → open (Mobile-Open, Mobile-Closed only)\n Center Slot → center\n End Slot → end\n Show Center Slot → center\n Show End Slot → end\n\nNOTES\n Device: Figma spells one four-way axis; code splits it in two. Desktop/Tablet/Mobile is a media query the browser already answers, and only Open/Closed is a prop.\n End Slot: a duplicate slot in the Figma component\n\nFull contract: https://raza-ahmed.github.io/ionbase-design-system/components/header/index.html.md\nGenerated from ionbase-ui@0.24.0. Edit the code, not this block.\n───── end code ─────"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|