@handamade/psi-react 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/IconButton/IconButton.d.ts +4 -0
- package/dist/IconButton/IconButton.d.ts.map +1 -1
- package/dist/Input/Input.d.ts +8 -2
- package/dist/Input/Input.d.ts.map +1 -1
- package/dist/index.js +158 -157
- package/dist/manifest.json +14 -0
- package/dist/patterns.json +455 -5
- package/docs/IconButton.md +1 -0
- package/docs/Input.md +1 -0
- package/llms.txt +1 -1
- package/package.json +2 -2
|
@@ -2,6 +2,10 @@ import type { ButtonHTMLAttributes, Ref } from "react";
|
|
|
2
2
|
type Variant = "accent" | "neutral" | "ghost" | "danger";
|
|
3
3
|
type Size = 24 | 32 | 40 | 48;
|
|
4
4
|
export interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
|
+
/** Accessible name for the icon-only control. Required: an IconButton has
|
|
6
|
+
* no text to name it, so omitting this ships an unnameable button (D60).
|
|
7
|
+
* If you also pass `aria-labelledby`, that wins per the accname algorithm. */
|
|
8
|
+
"aria-label": string;
|
|
5
9
|
/** Visual variant. @default "neutral" */
|
|
6
10
|
variant?: Variant;
|
|
7
11
|
/** Square size in px (24 | 32 | 40 | 48). @default 32 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.d.ts","sourceRoot":"","sources":["../../src/IconButton/IconButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EAEpB,GAAG,EACJ,MAAM,OAAO,CAAC;AAGf,KAAK,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AACzD,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAE9B,MAAM,WAAW,eACf,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC/C,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;kDAC8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,CAAC,EAAE,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;CAClD;AAgBD;gDACgD;AAChD,wBAAgB,UAAU,CAAC,EACzB,OAAmB,EACnB,IAAS,EACT,IAAI,EACJ,MAAM,EACN,GAAG,EACH,QAAQ,EACR,SAAS,EACT,OAAO,EACP,GAAG,EACH,GAAG,IAAI,EACR,EAAE,eAAe,+BA0CjB"}
|
|
1
|
+
{"version":3,"file":"IconButton.d.ts","sourceRoot":"","sources":["../../src/IconButton/IconButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EAEpB,GAAG,EACJ,MAAM,OAAO,CAAC;AAGf,KAAK,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AACzD,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAE9B,MAAM,WAAW,eACf,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC/C;;kFAE8E;IAC9E,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;kDAC8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,CAAC,EAAE,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;CAClD;AAgBD;gDACgD;AAChD,wBAAgB,UAAU,CAAC,EACzB,OAAmB,EACnB,IAAS,EACT,IAAI,EACJ,MAAM,EACN,GAAG,EACH,QAAQ,EACR,SAAS,EACT,OAAO,EACP,GAAG,EACH,GAAG,IAAI,EACR,EAAE,eAAe,+BA0CjB"}
|
package/dist/Input/Input.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { InputHTMLAttributes, Ref } from "react";
|
|
2
2
|
type Size = 24 | 32 | 40 | 48;
|
|
3
|
-
|
|
3
|
+
/** Input types Psi's Input supports. Deliberately narrower than the native
|
|
4
|
+
* `HTMLInputTypeAttribute`: checkbox/radio/file/submit are separate controls
|
|
5
|
+
* (Checkbox, Switch, Button), not variants of a text field (D60). */
|
|
6
|
+
export type InputType = "text" | "search" | "email" | "tel" | "url" | "password" | "number" | "date";
|
|
7
|
+
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"> {
|
|
8
|
+
/** Input type. @default "text" */
|
|
9
|
+
type?: InputType;
|
|
4
10
|
/** Height in px (24 | 32 | 40 | 48). @default 32 */
|
|
5
11
|
size?: Size;
|
|
6
12
|
/** Show error styling. Inside a Field, the Field's error also lights this. @default false */
|
|
@@ -11,6 +17,6 @@ export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
|
11
17
|
/** Single-line text input with pixel-true heights (24–48) and an error state.
|
|
12
18
|
* Inside a Field, id/aria-describedby/aria-invalid/required are wired
|
|
13
19
|
* automatically (D49). */
|
|
14
|
-
export declare function Input({ size, error, className, ref, ...rest }: InputProps): import("react").JSX.Element;
|
|
20
|
+
export declare function Input({ size, error, type, className, ref, ...rest }: InputProps): import("react").JSX.Element;
|
|
15
21
|
export {};
|
|
16
22
|
//# sourceMappingURL=Input.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/Input/Input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAItD,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAE9B,MAAM,WAAW,UAAW,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/Input/Input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAItD,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAE9B;;qEAEqE;AACrE,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,KAAK,GACL,KAAK,GACL,UAAU,GACV,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACrF,kCAAkC;IAClC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,oDAAoD;IACpD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,6FAA6F;IAC7F,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yDAAyD;IACzD,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AASD;;0BAE0B;AAC1B,wBAAgB,KAAK,CAAC,EAAE,IAAS,EAAE,KAAa,EAAE,IAAa,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,UAAU,+BAsBrG"}
|
package/dist/index.js
CHANGED
|
@@ -33,42 +33,42 @@ const O = "_button_c94w9_3", X = "_disabled_c94w9_30", J = "_size24_c94w9_44", Q
|
|
|
33
33
|
function un({
|
|
34
34
|
variant: e = "neutral",
|
|
35
35
|
size: t = 32,
|
|
36
|
-
href:
|
|
36
|
+
href: s,
|
|
37
37
|
target: a,
|
|
38
38
|
rel: c,
|
|
39
|
-
disabled:
|
|
40
|
-
className:
|
|
39
|
+
disabled: r,
|
|
40
|
+
className: o,
|
|
41
41
|
onClick: l,
|
|
42
42
|
ref: d,
|
|
43
|
-
...
|
|
43
|
+
...i
|
|
44
44
|
}) {
|
|
45
45
|
const u = [
|
|
46
46
|
f.button,
|
|
47
47
|
ue[e],
|
|
48
48
|
de[t],
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
s !== void 0 && r ? f.disabled : void 0,
|
|
50
|
+
o
|
|
51
51
|
].filter(Boolean).join(" ");
|
|
52
|
-
return
|
|
52
|
+
return s !== void 0 ? /* @__PURE__ */ n(
|
|
53
53
|
"a",
|
|
54
54
|
{
|
|
55
55
|
ref: d,
|
|
56
56
|
className: u,
|
|
57
|
-
href:
|
|
57
|
+
href: r ? void 0 : s,
|
|
58
58
|
target: a,
|
|
59
59
|
rel: c,
|
|
60
|
-
"aria-disabled":
|
|
61
|
-
onClick:
|
|
62
|
-
...
|
|
60
|
+
"aria-disabled": r || void 0,
|
|
61
|
+
onClick: r ? void 0 : l,
|
|
62
|
+
...i
|
|
63
63
|
}
|
|
64
64
|
) : /* @__PURE__ */ n(
|
|
65
65
|
"button",
|
|
66
66
|
{
|
|
67
67
|
ref: d,
|
|
68
68
|
className: u,
|
|
69
|
-
disabled:
|
|
69
|
+
disabled: r,
|
|
70
70
|
onClick: l,
|
|
71
|
-
...
|
|
71
|
+
...i
|
|
72
72
|
}
|
|
73
73
|
);
|
|
74
74
|
}
|
|
@@ -97,42 +97,42 @@ const _e = "_iconButton_129ca_3", he = "_disabled_129ca_29", pe = "_size24_129ca
|
|
|
97
97
|
function Ce({
|
|
98
98
|
variant: e = "neutral",
|
|
99
99
|
size: t = 32,
|
|
100
|
-
href:
|
|
100
|
+
href: s,
|
|
101
101
|
target: a,
|
|
102
102
|
rel: c,
|
|
103
|
-
disabled:
|
|
104
|
-
className:
|
|
103
|
+
disabled: r,
|
|
104
|
+
className: o,
|
|
105
105
|
onClick: l,
|
|
106
106
|
ref: d,
|
|
107
|
-
...
|
|
107
|
+
...i
|
|
108
108
|
}) {
|
|
109
109
|
const u = [
|
|
110
110
|
w.iconButton,
|
|
111
111
|
ke[e],
|
|
112
112
|
xe[t],
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
s !== void 0 && r ? w.disabled : void 0,
|
|
114
|
+
o
|
|
115
115
|
].filter(Boolean).join(" ");
|
|
116
|
-
return
|
|
116
|
+
return s !== void 0 ? /* @__PURE__ */ n(
|
|
117
117
|
"a",
|
|
118
118
|
{
|
|
119
119
|
ref: d,
|
|
120
120
|
className: u,
|
|
121
|
-
href:
|
|
121
|
+
href: r ? void 0 : s,
|
|
122
122
|
target: a,
|
|
123
123
|
rel: c,
|
|
124
|
-
"aria-disabled":
|
|
125
|
-
onClick:
|
|
126
|
-
...
|
|
124
|
+
"aria-disabled": r || void 0,
|
|
125
|
+
onClick: r ? void 0 : l,
|
|
126
|
+
...i
|
|
127
127
|
}
|
|
128
128
|
) : /* @__PURE__ */ n(
|
|
129
129
|
"button",
|
|
130
130
|
{
|
|
131
131
|
ref: d,
|
|
132
132
|
className: u,
|
|
133
|
-
disabled:
|
|
133
|
+
disabled: r,
|
|
134
134
|
onClick: l,
|
|
135
|
-
...
|
|
135
|
+
...i
|
|
136
136
|
}
|
|
137
137
|
);
|
|
138
138
|
}
|
|
@@ -147,19 +147,19 @@ const ze = "_card_1btb3_1", Le = "_stacked_1btb3_8", $e = "_featured_1btb3_10",
|
|
|
147
147
|
function dn({
|
|
148
148
|
variant: e = "stacked",
|
|
149
149
|
media: t,
|
|
150
|
-
hoverLift:
|
|
150
|
+
hoverLift: s = !1,
|
|
151
151
|
className: a,
|
|
152
152
|
children: c,
|
|
153
|
-
ref:
|
|
154
|
-
...
|
|
153
|
+
ref: r,
|
|
154
|
+
...o
|
|
155
155
|
}) {
|
|
156
156
|
const l = [
|
|
157
157
|
$.card,
|
|
158
158
|
e === "featured" ? $.featured : $.stacked,
|
|
159
|
-
|
|
159
|
+
s ? $.hoverLift : void 0,
|
|
160
160
|
a
|
|
161
161
|
].filter(Boolean).join(" ");
|
|
162
|
-
return /* @__PURE__ */ h("div", { ref:
|
|
162
|
+
return /* @__PURE__ */ h("div", { ref: r, className: l, ...o, children: [
|
|
163
163
|
t != null && /* @__PURE__ */ n("div", { className: $.media, children: t }),
|
|
164
164
|
/* @__PURE__ */ n("div", { className: $.body, children: c })
|
|
165
165
|
] });
|
|
@@ -168,9 +168,9 @@ const Ne = "_panel_jn8w4_1", Ie = "_padding16_jn8w4_8", q = {
|
|
|
168
168
|
panel: Ne,
|
|
169
169
|
padding16: Ie
|
|
170
170
|
};
|
|
171
|
-
function _n({ padding: e = 24, className: t, children:
|
|
172
|
-
const
|
|
173
|
-
return /* @__PURE__ */ n("div", { ref: a, className:
|
|
171
|
+
function _n({ padding: e = 24, className: t, children: s, ref: a, ...c }) {
|
|
172
|
+
const r = [q.panel, e === 16 ? q.padding16 : void 0, t].filter(Boolean).join(" ");
|
|
173
|
+
return /* @__PURE__ */ n("div", { ref: a, className: r, ...c, children: s });
|
|
174
174
|
}
|
|
175
175
|
const Me = "_navbar_1gyow_1", Ee = "_inner_1gyow_12", We = "_brand_1gyow_19", Ae = "_links_1gyow_20", De = "_actions_1gyow_50", M = {
|
|
176
176
|
navbar: Me,
|
|
@@ -179,20 +179,20 @@ const Me = "_navbar_1gyow_1", Ee = "_inner_1gyow_12", We = "_brand_1gyow_19", Ae
|
|
|
179
179
|
links: Ae,
|
|
180
180
|
actions: De
|
|
181
181
|
};
|
|
182
|
-
function hn({ brand: e, actions: t, children:
|
|
183
|
-
const
|
|
184
|
-
return /* @__PURE__ */ n("header", { ref: c, className:
|
|
182
|
+
function hn({ brand: e, actions: t, children: s, className: a, ref: c, ...r }) {
|
|
183
|
+
const o = [M.navbar, a].filter(Boolean).join(" ");
|
|
184
|
+
return /* @__PURE__ */ n("header", { ref: c, className: o, ...r, children: /* @__PURE__ */ h("div", { className: `psi-container ${M.inner}`, children: [
|
|
185
185
|
e != null && /* @__PURE__ */ n("div", { className: M.brand, children: e }),
|
|
186
|
-
/* @__PURE__ */ n("nav", { className: M.links, children:
|
|
186
|
+
/* @__PURE__ */ n("nav", { className: M.links, children: s }),
|
|
187
187
|
t != null && /* @__PURE__ */ n("div", { className: M.actions, children: t })
|
|
188
188
|
] }) });
|
|
189
189
|
}
|
|
190
190
|
const He = "_frame_et4fc_1", Ve = {
|
|
191
191
|
frame: He
|
|
192
192
|
};
|
|
193
|
-
function pn({ ratio: e, className: t, style:
|
|
194
|
-
const
|
|
195
|
-
return /* @__PURE__ */ n("div", { ref: c, className:
|
|
193
|
+
function pn({ ratio: e, className: t, style: s, children: a, ref: c, ...r }) {
|
|
194
|
+
const o = [Ve.frame, t].filter(Boolean).join(" ");
|
|
195
|
+
return /* @__PURE__ */ n("div", { ref: c, className: o, style: { aspectRatio: String(e), ...s }, ...r, children: a });
|
|
196
196
|
}
|
|
197
197
|
const Pe = "_field_lplye_1", Te = "_label_lplye_10", Re = "_marker_lplye_16", qe = "_message_lplye_20", Ke = "_invalid_lplye_26", j = {
|
|
198
198
|
field: Pe,
|
|
@@ -204,16 +204,16 @@ const Pe = "_field_lplye_1", Te = "_label_lplye_10", Re = "_marker_lplye_16", qe
|
|
|
204
204
|
function gn({
|
|
205
205
|
label: e,
|
|
206
206
|
description: t,
|
|
207
|
-
error:
|
|
207
|
+
error: s,
|
|
208
208
|
required: a = !1,
|
|
209
209
|
group: c = !1,
|
|
210
|
-
htmlFor:
|
|
211
|
-
className:
|
|
210
|
+
htmlFor: r,
|
|
211
|
+
className: o,
|
|
212
212
|
children: l,
|
|
213
213
|
ref: d,
|
|
214
|
-
...
|
|
214
|
+
...i
|
|
215
215
|
}) {
|
|
216
|
-
const u = H(), p =
|
|
216
|
+
const u = H(), p = r ?? u, _ = !!s, b = _ ? s : t, m = b != null && b !== !1 ? `${p}-message` : void 0, L = [j.field, _ && j.invalid, o].filter(Boolean).join(" "), g = e != null ? /* @__PURE__ */ h(V, { children: [
|
|
217
217
|
e,
|
|
218
218
|
a && /* @__PURE__ */ n("span", { "aria-hidden": "true", className: j.marker, children: " *" })
|
|
219
219
|
] }) : null, W = /* @__PURE__ */ h(V, { children: [
|
|
@@ -227,10 +227,10 @@ function gn({
|
|
|
227
227
|
ref: d,
|
|
228
228
|
className: L,
|
|
229
229
|
"aria-describedby": m,
|
|
230
|
-
...
|
|
230
|
+
...i,
|
|
231
231
|
children: W
|
|
232
232
|
}
|
|
233
|
-
) : /* @__PURE__ */ n("div", { ref: d, className: L, ...
|
|
233
|
+
) : /* @__PURE__ */ n("div", { ref: d, className: L, ...i, children: W });
|
|
234
234
|
}
|
|
235
235
|
function fn({ size: e = 20, ...t }) {
|
|
236
236
|
return /* @__PURE__ */ h("svg", { width: e, height: e, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...t, children: [
|
|
@@ -370,14 +370,14 @@ const Ue = "_dialog_l23jf_2", Ye = "_w400_l23jf_31", Ze = "_w560_l23jf_32", Ge =
|
|
|
370
370
|
function Dn({
|
|
371
371
|
open: e,
|
|
372
372
|
onClose: t,
|
|
373
|
-
title:
|
|
373
|
+
title: s,
|
|
374
374
|
footer: a,
|
|
375
375
|
width: c = 560,
|
|
376
|
-
dismissible:
|
|
377
|
-
className:
|
|
376
|
+
dismissible: r = !0,
|
|
377
|
+
className: o,
|
|
378
378
|
children: l,
|
|
379
379
|
ref: d,
|
|
380
|
-
...
|
|
380
|
+
...i
|
|
381
381
|
}) {
|
|
382
382
|
const u = z(null), p = H(), _ = (g) => {
|
|
383
383
|
u.current = g, typeof d == "function" ? d(g) : d && (d.current = g);
|
|
@@ -393,23 +393,23 @@ function Dn({
|
|
|
393
393
|
};
|
|
394
394
|
}, [e]);
|
|
395
395
|
const b = (g) => {
|
|
396
|
-
g.preventDefault(),
|
|
396
|
+
g.preventDefault(), r && t("esc");
|
|
397
397
|
}, m = (g) => {
|
|
398
|
-
|
|
399
|
-
}, L = [C.dialog, et[c],
|
|
398
|
+
r && g.target === u.current && t("backdrop");
|
|
399
|
+
}, L = [C.dialog, et[c], o].filter(Boolean).join(" ");
|
|
400
400
|
return /* @__PURE__ */ n(
|
|
401
401
|
"dialog",
|
|
402
402
|
{
|
|
403
403
|
ref: _,
|
|
404
404
|
className: L,
|
|
405
|
-
"aria-labelledby":
|
|
405
|
+
"aria-labelledby": s != null ? p : void 0,
|
|
406
406
|
onCancel: b,
|
|
407
407
|
onClick: m,
|
|
408
|
-
...
|
|
408
|
+
...i,
|
|
409
409
|
children: /* @__PURE__ */ h("div", { className: C.panel, children: [
|
|
410
|
-
(
|
|
411
|
-
|
|
412
|
-
|
|
410
|
+
(s != null || r) && /* @__PURE__ */ h("div", { className: C.header, children: [
|
|
411
|
+
s != null && /* @__PURE__ */ n("h2", { id: p, className: C.title, children: s }),
|
|
412
|
+
r && /* @__PURE__ */ n(
|
|
413
413
|
Ce,
|
|
414
414
|
{
|
|
415
415
|
variant: "ghost",
|
|
@@ -439,18 +439,19 @@ const tt = "_input_hpei8_3", nt = "_size24_hpei8_37", ot = "_size32_hpei8_43", r
|
|
|
439
439
|
40: S.size40,
|
|
440
440
|
48: S.size48
|
|
441
441
|
};
|
|
442
|
-
function Hn({ size: e = 32, error: t = !1, className:
|
|
443
|
-
const o = P(T),
|
|
442
|
+
function Hn({ size: e = 32, error: t = !1, type: s = "text", className: a, ref: c, ...r }) {
|
|
443
|
+
const o = P(T), l = t || ((o == null ? void 0 : o.invalid) ?? !1), d = [o == null ? void 0 : o.describedBy, r["aria-describedby"]].filter(Boolean).join(" ") || void 0, i = [S.input, at[e], l && S.error, a].filter(Boolean).join(" ");
|
|
444
444
|
return /* @__PURE__ */ n(
|
|
445
445
|
"input",
|
|
446
446
|
{
|
|
447
|
-
ref:
|
|
448
|
-
className:
|
|
449
|
-
id:
|
|
450
|
-
required:
|
|
447
|
+
ref: c,
|
|
448
|
+
className: i,
|
|
449
|
+
id: r.id ?? (o == null ? void 0 : o.id),
|
|
450
|
+
required: r.required ?? ((o == null ? void 0 : o.required) || void 0),
|
|
451
451
|
"aria-invalid": (o == null ? void 0 : o.invalid) || void 0,
|
|
452
|
-
|
|
453
|
-
|
|
452
|
+
type: s,
|
|
453
|
+
...r,
|
|
454
|
+
"aria-describedby": d
|
|
454
455
|
}
|
|
455
456
|
);
|
|
456
457
|
}
|
|
@@ -470,26 +471,26 @@ const ct = "_select_4x9ck_3", lt = "_size24_4x9ck_37", ut = "_size32_4x9ck_45",
|
|
|
470
471
|
function Vn({
|
|
471
472
|
size: e = 32,
|
|
472
473
|
error: t = !1,
|
|
473
|
-
className:
|
|
474
|
+
className: s,
|
|
474
475
|
ref: a,
|
|
475
476
|
children: c,
|
|
476
|
-
...
|
|
477
|
+
...r
|
|
477
478
|
}) {
|
|
478
|
-
const
|
|
479
|
+
const o = P(T), l = t || ((o == null ? void 0 : o.invalid) ?? !1), d = [o == null ? void 0 : o.describedBy, r["aria-describedby"]].filter(Boolean).join(" ") || void 0, i = [
|
|
479
480
|
N.select,
|
|
480
481
|
pt[e],
|
|
481
482
|
l && N.error,
|
|
482
|
-
|
|
483
|
+
s
|
|
483
484
|
].filter(Boolean).join(" ");
|
|
484
485
|
return /* @__PURE__ */ n(
|
|
485
486
|
"select",
|
|
486
487
|
{
|
|
487
488
|
ref: a,
|
|
488
|
-
className:
|
|
489
|
-
id:
|
|
490
|
-
required:
|
|
491
|
-
"aria-invalid": (
|
|
492
|
-
...
|
|
489
|
+
className: i,
|
|
490
|
+
id: r.id ?? (o == null ? void 0 : o.id),
|
|
491
|
+
required: r.required ?? ((o == null ? void 0 : o.required) || void 0),
|
|
492
|
+
"aria-invalid": (o == null ? void 0 : o.invalid) || void 0,
|
|
493
|
+
...r,
|
|
493
494
|
"aria-describedby": d,
|
|
494
495
|
children: c
|
|
495
496
|
}
|
|
@@ -505,19 +506,19 @@ const gt = "_label_1v4vv_3", ft = "_disabled_1v4vv_13", vt = "_input_1v4vv_20",
|
|
|
505
506
|
function Pn({
|
|
506
507
|
children: e,
|
|
507
508
|
className: t,
|
|
508
|
-
disabled:
|
|
509
|
+
disabled: s,
|
|
509
510
|
ref: a,
|
|
510
511
|
...c
|
|
511
512
|
}) {
|
|
512
|
-
const
|
|
513
|
-
return /* @__PURE__ */ h("label", { className:
|
|
513
|
+
const r = [E.label, s && E.disabled, t].filter(Boolean).join(" ");
|
|
514
|
+
return /* @__PURE__ */ h("label", { className: r, children: [
|
|
514
515
|
/* @__PURE__ */ n(
|
|
515
516
|
"input",
|
|
516
517
|
{
|
|
517
518
|
ref: a,
|
|
518
519
|
type: "checkbox",
|
|
519
520
|
className: E.input,
|
|
520
|
-
disabled:
|
|
521
|
+
disabled: s,
|
|
521
522
|
...c
|
|
522
523
|
}
|
|
523
524
|
),
|
|
@@ -536,12 +537,12 @@ const mt = "_label_jru2c_3", wt = "_disabled_jru2c_13", kt = "_input_jru2c_20",
|
|
|
536
537
|
function Tn({
|
|
537
538
|
children: e,
|
|
538
539
|
className: t,
|
|
539
|
-
disabled:
|
|
540
|
+
disabled: s,
|
|
540
541
|
ref: a,
|
|
541
542
|
...c
|
|
542
543
|
}) {
|
|
543
|
-
const
|
|
544
|
-
return /* @__PURE__ */ h("label", { className:
|
|
544
|
+
const r = [B.label, s && B.disabled, t].filter(Boolean).join(" ");
|
|
545
|
+
return /* @__PURE__ */ h("label", { className: r, children: [
|
|
545
546
|
/* @__PURE__ */ n(
|
|
546
547
|
"input",
|
|
547
548
|
{
|
|
@@ -549,7 +550,7 @@ function Tn({
|
|
|
549
550
|
type: "checkbox",
|
|
550
551
|
role: "switch",
|
|
551
552
|
className: B.input,
|
|
552
|
-
disabled:
|
|
553
|
+
disabled: s,
|
|
553
554
|
...c
|
|
554
555
|
}
|
|
555
556
|
),
|
|
@@ -586,21 +587,21 @@ const Lt = "_tag_3oysa_3", $t = "_dismiss_3oysa_17", jt = "_neutral_3oysa_43", B
|
|
|
586
587
|
function Rn({
|
|
587
588
|
variant: e = "neutral",
|
|
588
589
|
subtle: t = !1,
|
|
589
|
-
onDismiss:
|
|
590
|
+
onDismiss: s,
|
|
590
591
|
className: a,
|
|
591
592
|
children: c,
|
|
592
|
-
ref:
|
|
593
|
-
...
|
|
593
|
+
ref: r,
|
|
594
|
+
...o
|
|
594
595
|
}) {
|
|
595
596
|
const l = t ? Vt : Ht, d = [y.tag, l[e], a].filter(Boolean).join(" ");
|
|
596
|
-
return /* @__PURE__ */ h("span", { ref:
|
|
597
|
+
return /* @__PURE__ */ h("span", { ref: r, className: d, ...o, children: [
|
|
597
598
|
c,
|
|
598
|
-
|
|
599
|
+
s && /* @__PURE__ */ n(
|
|
599
600
|
"button",
|
|
600
601
|
{
|
|
601
602
|
type: "button",
|
|
602
603
|
className: y.dismiss,
|
|
603
|
-
onClick:
|
|
604
|
+
onClick: s,
|
|
604
605
|
"aria-label": "Dismiss",
|
|
605
606
|
children: /* @__PURE__ */ h(
|
|
606
607
|
"svg",
|
|
@@ -640,27 +641,27 @@ const Pt = "_wrapper_1eu6z_3", Tt = "_tooltip_1eu6z_10", Rt = "_top_1eu6z_24", q
|
|
|
640
641
|
function qn({
|
|
641
642
|
content: e,
|
|
642
643
|
children: t,
|
|
643
|
-
placement:
|
|
644
|
+
placement: s = "top"
|
|
644
645
|
}) {
|
|
645
|
-
const [a, c] = Z(!1),
|
|
646
|
-
|
|
647
|
-
}, []), d = k(() => c(!0), []),
|
|
646
|
+
const [a, c] = Z(!1), r = H(), o = z(void 0), l = k(() => {
|
|
647
|
+
o.current !== void 0 && (window.clearTimeout(o.current), o.current = void 0);
|
|
648
|
+
}, []), d = k(() => c(!0), []), i = k(() => c(!1), []);
|
|
648
649
|
x(() => l, [l]), x(() => {
|
|
649
650
|
if (!a) return;
|
|
650
651
|
const p = (_) => {
|
|
651
|
-
_.key === "Escape" &&
|
|
652
|
+
_.key === "Escape" && i();
|
|
652
653
|
};
|
|
653
654
|
return document.addEventListener("keydown", p), () => document.removeEventListener("keydown", p);
|
|
654
|
-
}, [a,
|
|
655
|
+
}, [a, i]);
|
|
655
656
|
const u = U(t, {
|
|
656
|
-
"aria-describedby": a ?
|
|
657
|
+
"aria-describedby": a ? r : void 0,
|
|
657
658
|
onMouseEnter: (p) => {
|
|
658
|
-
l(),
|
|
659
|
+
l(), o.current = window.setTimeout(d, Yt);
|
|
659
660
|
const _ = t.props.onMouseEnter;
|
|
660
661
|
_ == null || _(p);
|
|
661
662
|
},
|
|
662
663
|
onMouseLeave: (p) => {
|
|
663
|
-
l(),
|
|
664
|
+
l(), i();
|
|
664
665
|
const _ = t.props.onMouseLeave;
|
|
665
666
|
_ == null || _(p);
|
|
666
667
|
},
|
|
@@ -670,7 +671,7 @@ function qn({
|
|
|
670
671
|
_ == null || _(p);
|
|
671
672
|
},
|
|
672
673
|
onBlur: (p) => {
|
|
673
|
-
l(),
|
|
674
|
+
l(), i();
|
|
674
675
|
const _ = t.props.onBlur;
|
|
675
676
|
_ == null || _(p);
|
|
676
677
|
}
|
|
@@ -680,9 +681,9 @@ function qn({
|
|
|
680
681
|
a && /* @__PURE__ */ n(
|
|
681
682
|
"span",
|
|
682
683
|
{
|
|
683
|
-
id:
|
|
684
|
+
id: r,
|
|
684
685
|
role: "tooltip",
|
|
685
|
-
className: [I.tooltip, Ut[
|
|
686
|
+
className: [I.tooltip, Ut[s]].filter(Boolean).join(" "),
|
|
686
687
|
children: e
|
|
687
688
|
}
|
|
688
689
|
)
|
|
@@ -694,9 +695,9 @@ const Zt = "_toolbar_1i848_1", Gt = "_gap8_1i848_7", Ot = "_gap12_1i848_8", Xt =
|
|
|
694
695
|
gap12: Ot,
|
|
695
696
|
gap16: Xt
|
|
696
697
|
}, Jt = { 8: A.gap8, 12: A.gap12, 16: A.gap16 };
|
|
697
|
-
function Kn({ gap: e = 8, className: t, children:
|
|
698
|
-
const
|
|
699
|
-
return /* @__PURE__ */ n("div", { ref: a, role: c["aria-label"] != null ? "group" : void 0, className:
|
|
698
|
+
function Kn({ gap: e = 8, className: t, children: s, ref: a, ...c }) {
|
|
699
|
+
const r = [A.toolbar, Jt[e], t].filter(Boolean).join(" ");
|
|
700
|
+
return /* @__PURE__ */ n("div", { ref: a, role: c["aria-label"] != null ? "group" : void 0, className: r, ...c, children: s });
|
|
700
701
|
}
|
|
701
702
|
const Qt = "_trigger_vpa0u_4", en = "_menu_vpa0u_16", tn = "_item_vpa0u_37", nn = "_separator_vpa0u_74", D = {
|
|
702
703
|
trigger: Qt,
|
|
@@ -704,85 +705,85 @@ const Qt = "_trigger_vpa0u_4", en = "_menu_vpa0u_16", tn = "_item_vpa0u_37", nn
|
|
|
704
705
|
item: tn,
|
|
705
706
|
separator: nn
|
|
706
707
|
}, on = 500;
|
|
707
|
-
function rn({ popoverRef: e, triggerRef: t, open:
|
|
708
|
-
const c = z(""),
|
|
709
|
-
const
|
|
710
|
-
return
|
|
711
|
-
|
|
708
|
+
function rn({ popoverRef: e, triggerRef: t, open: s, onEsc: a }) {
|
|
709
|
+
const c = z(""), r = z(0), o = k(() => {
|
|
710
|
+
const i = e.current;
|
|
711
|
+
return i ? Array.from(
|
|
712
|
+
i.querySelectorAll('[data-psi-menu-item]:not([aria-disabled="true"])')
|
|
712
713
|
) : [];
|
|
713
714
|
}, [e]), l = k(
|
|
714
|
-
(
|
|
715
|
-
if (
|
|
716
|
-
for (const u of
|
|
717
|
-
|
|
715
|
+
(i) => {
|
|
716
|
+
if (i) {
|
|
717
|
+
for (const u of o()) u.tabIndex = u === i ? 0 : -1;
|
|
718
|
+
i.focus();
|
|
718
719
|
}
|
|
719
720
|
},
|
|
720
|
-
[
|
|
721
|
+
[o]
|
|
721
722
|
), d = k(() => {
|
|
722
723
|
var u;
|
|
723
|
-
const
|
|
724
|
-
|
|
724
|
+
const i = (u = t.current) == null ? void 0 : u.querySelector("button, a, [tabindex]");
|
|
725
|
+
i == null || i.focus();
|
|
725
726
|
}, [t]);
|
|
726
727
|
return x(() => {
|
|
727
|
-
if (!
|
|
728
|
-
const
|
|
729
|
-
return l(
|
|
728
|
+
if (!s) return;
|
|
729
|
+
const i = o();
|
|
730
|
+
return l(i[0]), () => {
|
|
730
731
|
var u;
|
|
731
732
|
(u = e.current) != null && u.contains(document.activeElement) && d();
|
|
732
733
|
};
|
|
733
|
-
}, [
|
|
734
|
-
(
|
|
735
|
-
if (
|
|
736
|
-
|
|
734
|
+
}, [s, e, o, l, d]), k(
|
|
735
|
+
(i) => {
|
|
736
|
+
if (i.key === "Escape") {
|
|
737
|
+
i.preventDefault(), a();
|
|
737
738
|
return;
|
|
738
739
|
}
|
|
739
|
-
const u =
|
|
740
|
+
const u = o();
|
|
740
741
|
if (u.length === 0) return;
|
|
741
742
|
const p = u.indexOf(document.activeElement);
|
|
742
|
-
switch (
|
|
743
|
+
switch (i.key) {
|
|
743
744
|
case "ArrowDown":
|
|
744
|
-
|
|
745
|
+
i.preventDefault(), l(u[(p + 1 + u.length) % u.length]);
|
|
745
746
|
return;
|
|
746
747
|
case "ArrowUp":
|
|
747
|
-
|
|
748
|
+
i.preventDefault(), l(u[p <= 0 ? u.length - 1 : p - 1]);
|
|
748
749
|
return;
|
|
749
750
|
case "Home":
|
|
750
|
-
|
|
751
|
+
i.preventDefault(), l(u[0]);
|
|
751
752
|
return;
|
|
752
753
|
case "End":
|
|
753
|
-
|
|
754
|
+
i.preventDefault(), l(u[u.length - 1]);
|
|
754
755
|
return;
|
|
755
756
|
}
|
|
756
|
-
if (
|
|
757
|
+
if (i.key.length !== 1 || i.metaKey || i.ctrlKey || i.altKey) return;
|
|
757
758
|
const _ = Date.now();
|
|
758
|
-
c.current = _ -
|
|
759
|
+
c.current = _ - r.current > on ? i.key.toLowerCase() : c.current + i.key.toLowerCase(), r.current = _;
|
|
759
760
|
const b = u.find(
|
|
760
761
|
(m) => (m.textContent ?? "").trim().toLowerCase().startsWith(c.current)
|
|
761
762
|
);
|
|
762
|
-
b && (
|
|
763
|
+
b && (i.preventDefault(), l(b));
|
|
763
764
|
},
|
|
764
|
-
[
|
|
765
|
+
[o, l, a]
|
|
765
766
|
);
|
|
766
767
|
}
|
|
767
768
|
function sn() {
|
|
768
769
|
return typeof CSS < "u" && CSS.supports("anchor-name", "--x");
|
|
769
770
|
}
|
|
770
|
-
function an({ popoverRef: e, triggerRef: t, open:
|
|
771
|
+
function an({ popoverRef: e, triggerRef: t, open: s, placement: a, anchorName: c }) {
|
|
771
772
|
x(() => {
|
|
772
|
-
const
|
|
773
|
-
!
|
|
773
|
+
const r = t.current, o = e.current;
|
|
774
|
+
!r || !o || (r.style.setProperty("anchor-name", c), o.style.setProperty("position-anchor", c));
|
|
774
775
|
}, [e, t, c]), x(() => {
|
|
775
|
-
if (!
|
|
776
|
-
const
|
|
777
|
-
if (!
|
|
776
|
+
if (!s || sn()) return;
|
|
777
|
+
const r = t.current, o = e.current;
|
|
778
|
+
if (!r || !o) return;
|
|
778
779
|
const l = () => {
|
|
779
|
-
const d =
|
|
780
|
-
|
|
780
|
+
const d = r.getBoundingClientRect(), i = a.startsWith("bottom"), u = a.endsWith("end"), p = getComputedStyle(r).direction === "rtl", _ = u !== p;
|
|
781
|
+
o.style.position = "fixed", o.style.top = i ? `${d.bottom}px` : "", o.style.bottom = i ? "" : `${window.innerHeight - d.top}px`, o.style.left = _ ? "" : `${d.left}px`, o.style.right = _ ? `${window.innerWidth - d.right}px` : "";
|
|
781
782
|
};
|
|
782
783
|
return l(), window.addEventListener("scroll", l, !0), window.addEventListener("resize", l), () => {
|
|
783
784
|
window.removeEventListener("scroll", l, !0), window.removeEventListener("resize", l);
|
|
784
785
|
};
|
|
785
|
-
}, [
|
|
786
|
+
}, [s, a, e, t]);
|
|
786
787
|
}
|
|
787
788
|
const Y = F({ close: () => {
|
|
788
789
|
} });
|
|
@@ -792,17 +793,17 @@ function K(e) {
|
|
|
792
793
|
function Fn({
|
|
793
794
|
open: e,
|
|
794
795
|
onClose: t,
|
|
795
|
-
trigger:
|
|
796
|
+
trigger: s,
|
|
796
797
|
placement: a = "bottom-start",
|
|
797
798
|
children: c,
|
|
798
|
-
className:
|
|
799
|
-
ref:
|
|
799
|
+
className: r,
|
|
800
|
+
ref: o,
|
|
800
801
|
...l
|
|
801
802
|
}) {
|
|
802
|
-
const d = z(null),
|
|
803
|
-
an({ popoverRef: d, triggerRef:
|
|
803
|
+
const d = z(null), i = z(null), u = z(!1), p = `--psi-menu-${H().replace(/:/g, "")}`;
|
|
804
|
+
an({ popoverRef: d, triggerRef: i, open: e, placement: a, anchorName: p });
|
|
804
805
|
const _ = (v) => {
|
|
805
|
-
d.current = v, typeof
|
|
806
|
+
d.current = v, typeof o == "function" ? o(v) : o && (o.current = v);
|
|
806
807
|
};
|
|
807
808
|
x(() => {
|
|
808
809
|
const v = d.current;
|
|
@@ -821,7 +822,7 @@ function Fn({
|
|
|
821
822
|
}
|
|
822
823
|
}, [t, e]), m = rn({
|
|
823
824
|
popoverRef: d,
|
|
824
|
-
triggerRef:
|
|
825
|
+
triggerRef: i,
|
|
825
826
|
open: e,
|
|
826
827
|
onEsc: () => t("esc")
|
|
827
828
|
}), L = k(
|
|
@@ -829,15 +830,15 @@ function Fn({
|
|
|
829
830
|
t(v);
|
|
830
831
|
},
|
|
831
832
|
[t]
|
|
832
|
-
), g = G(
|
|
833
|
+
), g = G(s);
|
|
833
834
|
x(() => {
|
|
834
835
|
g || console.warn(
|
|
835
836
|
"Psi Menu: `trigger` must be a single React element that forwards props to a focusable node. Menu clones it to attach aria-haspopup and aria-expanded; a string, fragment or array cannot carry them, so the menu renders without its trigger ARIA."
|
|
836
837
|
);
|
|
837
838
|
}, [g]);
|
|
838
|
-
const W = g ? U(
|
|
839
|
+
const W = g ? U(s, { "aria-haspopup": "menu", "aria-expanded": e }) : s;
|
|
839
840
|
return /* @__PURE__ */ h(V, { children: [
|
|
840
|
-
/* @__PURE__ */ n("div", { ref:
|
|
841
|
+
/* @__PURE__ */ n("div", { ref: i, className: D.trigger, "data-psi-menu-trigger": !0, children: W }),
|
|
841
842
|
/* @__PURE__ */ n(
|
|
842
843
|
"div",
|
|
843
844
|
{
|
|
@@ -847,7 +848,7 @@ function Fn({
|
|
|
847
848
|
role: "menu",
|
|
848
849
|
"data-psi-menu": !0,
|
|
849
850
|
"data-placement": a,
|
|
850
|
-
className: [D.menu,
|
|
851
|
+
className: [D.menu, r].filter(Boolean).join(" "),
|
|
851
852
|
onToggle: b,
|
|
852
853
|
onKeyDown: m,
|
|
853
854
|
children: /* @__PURE__ */ n(Y.Provider, { value: { close: L }, children: c })
|
|
@@ -855,7 +856,7 @@ function Fn({
|
|
|
855
856
|
)
|
|
856
857
|
] });
|
|
857
858
|
}
|
|
858
|
-
function Un({ children: e, onSelect: t, variant:
|
|
859
|
+
function Un({ children: e, onSelect: t, variant: s = "neutral", disabled: a = !1 }) {
|
|
859
860
|
const { close: c } = P(Y);
|
|
860
861
|
return /* @__PURE__ */ n(
|
|
861
862
|
"button",
|
|
@@ -863,7 +864,7 @@ function Un({ children: e, onSelect: t, variant: i = "neutral", disabled: a = !1
|
|
|
863
864
|
type: "button",
|
|
864
865
|
role: "menuitem",
|
|
865
866
|
"data-psi-menu-item": !0,
|
|
866
|
-
"data-variant":
|
|
867
|
+
"data-variant": s,
|
|
867
868
|
"aria-disabled": a || void 0,
|
|
868
869
|
tabIndex: -1,
|
|
869
870
|
className: D.item,
|
package/dist/manifest.json
CHANGED
|
@@ -61,6 +61,13 @@
|
|
|
61
61
|
"description": "Square icon-only button; same variant/size/href contract as Button. Give it an accessible name (`aria-label`).",
|
|
62
62
|
"slots": [],
|
|
63
63
|
"props": [
|
|
64
|
+
{
|
|
65
|
+
"name": "aria-label",
|
|
66
|
+
"type": "string",
|
|
67
|
+
"required": true,
|
|
68
|
+
"default": null,
|
|
69
|
+
"description": "Accessible name for the icon-only control. Required: an IconButton has\nno text to name it, so omitting this ships an unnameable button (D60).\nIf you also pass `aria-labelledby`, that wins per the accname algorithm."
|
|
70
|
+
},
|
|
64
71
|
{
|
|
65
72
|
"name": "variant",
|
|
66
73
|
"type": "\"accent\" | \"neutral\" | \"ghost\" | \"danger\"",
|
|
@@ -194,6 +201,13 @@
|
|
|
194
201
|
"description": "Single-line text input with pixel-true heights (24–48) and an error state. Inside a Field, id/aria-describedby/aria-invalid/required are wired automatically (D49).",
|
|
195
202
|
"slots": [],
|
|
196
203
|
"props": [
|
|
204
|
+
{
|
|
205
|
+
"name": "type",
|
|
206
|
+
"type": "\"number\" | \"text\" | \"search\" | \"email\" | \"tel\" | \"url\" | \"password\" | \"date\"",
|
|
207
|
+
"required": false,
|
|
208
|
+
"default": "text",
|
|
209
|
+
"description": "Input type."
|
|
210
|
+
},
|
|
197
211
|
{
|
|
198
212
|
"name": "size",
|
|
199
213
|
"type": "24 | 32 | 40 | 48",
|
package/dist/patterns.json
CHANGED
|
@@ -1,5 +1,215 @@
|
|
|
1
1
|
{
|
|
2
2
|
"patterns": [
|
|
3
|
+
{
|
|
4
|
+
"id": "action-feedback",
|
|
5
|
+
"intent": "Transient confirmation after a completed action, with an optional undo affordance",
|
|
6
|
+
"match": [
|
|
7
|
+
"toast",
|
|
8
|
+
"snackbar",
|
|
9
|
+
"action feedback",
|
|
10
|
+
"confirmation message",
|
|
11
|
+
"undo toast"
|
|
12
|
+
],
|
|
13
|
+
"compose": {
|
|
14
|
+
"component": "Toast",
|
|
15
|
+
"props": {
|
|
16
|
+
"variant": "{param:variant}"
|
|
17
|
+
},
|
|
18
|
+
"slots": {
|
|
19
|
+
"body": [
|
|
20
|
+
"{content:message}"
|
|
21
|
+
],
|
|
22
|
+
"action": [
|
|
23
|
+
{
|
|
24
|
+
"component": "Button",
|
|
25
|
+
"props": {
|
|
26
|
+
"variant": "ghost"
|
|
27
|
+
},
|
|
28
|
+
"content": "undo-label"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"parameters": [
|
|
34
|
+
{
|
|
35
|
+
"key": "variant",
|
|
36
|
+
"ask": "What kind of outcome is being confirmed?",
|
|
37
|
+
"options": [
|
|
38
|
+
"success",
|
|
39
|
+
"danger",
|
|
40
|
+
"neutral"
|
|
41
|
+
],
|
|
42
|
+
"default": "success"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"content": {
|
|
46
|
+
"message": "[what just happened]",
|
|
47
|
+
"undo-label": "Undo"
|
|
48
|
+
},
|
|
49
|
+
"gaps": [
|
|
50
|
+
"Toast"
|
|
51
|
+
],
|
|
52
|
+
"blocked": true,
|
|
53
|
+
"preset": null
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "bulk-action-bar",
|
|
57
|
+
"intent": "Bar that appears when table rows are selected: selection count, bulk actions, and a clear-selection control",
|
|
58
|
+
"match": [
|
|
59
|
+
"bulk actions",
|
|
60
|
+
"selection bar",
|
|
61
|
+
"batch actions",
|
|
62
|
+
"selected rows toolbar"
|
|
63
|
+
],
|
|
64
|
+
"compose": {
|
|
65
|
+
"component": "Toolbar",
|
|
66
|
+
"props": {
|
|
67
|
+
"gap": 12
|
|
68
|
+
},
|
|
69
|
+
"slots": {
|
|
70
|
+
"body": [
|
|
71
|
+
{
|
|
72
|
+
"component": "Tag",
|
|
73
|
+
"props": {
|
|
74
|
+
"variant": "accent",
|
|
75
|
+
"subtle": true
|
|
76
|
+
},
|
|
77
|
+
"content": "count-label"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"component": "Button",
|
|
81
|
+
"props": {
|
|
82
|
+
"variant": "neutral"
|
|
83
|
+
},
|
|
84
|
+
"content": "export-label"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"component": "Button",
|
|
88
|
+
"props": {
|
|
89
|
+
"variant": "danger-subtle"
|
|
90
|
+
},
|
|
91
|
+
"content": "delete-label"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"component": "Button",
|
|
95
|
+
"props": {
|
|
96
|
+
"variant": "ghost"
|
|
97
|
+
},
|
|
98
|
+
"content": "clear-label"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"parameters": [],
|
|
104
|
+
"content": {
|
|
105
|
+
"count-label": "[n] selected",
|
|
106
|
+
"export-label": "Export",
|
|
107
|
+
"delete-label": "Delete",
|
|
108
|
+
"clear-label": "Clear selection"
|
|
109
|
+
},
|
|
110
|
+
"gaps": [],
|
|
111
|
+
"blocked": false,
|
|
112
|
+
"preset": "<Toolbar\n gap={12}\n>\n <Tag subtle={true} variant=\"accent\">[n] selected</Tag>\n <Button variant=\"neutral\">Export</Button>\n <Button variant=\"danger-subtle\">Delete</Button>\n <Button variant=\"ghost\">Clear selection</Button>\n</Toolbar>\n"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "data-table",
|
|
116
|
+
"intent": "Sortable, selectable table of records with numeric columns and a per-row actions menu — compose the row menu from the row-actions pattern",
|
|
117
|
+
"match": [
|
|
118
|
+
"data table",
|
|
119
|
+
"transactions table",
|
|
120
|
+
"sortable table",
|
|
121
|
+
"records table",
|
|
122
|
+
"list of transactions"
|
|
123
|
+
],
|
|
124
|
+
"compose": {
|
|
125
|
+
"component": "Table",
|
|
126
|
+
"props": {
|
|
127
|
+
"selectable": true,
|
|
128
|
+
"sortable": true
|
|
129
|
+
},
|
|
130
|
+
"slots": {
|
|
131
|
+
"head": [
|
|
132
|
+
"{content:columns-note}"
|
|
133
|
+
],
|
|
134
|
+
"body": [
|
|
135
|
+
"{content:rows-note}"
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"parameters": [],
|
|
140
|
+
"content": {
|
|
141
|
+
"columns-note": "[one header cell per column; numeric columns align right]",
|
|
142
|
+
"rows-note": "[one row per record; put the row-actions menu in the last cell]"
|
|
143
|
+
},
|
|
144
|
+
"gaps": [
|
|
145
|
+
"Table"
|
|
146
|
+
],
|
|
147
|
+
"blocked": true,
|
|
148
|
+
"preset": null
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"id": "date-range-filter",
|
|
152
|
+
"intent": "From/to date pair for narrowing a dated list — native date inputs, no calendar widget",
|
|
153
|
+
"match": [
|
|
154
|
+
"date range filter",
|
|
155
|
+
"from to date",
|
|
156
|
+
"date filter",
|
|
157
|
+
"period filter",
|
|
158
|
+
"filter by date"
|
|
159
|
+
],
|
|
160
|
+
"compose": {
|
|
161
|
+
"component": "Toolbar",
|
|
162
|
+
"props": {
|
|
163
|
+
"gap": 12
|
|
164
|
+
},
|
|
165
|
+
"slots": {
|
|
166
|
+
"body": [
|
|
167
|
+
{
|
|
168
|
+
"component": "Field",
|
|
169
|
+
"slots": {
|
|
170
|
+
"label": [
|
|
171
|
+
"{content:from-label}"
|
|
172
|
+
],
|
|
173
|
+
"body": [
|
|
174
|
+
{
|
|
175
|
+
"component": "Input",
|
|
176
|
+
"props": {
|
|
177
|
+
"type": "date",
|
|
178
|
+
"size": 32
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"component": "Field",
|
|
186
|
+
"slots": {
|
|
187
|
+
"label": [
|
|
188
|
+
"{content:to-label}"
|
|
189
|
+
],
|
|
190
|
+
"body": [
|
|
191
|
+
{
|
|
192
|
+
"component": "Input",
|
|
193
|
+
"props": {
|
|
194
|
+
"type": "date",
|
|
195
|
+
"size": 32
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"parameters": [],
|
|
205
|
+
"content": {
|
|
206
|
+
"from-label": "From",
|
|
207
|
+
"to-label": "To"
|
|
208
|
+
},
|
|
209
|
+
"gaps": [],
|
|
210
|
+
"blocked": false,
|
|
211
|
+
"preset": "<Toolbar\n gap={12}\n>\n <Field\n label=\"From\"\n >\n <Input size={32} type=\"date\" />\n </Field>\n <Field\n label=\"To\"\n >\n <Input size={32} type=\"date\" />\n </Field>\n</Toolbar>\n"
|
|
212
|
+
},
|
|
3
213
|
{
|
|
4
214
|
"id": "destructive-confirm",
|
|
5
215
|
"intent": "Dialog confirming a destructive action",
|
|
@@ -59,6 +269,108 @@
|
|
|
59
269
|
"blocked": false,
|
|
60
270
|
"preset": "<Dialog\n footer={<>\n <Button size={32} variant=\"ghost\">Cancel</Button>\n <Button size={32} variant=\"danger\">[verb the object]</Button>\n </>}\n title=\"[Delete the object?]\"\n>\n [what is permanently lost]\n</Dialog>\n"
|
|
61
271
|
},
|
|
272
|
+
{
|
|
273
|
+
"id": "detail-drawer",
|
|
274
|
+
"intent": "Side sheet showing one record's detail, opened from a table row, with its primary actions in a footer",
|
|
275
|
+
"match": [
|
|
276
|
+
"detail drawer",
|
|
277
|
+
"side sheet",
|
|
278
|
+
"row detail",
|
|
279
|
+
"slide-over",
|
|
280
|
+
"record detail panel"
|
|
281
|
+
],
|
|
282
|
+
"compose": {
|
|
283
|
+
"component": "Drawer",
|
|
284
|
+
"props": {
|
|
285
|
+
"side": "{param:side}"
|
|
286
|
+
},
|
|
287
|
+
"slots": {
|
|
288
|
+
"title": [
|
|
289
|
+
"{content:title}"
|
|
290
|
+
],
|
|
291
|
+
"body": [
|
|
292
|
+
"{content:body-note}"
|
|
293
|
+
],
|
|
294
|
+
"footer": [
|
|
295
|
+
{
|
|
296
|
+
"component": "Button",
|
|
297
|
+
"props": {
|
|
298
|
+
"variant": "accent"
|
|
299
|
+
},
|
|
300
|
+
"content": "primary-label"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"component": "Button",
|
|
304
|
+
"props": {
|
|
305
|
+
"variant": "neutral"
|
|
306
|
+
},
|
|
307
|
+
"content": "dismiss-label"
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
"parameters": [
|
|
313
|
+
{
|
|
314
|
+
"key": "side",
|
|
315
|
+
"ask": "Which edge should the drawer open from?",
|
|
316
|
+
"options": [
|
|
317
|
+
"end",
|
|
318
|
+
"start"
|
|
319
|
+
],
|
|
320
|
+
"default": "end"
|
|
321
|
+
}
|
|
322
|
+
],
|
|
323
|
+
"content": {
|
|
324
|
+
"title": "[record title]",
|
|
325
|
+
"body-note": "[key-value summary of the selected record]",
|
|
326
|
+
"primary-label": "Save",
|
|
327
|
+
"dismiss-label": "Close"
|
|
328
|
+
},
|
|
329
|
+
"gaps": [
|
|
330
|
+
"Drawer"
|
|
331
|
+
],
|
|
332
|
+
"blocked": true,
|
|
333
|
+
"preset": null
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"id": "empty-state",
|
|
337
|
+
"intent": "Placeholder shown when a list has no results, distinguishing an empty filter from an empty dataset",
|
|
338
|
+
"match": [
|
|
339
|
+
"empty state",
|
|
340
|
+
"no results",
|
|
341
|
+
"nothing here",
|
|
342
|
+
"zero state",
|
|
343
|
+
"no data"
|
|
344
|
+
],
|
|
345
|
+
"compose": {
|
|
346
|
+
"component": "Panel",
|
|
347
|
+
"props": {
|
|
348
|
+
"padding": 24
|
|
349
|
+
},
|
|
350
|
+
"slots": {
|
|
351
|
+
"body": [
|
|
352
|
+
"{content:headline}",
|
|
353
|
+
"{content:explanation}",
|
|
354
|
+
{
|
|
355
|
+
"component": "Button",
|
|
356
|
+
"props": {
|
|
357
|
+
"variant": "neutral"
|
|
358
|
+
},
|
|
359
|
+
"content": "reset-label"
|
|
360
|
+
}
|
|
361
|
+
]
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
"parameters": [],
|
|
365
|
+
"content": {
|
|
366
|
+
"headline": "[nothing matches these filters]",
|
|
367
|
+
"explanation": "[say whether the dataset is empty or the filters are too narrow]",
|
|
368
|
+
"reset-label": "Clear filters"
|
|
369
|
+
},
|
|
370
|
+
"gaps": [],
|
|
371
|
+
"blocked": false,
|
|
372
|
+
"preset": "<Panel\n padding={24}\n>\n [nothing matches these filters]\n [say whether the dataset is empty or the filters are too narrow]\n <Button variant=\"neutral\">Clear filters</Button>\n</Panel>\n"
|
|
373
|
+
},
|
|
62
374
|
{
|
|
63
375
|
"id": "filter-toolbar",
|
|
64
376
|
"intent": "Toolbar of filter controls: search, category select, active-filter tags",
|
|
@@ -95,7 +407,7 @@
|
|
|
95
407
|
},
|
|
96
408
|
{
|
|
97
409
|
"id": "row-actions",
|
|
98
|
-
"intent": "List or table row with
|
|
410
|
+
"intent": "List or table row with an icon-only actions menu, including a destructive item — hand the destructive item's confirmation off to the destructive-confirm pattern",
|
|
99
411
|
"match": [
|
|
100
412
|
"row actions",
|
|
101
413
|
"per-row actions",
|
|
@@ -112,11 +424,12 @@
|
|
|
112
424
|
"slots": {
|
|
113
425
|
"trigger": [
|
|
114
426
|
{
|
|
115
|
-
"component": "
|
|
427
|
+
"component": "IconButton",
|
|
116
428
|
"props": {
|
|
117
|
-
"variant": "ghost"
|
|
429
|
+
"variant": "ghost",
|
|
430
|
+
"aria-label": "{content:trigger-label}"
|
|
118
431
|
},
|
|
119
|
-
"content": "trigger-
|
|
432
|
+
"content": "trigger-icon"
|
|
120
433
|
}
|
|
121
434
|
],
|
|
122
435
|
"body": [
|
|
@@ -154,13 +467,14 @@
|
|
|
154
467
|
],
|
|
155
468
|
"content": {
|
|
156
469
|
"trigger-label": "Actions",
|
|
470
|
+
"trigger-icon": "[icon]",
|
|
157
471
|
"edit-label": "Edit",
|
|
158
472
|
"duplicate-label": "Duplicate",
|
|
159
473
|
"delete-label": "Delete"
|
|
160
474
|
},
|
|
161
475
|
"gaps": [],
|
|
162
476
|
"blocked": false,
|
|
163
|
-
"preset": "<Menu\n aria-label=\"Actions\"\n placement=\"bottom-end\"\n trigger={<
|
|
477
|
+
"preset": "<Menu\n aria-label=\"Actions\"\n placement=\"bottom-end\"\n trigger={<IconButton aria-label=\"Actions\" variant=\"ghost\">[icon]</IconButton>}\n>\n <MenuItem>Edit</MenuItem>\n <MenuItem>Duplicate</MenuItem>\n <MenuSeparator />\n <MenuItem variant=\"danger\">Delete</MenuItem>\n</Menu>\n"
|
|
164
478
|
},
|
|
165
479
|
{
|
|
166
480
|
"id": "settings-form-row",
|
|
@@ -201,6 +515,142 @@
|
|
|
201
515
|
"gaps": [],
|
|
202
516
|
"blocked": false,
|
|
203
517
|
"preset": "<Field\n description=\"[one-line consequence of the setting]\"\n group={true}\n label=\"[setting name]\"\n>\n <Switch>[what turning it on does]</Switch>\n</Field>\n"
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
"id": "summary-tiles",
|
|
521
|
+
"intent": "Row of headline figures above a ledger — balances or totals, one Card per figure",
|
|
522
|
+
"match": [
|
|
523
|
+
"summary tiles",
|
|
524
|
+
"stat cards",
|
|
525
|
+
"kpi row",
|
|
526
|
+
"balance cards",
|
|
527
|
+
"totals row"
|
|
528
|
+
],
|
|
529
|
+
"compose": {
|
|
530
|
+
"component": "Toolbar",
|
|
531
|
+
"props": {
|
|
532
|
+
"gap": 16
|
|
533
|
+
},
|
|
534
|
+
"slots": {
|
|
535
|
+
"body": [
|
|
536
|
+
{
|
|
537
|
+
"component": "Card",
|
|
538
|
+
"props": {
|
|
539
|
+
"variant": "stacked"
|
|
540
|
+
},
|
|
541
|
+
"content": "tile-note"
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
"component": "Card",
|
|
545
|
+
"props": {
|
|
546
|
+
"variant": "stacked"
|
|
547
|
+
},
|
|
548
|
+
"content": "tile-note"
|
|
549
|
+
}
|
|
550
|
+
]
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
"parameters": [],
|
|
554
|
+
"content": {
|
|
555
|
+
"tile-note": "[label above, figure below]"
|
|
556
|
+
},
|
|
557
|
+
"gaps": [],
|
|
558
|
+
"blocked": false,
|
|
559
|
+
"preset": "<Toolbar\n gap={16}\n>\n <Card variant=\"stacked\">[label above, figure below]</Card>\n <Card variant=\"stacked\">[label above, figure below]</Card>\n</Toolbar>\n"
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
"id": "tabbed-workspace",
|
|
563
|
+
"intent": "Tab set switching between sibling views of the same workspace, such as accounts or saved filters",
|
|
564
|
+
"match": [
|
|
565
|
+
"tabs",
|
|
566
|
+
"tabbed view",
|
|
567
|
+
"switch between accounts",
|
|
568
|
+
"tab bar",
|
|
569
|
+
"segmented views"
|
|
570
|
+
],
|
|
571
|
+
"compose": {
|
|
572
|
+
"component": "Tabs",
|
|
573
|
+
"props": {
|
|
574
|
+
"orientation": "{param:orientation}"
|
|
575
|
+
},
|
|
576
|
+
"slots": {
|
|
577
|
+
"list": [
|
|
578
|
+
"{content:tabs-note}"
|
|
579
|
+
],
|
|
580
|
+
"panels": [
|
|
581
|
+
"{content:panels-note}"
|
|
582
|
+
]
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
"parameters": [
|
|
586
|
+
{
|
|
587
|
+
"key": "orientation",
|
|
588
|
+
"ask": "How should the tab list be laid out?",
|
|
589
|
+
"options": [
|
|
590
|
+
"horizontal",
|
|
591
|
+
"vertical"
|
|
592
|
+
],
|
|
593
|
+
"default": "horizontal"
|
|
594
|
+
}
|
|
595
|
+
],
|
|
596
|
+
"content": {
|
|
597
|
+
"tabs-note": "[one tab per view; keep labels to one or two words]",
|
|
598
|
+
"panels-note": "[one panel per tab, in the same order]"
|
|
599
|
+
},
|
|
600
|
+
"gaps": [
|
|
601
|
+
"Tabs"
|
|
602
|
+
],
|
|
603
|
+
"blocked": true,
|
|
604
|
+
"preset": null
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
"id": "table-pagination",
|
|
608
|
+
"intent": "Page-size selector and page range control beneath a data table",
|
|
609
|
+
"match": [
|
|
610
|
+
"pagination",
|
|
611
|
+
"table pagination",
|
|
612
|
+
"page controls",
|
|
613
|
+
"rows per page",
|
|
614
|
+
"paging"
|
|
615
|
+
],
|
|
616
|
+
"compose": {
|
|
617
|
+
"component": "Toolbar",
|
|
618
|
+
"props": {
|
|
619
|
+
"gap": 12
|
|
620
|
+
},
|
|
621
|
+
"slots": {
|
|
622
|
+
"body": [
|
|
623
|
+
{
|
|
624
|
+
"component": "Field",
|
|
625
|
+
"slots": {
|
|
626
|
+
"label": [
|
|
627
|
+
"{content:page-size-label}"
|
|
628
|
+
],
|
|
629
|
+
"body": [
|
|
630
|
+
{
|
|
631
|
+
"component": "Select",
|
|
632
|
+
"props": {
|
|
633
|
+
"size": 32
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
]
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
"component": "Pagination"
|
|
641
|
+
}
|
|
642
|
+
]
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
"parameters": [],
|
|
646
|
+
"content": {
|
|
647
|
+
"page-size-label": "Rows per page"
|
|
648
|
+
},
|
|
649
|
+
"gaps": [
|
|
650
|
+
"Pagination"
|
|
651
|
+
],
|
|
652
|
+
"blocked": true,
|
|
653
|
+
"preset": null
|
|
204
654
|
}
|
|
205
655
|
]
|
|
206
656
|
}
|
package/docs/IconButton.md
CHANGED
|
@@ -7,6 +7,7 @@ Square icon-only button; same variant/size/href contract as Button. Give it an a
|
|
|
7
7
|
|
|
8
8
|
| Prop | Type | Default | Required | Description |
|
|
9
9
|
|---|---|---|---|---|
|
|
10
|
+
| `aria-label` | `string` | — | yes | Accessible name for the icon-only control. Required: an IconButton has no text to name it, so omitting this ships an unnameable button (D60). If you also pass `aria-labelledby`, that wins per the accname algorithm. |
|
|
10
11
|
| `variant` | `"accent" \| "neutral" \| "ghost" \| "danger"` | neutral | no | Visual variant. |
|
|
11
12
|
| `size` | `24 \| 32 \| 40 \| 48` | 32 | no | Square size in px (24 \| 32 \| 40 \| 48). |
|
|
12
13
|
| `href` | `string` | — | no | Render as an anchor with this href (D33). disabled → aria-disabled, no href attribute, pointer-events: none. |
|
package/docs/Input.md
CHANGED
|
@@ -7,6 +7,7 @@ Single-line text input with pixel-true heights (24–48) and an error state. Ins
|
|
|
7
7
|
|
|
8
8
|
| Prop | Type | Default | Required | Description |
|
|
9
9
|
|---|---|---|---|---|
|
|
10
|
+
| `type` | `"number" \| "text" \| "search" \| "email" \| "tel" \| "url" \| "password" \| "date"` | text | no | Input type. |
|
|
10
11
|
| `size` | `24 \| 32 \| 40 \| 48` | 32 | no | Height in px (24 \| 32 \| 40 \| 48). |
|
|
11
12
|
| `error` | `boolean` | false | no | Show error styling. Inside a Field, the Field's error also lights this. |
|
|
12
13
|
| `ref` | `Ref<HTMLInputElement>` | — | no | Forwarded ref to the underlying `<input>` element. |
|
package/llms.txt
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Machine-readable artifacts
|
|
6
6
|
- dist/manifest.json: full component/prop inventory with types and defaults
|
|
7
|
-
- dist/patterns.json:
|
|
7
|
+
- dist/patterns.json: 13 composition patterns (D47) — gap-annotated recipes with clarifying parameters; presets are generated JSX, never hand-written
|
|
8
8
|
- docs/{Component}.md: per-component docs (props, theming, variant guidance)
|
|
9
9
|
|
|
10
10
|
## Rules for generated code
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@handamade/psi-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"tsx": "^4.22.4",
|
|
41
41
|
"vite": "^6.0.0",
|
|
42
42
|
"vitest": "^3.2.6",
|
|
43
|
-
"@handamade/psi-tokens": "0.
|
|
43
|
+
"@handamade/psi-tokens": "0.9.0"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "vite build && tsc -p tsconfig.build.json && tsx scripts/emit-manifest.ts && tsx scripts/emit-patterns.ts && tsx scripts/emit-docs.ts",
|