@pinfold/react 0.0.0-stage → 0.2.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/README.md +58 -2
- package/accordion/lazy/package.json +6 -0
- package/accordion/package.json +6 -0
- package/dist/accordion/client.cjs +491 -0
- package/dist/accordion/client.d.cts +34 -0
- package/dist/accordion/client.d.ts +34 -0
- package/dist/accordion/client.js +490 -0
- package/dist/accordion/index.cjs +49 -0
- package/dist/accordion/index.d.cts +56 -0
- package/dist/accordion/index.d.ts +56 -0
- package/dist/accordion/index.js +14 -0
- package/dist/accordion/lazy.cjs +17 -0
- package/dist/accordion/lazy.d.cts +16 -0
- package/dist/accordion/lazy.d.ts +16 -0
- package/dist/accordion/lazy.js +16 -0
- package/dist/chunk-5ZMK623A.js +61 -0
- package/dist/chunk-BPPCPHHU.js +70 -0
- package/dist/chunk-DQWSDHRY.cjs +71 -0
- package/dist/chunk-Q232PTPW.js +115 -0
- package/dist/chunk-RJPT3NTP.cjs +62 -0
- package/dist/chunk-VPKVOJHA.cjs +116 -0
- package/dist/client.cjs +30 -0
- package/dist/client.d.cts +120 -0
- package/dist/client.d.ts +120 -0
- package/dist/client.js +29 -0
- package/dist/index.cjs +52 -0
- package/dist/index.d.cts +123 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.js +10 -0
- package/dist/types-CkcgnWwL.d.cts +367 -0
- package/dist/types-CkcgnWwL.d.ts +367 -0
- package/dist/types-N0Yo4zGa.d.cts +374 -0
- package/dist/types-N0Yo4zGa.d.ts +374 -0
- package/dist/validate-EQHBH4NH.cjs +42 -0
- package/dist/validate-WKHQNNGD.js +41 -0
- package/llms-full.txt +140 -0
- package/llms.txt +26 -0
- package/package.json +92 -4
- package/registry/accordion.json +20 -0
- package/registry/registry.json +25 -0
- package/schema/accordion.json +903 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
renderSlot,
|
|
4
|
+
slotProps,
|
|
5
|
+
usePinfoldComponent
|
|
6
|
+
} from "../chunk-BPPCPHHU.js";
|
|
7
|
+
import {
|
|
8
|
+
useControllableState,
|
|
9
|
+
useEvent,
|
|
10
|
+
useId,
|
|
11
|
+
usePinfold
|
|
12
|
+
} from "../chunk-Q232PTPW.js";
|
|
13
|
+
|
|
14
|
+
// src/accordion/useAccordion.tsx
|
|
15
|
+
import * as React2 from "react";
|
|
16
|
+
import {
|
|
17
|
+
accordionFocusTarget,
|
|
18
|
+
accordionPartIds,
|
|
19
|
+
accordionRowId,
|
|
20
|
+
ariaAttr,
|
|
21
|
+
closeAllAccordion,
|
|
22
|
+
dataAttr,
|
|
23
|
+
initialAccordionValue,
|
|
24
|
+
mapAccordionFields,
|
|
25
|
+
mergeProps as mergeProps2,
|
|
26
|
+
openAllAccordion,
|
|
27
|
+
setAccordionItem,
|
|
28
|
+
warnOnce,
|
|
29
|
+
__DEV__
|
|
30
|
+
} from "@pinfold/core";
|
|
31
|
+
|
|
32
|
+
// src/accordion/AccordionView.tsx
|
|
33
|
+
import * as React from "react";
|
|
34
|
+
import { accordionRowsJoined, cn, dimensionVars, mergeProps, resolveNode, shouldMountPanel } from "@pinfold/core";
|
|
35
|
+
var B = "pinfold-accordion";
|
|
36
|
+
var RADIUS_SCALE = { none: 0, sm: 0.6, md: 1, lg: 1.5, full: 2.4 };
|
|
37
|
+
var GAP = { none: "0px", sm: "var(--pinfold-space-2)", md: "var(--pinfold-space-3)", lg: "var(--pinfold-space-5)" };
|
|
38
|
+
var own = (map, key) => typeof key === "string" && Object.prototype.hasOwnProperty.call(map, key);
|
|
39
|
+
var radiusValue = (r) => own(RADIUS_SCALE, r) ? `calc(var(--pinfold-acc-radius-unit) * ${RADIUS_SCALE[r]})` : r;
|
|
40
|
+
var gapValue = (g) => own(GAP, g) ? GAP[g] : g;
|
|
41
|
+
var GLYPHS = {
|
|
42
|
+
chevron: /* @__PURE__ */ React.createElement("path", { d: "M4 6.5 8 10.5 12 6.5" }),
|
|
43
|
+
caret: /* @__PURE__ */ React.createElement("path", { d: "M6 4l5 4-5 4z", fill: "currentColor", stroke: "none" }),
|
|
44
|
+
arrow: /* @__PURE__ */ React.createElement("path", { d: "M8 3.5v9M4.5 9 8 12.5 11.5 9" }),
|
|
45
|
+
plus: /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("path", { d: "M8 3.5v9", className: `${B}__indicator-bar` }), /* @__PURE__ */ React.createElement("path", { d: "M3.5 8h9" }))
|
|
46
|
+
};
|
|
47
|
+
function overflowProps(policy, fallback) {
|
|
48
|
+
const p = policy != null ? policy : fallback;
|
|
49
|
+
if (typeof p === "object") return { "data-overflow": "clamp", style: { "--pinfold-lines": String(p.lines) } };
|
|
50
|
+
return { "data-overflow": p };
|
|
51
|
+
}
|
|
52
|
+
function slot(ctx, name, base, item) {
|
|
53
|
+
var _a, _b, _c, _d;
|
|
54
|
+
const merged = slotProps(ctx.config, name, base);
|
|
55
|
+
const perItem = item == null ? void 0 : item.config;
|
|
56
|
+
if (!((_a = perItem == null ? void 0 : perItem.classNames) == null ? void 0 : _a[name]) && !((_b = perItem == null ? void 0 : perItem.styles) == null ? void 0 : _b[name])) return merged;
|
|
57
|
+
return mergeProps(merged, {
|
|
58
|
+
className: (_c = perItem.classNames) == null ? void 0 : _c[name],
|
|
59
|
+
style: (_d = perItem.styles) == null ? void 0 : _d[name]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function renderRoot(ctx, rootProps) {
|
|
63
|
+
var _a, _b;
|
|
64
|
+
const { api, config, a } = ctx;
|
|
65
|
+
const dimensions = {
|
|
66
|
+
radius: radiusValue(config.radius),
|
|
67
|
+
itemRadius: radiusValue(config.itemRadius),
|
|
68
|
+
gap: gapValue(config.gap),
|
|
69
|
+
...config.dimensions
|
|
70
|
+
};
|
|
71
|
+
const props = api.getRootProps(
|
|
72
|
+
mergeProps(
|
|
73
|
+
slot(ctx, "root", {
|
|
74
|
+
className: a.unstyled ? config.className : cn("pinfold", B, config.className),
|
|
75
|
+
style: { ...dimensionVars("accordion", dimensions), ...config.style },
|
|
76
|
+
"data-variant": a.variant,
|
|
77
|
+
"data-size": a.size,
|
|
78
|
+
"data-tone": a.tone,
|
|
79
|
+
"data-indicator-position": a.indicatorPosition,
|
|
80
|
+
"data-static-indicator": a.animateIndicator ? void 0 : "",
|
|
81
|
+
"data-dividers": a.dividers ? "" : void 0,
|
|
82
|
+
// Separated or filled rows with no gap join into one group (cards and ghost always touch).
|
|
83
|
+
"data-joined": (a.variant === "separated" || a.variant === "filled") && accordionRowsJoined(a.variant, dimensions.gap) ? "" : void 0,
|
|
84
|
+
"data-animate": a.animate ? "" : void 0,
|
|
85
|
+
"data-unstyled": a.unstyled ? "" : void 0,
|
|
86
|
+
"data-scroll": ((_a = config.dimensions) == null ? void 0 : _a.panelMaxHeight) != null ? "" : void 0,
|
|
87
|
+
"data-clamp": ((_b = config.dimensions) == null ? void 0 : _b.maxHeight) != null ? "" : void 0,
|
|
88
|
+
"data-until-found": a.hiddenUntilFound ? "" : void 0
|
|
89
|
+
}),
|
|
90
|
+
rootProps
|
|
91
|
+
)
|
|
92
|
+
);
|
|
93
|
+
return /* @__PURE__ */ React.createElement("div", { ...props }, api.items.map((item) => renderItem(ctx, item)));
|
|
94
|
+
}
|
|
95
|
+
function renderItem(ctx, item, extra) {
|
|
96
|
+
const { api, config } = ctx;
|
|
97
|
+
const props = api.getItemProps(
|
|
98
|
+
item,
|
|
99
|
+
mergeProps(slot(ctx, "item", { className: cls(ctx, `${B}__item`) }, item), extra != null ? extra : {})
|
|
100
|
+
);
|
|
101
|
+
const header = renderHeader(ctx, item);
|
|
102
|
+
const panel = renderPanel(ctx, item);
|
|
103
|
+
if (config.renderItem) {
|
|
104
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: item.id }, config.renderItem({ state: item, props, header, panel }));
|
|
105
|
+
}
|
|
106
|
+
return /* @__PURE__ */ React.createElement("div", { key: item.id, ...props }, header, panel);
|
|
107
|
+
}
|
|
108
|
+
function renderHeader(ctx, item, extra, children) {
|
|
109
|
+
const { api, a } = ctx;
|
|
110
|
+
const headerProps = api.getHeaderProps(
|
|
111
|
+
item,
|
|
112
|
+
slot(ctx, "header", { className: cls(ctx, `${B}__header`) }, item)
|
|
113
|
+
);
|
|
114
|
+
const triggerProps = api.getTriggerProps(
|
|
115
|
+
item,
|
|
116
|
+
mergeProps(slot(ctx, "trigger", { className: cls(ctx, `${B}__trigger`) }, item), extra != null ? extra : {})
|
|
117
|
+
);
|
|
118
|
+
delete headerProps.role;
|
|
119
|
+
delete headerProps["aria-level"];
|
|
120
|
+
const Heading = "h" + a.headingLevel;
|
|
121
|
+
return /* @__PURE__ */ React.createElement(Heading, { ...headerProps }, renderSlot(
|
|
122
|
+
ctx.config,
|
|
123
|
+
"trigger",
|
|
124
|
+
triggerProps,
|
|
125
|
+
item,
|
|
126
|
+
children != null ? children : /* @__PURE__ */ React.createElement(TriggerContent, { ctx, item }),
|
|
127
|
+
(props, kids) => /* @__PURE__ */ React.createElement("button", { ...props }, kids)
|
|
128
|
+
));
|
|
129
|
+
}
|
|
130
|
+
function TriggerContent({ ctx, item }) {
|
|
131
|
+
var _a, _b, _c, _d;
|
|
132
|
+
const { title, description, badge } = item.config;
|
|
133
|
+
const iconNode = resolveNode((_a = item.config.icon) != null ? _a : ctx.config.icon, item);
|
|
134
|
+
const endIconNode = resolveNode((_b = item.config.endIcon) != null ? _b : ctx.config.endIcon, item);
|
|
135
|
+
const descriptionNode = resolveNode(description, item);
|
|
136
|
+
const badgeNode = resolveNode(badge, item);
|
|
137
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, iconNode ? /* @__PURE__ */ React.createElement("span", { ...slot(ctx, "icon", { className: cls(ctx, `${B}__icon`), "aria-hidden": "true" }, item) }, iconNode) : null, /* @__PURE__ */ React.createElement("span", { ...slot(ctx, "label", { className: cls(ctx, `${B}__label`) }, item) }, /* @__PURE__ */ React.createElement("span", { ...slot(ctx, "title", { className: cls(ctx, `${B}__title`), ...overflowProps((_c = ctx.config.overflow) == null ? void 0 : _c.title, "wrap") }, item) }, resolveNode(title, item)), descriptionNode ? /* @__PURE__ */ React.createElement(
|
|
138
|
+
"span",
|
|
139
|
+
{
|
|
140
|
+
...slot(
|
|
141
|
+
ctx,
|
|
142
|
+
"description",
|
|
143
|
+
{ className: cls(ctx, `${B}__description`), ...overflowProps((_d = ctx.config.overflow) == null ? void 0 : _d.description, { lines: 2 }) },
|
|
144
|
+
item
|
|
145
|
+
)
|
|
146
|
+
},
|
|
147
|
+
descriptionNode
|
|
148
|
+
) : null), badgeNode ? /* @__PURE__ */ React.createElement("span", { ...slot(ctx, "badge", { className: cls(ctx, `${B}__badge`) }, item) }, badgeNode) : null, endIconNode ? /* @__PURE__ */ React.createElement("span", { ...slot(ctx, "endIcon", { className: cls(ctx, `${B}__end-icon`), "aria-hidden": "true" }, item) }, endIconNode) : null, renderIndicator(ctx, item));
|
|
149
|
+
}
|
|
150
|
+
function renderIndicator(ctx, item, extra) {
|
|
151
|
+
var _a;
|
|
152
|
+
const chosen = (_a = item.config.indicator) != null ? _a : ctx.a.indicator;
|
|
153
|
+
return renderSlot(
|
|
154
|
+
ctx.config,
|
|
155
|
+
"indicator",
|
|
156
|
+
mergeProps(
|
|
157
|
+
slot(ctx, "indicator", { className: cls(ctx, `${B}__indicator`), "aria-hidden": "true" }, item),
|
|
158
|
+
extra != null ? extra : {}
|
|
159
|
+
),
|
|
160
|
+
item,
|
|
161
|
+
null,
|
|
162
|
+
(props) => /* @__PURE__ */ React.createElement(Indicator, { ...props, indicator: chosen, state: item })
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
function Indicator({
|
|
166
|
+
indicator,
|
|
167
|
+
state,
|
|
168
|
+
...props
|
|
169
|
+
}) {
|
|
170
|
+
var _a;
|
|
171
|
+
if (indicator === "none") return null;
|
|
172
|
+
if (typeof indicator !== "string") {
|
|
173
|
+
const node = resolveNode(indicator, state);
|
|
174
|
+
return node ? /* @__PURE__ */ React.createElement("span", { ...props }, node) : null;
|
|
175
|
+
}
|
|
176
|
+
const glyph = (_a = GLYPHS[indicator != null ? indicator : "chevron"]) != null ? _a : GLYPHS.chevron;
|
|
177
|
+
return /* @__PURE__ */ React.createElement("span", { ...props }, /* @__PURE__ */ React.createElement("svg", { viewBox: "0 0 16 16", width: "1em", height: "1em", fill: "none", focusable: "false" }, /* @__PURE__ */ React.createElement("g", { stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }, glyph)));
|
|
178
|
+
}
|
|
179
|
+
function renderPanel(ctx, item, extra, children) {
|
|
180
|
+
const { api, a, config } = ctx;
|
|
181
|
+
const panelProps = api.getPanelProps(
|
|
182
|
+
item,
|
|
183
|
+
mergeProps(slot(ctx, "panel", { className: cls(ctx, `${B}__panel`) }, item), extra != null ? extra : {})
|
|
184
|
+
);
|
|
185
|
+
const body = children != null ? children : shouldMountPanel(a.mountPanels, item.open, ctx.everOpened.has(item.id)) ? resolveNode(item.config.content, item) : null;
|
|
186
|
+
return renderSlot(
|
|
187
|
+
config,
|
|
188
|
+
"panel",
|
|
189
|
+
panelProps,
|
|
190
|
+
item,
|
|
191
|
+
/* @__PURE__ */ React.createElement("div", { ...slot(ctx, "content", { className: cls(ctx, `${B}__content`) }, item) }, body),
|
|
192
|
+
(props, kids) => /* @__PURE__ */ React.createElement("div", { ...props }, /* @__PURE__ */ React.createElement("div", { className: cls(ctx, `${B}__panel-inner`), ref: ctx.findable(item) }, kids))
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
var cls = (ctx, name) => ctx.a.unstyled ? void 0 : name;
|
|
196
|
+
|
|
197
|
+
// src/accordion/useAccordion.tsx
|
|
198
|
+
function useAccordion(input) {
|
|
199
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
200
|
+
const ctx = usePinfold();
|
|
201
|
+
const config = ctx.defaults.accordion ? { ...ctx.defaults.accordion, ...defined(input) } : input;
|
|
202
|
+
const {
|
|
203
|
+
mode = "single",
|
|
204
|
+
collapsible = true,
|
|
205
|
+
disabled: allDisabled = false,
|
|
206
|
+
value: controlled,
|
|
207
|
+
defaultValue,
|
|
208
|
+
onValueChange,
|
|
209
|
+
onBeforeChange,
|
|
210
|
+
onItemToggle,
|
|
211
|
+
orientation = "vertical",
|
|
212
|
+
dir = ctx.dir,
|
|
213
|
+
loop = true,
|
|
214
|
+
syncWithHash = false,
|
|
215
|
+
id: idProp
|
|
216
|
+
} = config;
|
|
217
|
+
if (process.env.NODE_ENV !== "production") {
|
|
218
|
+
void import("../validate-WKHQNNGD.js").then((m) => m.validateAccordion(input, config));
|
|
219
|
+
}
|
|
220
|
+
const appearance = {
|
|
221
|
+
variant: (_a = config.variant) != null ? _a : "solid",
|
|
222
|
+
size: (_b = config.size) != null ? _b : ctx.size,
|
|
223
|
+
tone: (_c = config.tone) != null ? _c : ctx.tone,
|
|
224
|
+
indicator: (_d = config.indicator) != null ? _d : "chevron",
|
|
225
|
+
indicatorPosition: (_e = config.indicatorPosition) != null ? _e : "end",
|
|
226
|
+
animateIndicator: (_f = config.animateIndicator) != null ? _f : true,
|
|
227
|
+
headingLevel: (_g = config.headingLevel) != null ? _g : 3,
|
|
228
|
+
animate: (_h = config.animate) != null ? _h : !ctx.disableAnimation,
|
|
229
|
+
dividers: (_i = config.dividers) != null ? _i : true,
|
|
230
|
+
mountPanels: (_j = config.mountPanels) != null ? _j : config.unmountClosed ? "open" : "always",
|
|
231
|
+
hiddenUntilFound: (_k = config.hiddenUntilFound) != null ? _k : true,
|
|
232
|
+
unstyled: (_l = config.unstyled) != null ? _l : false
|
|
233
|
+
};
|
|
234
|
+
const headingLevel = appearance.headingLevel;
|
|
235
|
+
const baseId = useId(idProp);
|
|
236
|
+
const triggerRefs = React2.useRef([]);
|
|
237
|
+
const itemConfigs = React2.useMemo(
|
|
238
|
+
() => mapAccordionFields(Array.isArray(config.items) ? config.items : [], config.fields),
|
|
239
|
+
// `fields` is plain data: key it by content so an inline object does not remap every render.
|
|
240
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
241
|
+
[config.items, JSON.stringify(config.fields)]
|
|
242
|
+
);
|
|
243
|
+
const items = React2.useMemo(
|
|
244
|
+
() => itemConfigs.map((item, index) => {
|
|
245
|
+
var _a2, _b2;
|
|
246
|
+
const id = accordionRowId(item, index);
|
|
247
|
+
const disabled = allDisabled || !!item.disabled || ((_b2 = (_a2 = config.disabledIds) == null ? void 0 : _a2.indexOf(id)) != null ? _b2 : -1) !== -1;
|
|
248
|
+
return { id, index, disabled, config: item, ...accordionPartIds(baseId, id) };
|
|
249
|
+
}),
|
|
250
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
251
|
+
[itemConfigs, baseId, allDisabled, JSON.stringify(config.disabledIds)]
|
|
252
|
+
);
|
|
253
|
+
const [value, setValue] = useControllableState({
|
|
254
|
+
value: controlled,
|
|
255
|
+
defaultValue: () => initialAccordionValue(itemConfigs, defaultValue, mode)
|
|
256
|
+
});
|
|
257
|
+
const everOpened = React2.useRef(/* @__PURE__ */ new Set());
|
|
258
|
+
value.forEach((id) => everOpened.current.add(id));
|
|
259
|
+
const isOpen = React2.useCallback((id) => value.indexOf(id) !== -1, [value]);
|
|
260
|
+
const rules = { mode, collapsible, disabled: allDisabled };
|
|
261
|
+
const commit = useEvent((next, details) => {
|
|
262
|
+
if (!next) return false;
|
|
263
|
+
if ((onBeforeChange == null ? void 0 : onBeforeChange(details)) === false) return false;
|
|
264
|
+
setValue(next);
|
|
265
|
+
onValueChange == null ? void 0 : onValueChange(next, details);
|
|
266
|
+
if (details.id != null) onItemToggle == null ? void 0 : onItemToggle(details.id, details.open);
|
|
267
|
+
if (syncWithHash && details.id != null && (details.reason === "click" || details.reason === "keyboard")) {
|
|
268
|
+
writeHash(details.open ? details.id : null);
|
|
269
|
+
}
|
|
270
|
+
return true;
|
|
271
|
+
});
|
|
272
|
+
const change = useEvent(
|
|
273
|
+
(id, open, reason, event) => commit(setAccordionItem(value, items, id, open, rules), { id, open, reason, event })
|
|
274
|
+
);
|
|
275
|
+
const focusItem = useEvent((index) => {
|
|
276
|
+
var _a2;
|
|
277
|
+
(_a2 = triggerRefs.current[index]) == null ? void 0 : _a2.focus();
|
|
278
|
+
});
|
|
279
|
+
React2.useEffect(() => {
|
|
280
|
+
if (!syncWithHash) return;
|
|
281
|
+
const fromHash = () => {
|
|
282
|
+
var _a2, _b2;
|
|
283
|
+
const id = readHash();
|
|
284
|
+
const row = id != null ? items.find((i) => i.id === id) : void 0;
|
|
285
|
+
if (!row) return;
|
|
286
|
+
change(row.id, true, "hash");
|
|
287
|
+
(_b2 = (_a2 = triggerRefs.current[row.index]) == null ? void 0 : _a2.scrollIntoView) == null ? void 0 : _b2.call(_a2, { block: "start" });
|
|
288
|
+
};
|
|
289
|
+
fromHash();
|
|
290
|
+
window.addEventListener("hashchange", fromHash);
|
|
291
|
+
return () => window.removeEventListener("hashchange", fromHash);
|
|
292
|
+
}, [syncWithHash, items, change]);
|
|
293
|
+
const state = React2.useMemo(
|
|
294
|
+
() => items.map((item) => ({ ...item, open: isOpen(item.id) })),
|
|
295
|
+
[items, isOpen]
|
|
296
|
+
);
|
|
297
|
+
const onTriggerKeyDown = useEvent((event, index) => {
|
|
298
|
+
const next = accordionFocusTarget(event.key, index, items.length, { orientation, dir, loop });
|
|
299
|
+
if (next === null) return;
|
|
300
|
+
event.preventDefault();
|
|
301
|
+
focusItem(next);
|
|
302
|
+
});
|
|
303
|
+
const viewRef = React2.useRef(null);
|
|
304
|
+
const panels = React2.useRef(/* @__PURE__ */ new Map());
|
|
305
|
+
const accordionState = {
|
|
306
|
+
items: state,
|
|
307
|
+
value,
|
|
308
|
+
isOpen,
|
|
309
|
+
open: useEvent((id) => change(id, true, "api")),
|
|
310
|
+
close: useEvent((id) => change(id, false, "api")),
|
|
311
|
+
toggle: useEvent((id) => change(id, !isOpen(id), "api")),
|
|
312
|
+
openAll: useEvent(() => commit(openAllAccordion(value, items, rules), { open: true, reason: "api" })),
|
|
313
|
+
closeAll: useEvent(() => commit(closeAllAccordion(value, items, rules), { open: false, reason: "api" })),
|
|
314
|
+
focusItem,
|
|
315
|
+
render: (props) => renderRoot(viewRef.current, props),
|
|
316
|
+
getRootProps: (props) => mergeProps2(
|
|
317
|
+
{
|
|
318
|
+
"data-pinfold": "accordion",
|
|
319
|
+
"data-orientation": orientation,
|
|
320
|
+
"data-mode": mode,
|
|
321
|
+
"data-disabled": dataAttr(allDisabled),
|
|
322
|
+
dir
|
|
323
|
+
},
|
|
324
|
+
props
|
|
325
|
+
),
|
|
326
|
+
getItemProps: (item, props) => mergeProps2(
|
|
327
|
+
{
|
|
328
|
+
"data-state": item.open ? "open" : "closed",
|
|
329
|
+
"data-disabled": dataAttr(item.disabled),
|
|
330
|
+
"data-index": item.index
|
|
331
|
+
},
|
|
332
|
+
props
|
|
333
|
+
),
|
|
334
|
+
getHeaderProps: (item, props) => mergeProps2(
|
|
335
|
+
{
|
|
336
|
+
role: "heading",
|
|
337
|
+
"aria-level": headingLevel,
|
|
338
|
+
"data-state": item.open ? "open" : "closed"
|
|
339
|
+
},
|
|
340
|
+
props
|
|
341
|
+
),
|
|
342
|
+
getTriggerProps: (item, props) => mergeProps2(
|
|
343
|
+
{
|
|
344
|
+
type: "button",
|
|
345
|
+
id: item.triggerId,
|
|
346
|
+
"aria-expanded": item.open,
|
|
347
|
+
"aria-controls": item.panelId,
|
|
348
|
+
"aria-disabled": ariaAttr(item.disabled),
|
|
349
|
+
"data-state": item.open ? "open" : "closed",
|
|
350
|
+
"data-disabled": dataAttr(item.disabled),
|
|
351
|
+
ref: (node) => {
|
|
352
|
+
triggerRefs.current[item.index] = node;
|
|
353
|
+
},
|
|
354
|
+
onClick: (event) => {
|
|
355
|
+
if (item.disabled) {
|
|
356
|
+
event.preventDefault();
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
change(item.id, !isOpen(item.id), event.detail === 0 ? "keyboard" : "click", event);
|
|
360
|
+
},
|
|
361
|
+
onKeyDown: (event) => onTriggerKeyDown(event, item.index)
|
|
362
|
+
},
|
|
363
|
+
props
|
|
364
|
+
),
|
|
365
|
+
getPanelProps: (item, props) => mergeProps2(
|
|
366
|
+
{
|
|
367
|
+
id: item.panelId,
|
|
368
|
+
role: "region",
|
|
369
|
+
"aria-labelledby": item.triggerId,
|
|
370
|
+
"data-state": item.open ? "open" : "closed",
|
|
371
|
+
ref: (node) => trackPanel(panels.current, item, node, appearance.animate)
|
|
372
|
+
},
|
|
373
|
+
props
|
|
374
|
+
)
|
|
375
|
+
};
|
|
376
|
+
const buildParts = () => {
|
|
377
|
+
const pick = (props) => {
|
|
378
|
+
var _a2;
|
|
379
|
+
const rows = viewRef.current.api.items;
|
|
380
|
+
const found = props.index != null ? rows[props.index] : props.id != null ? rows.find((row) => row.id === props.id) : rows[0];
|
|
381
|
+
warnOnce(
|
|
382
|
+
__DEV__ && !found,
|
|
383
|
+
`Accordion: no row matches ${JSON.stringify((_a2 = props.id) != null ? _a2 : props.index)}. Sub-components address a row by \`id\` or \`index\`.`
|
|
384
|
+
);
|
|
385
|
+
return found;
|
|
386
|
+
};
|
|
387
|
+
const box = (props) => ({ className: props.className, style: props.style });
|
|
388
|
+
return {
|
|
389
|
+
Item: (props) => {
|
|
390
|
+
const item = pick(props);
|
|
391
|
+
return item ? renderItem(viewRef.current, item, box(props)) : null;
|
|
392
|
+
},
|
|
393
|
+
Trigger: (props) => {
|
|
394
|
+
const item = pick(props);
|
|
395
|
+
return item ? renderHeader(viewRef.current, item, box(props), props.children) : null;
|
|
396
|
+
},
|
|
397
|
+
Panel: (props) => {
|
|
398
|
+
const item = pick(props);
|
|
399
|
+
return item ? /* @__PURE__ */ React2.createElement(React2.Fragment, null, renderPanel(viewRef.current, item, box(props), props.children)) : null;
|
|
400
|
+
},
|
|
401
|
+
Indicator: (props) => {
|
|
402
|
+
const item = pick(props);
|
|
403
|
+
return item ? /* @__PURE__ */ React2.createElement(React2.Fragment, null, renderIndicator(viewRef.current, item, box(props))) : null;
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
};
|
|
407
|
+
const api = usePinfoldComponent(
|
|
408
|
+
"Accordion",
|
|
409
|
+
accordionState,
|
|
410
|
+
(props) => renderRoot(viewRef.current, props),
|
|
411
|
+
buildParts
|
|
412
|
+
);
|
|
413
|
+
const onFound = useEvent((id) => change(id, true, "find-in-page"));
|
|
414
|
+
const findable2 = (item) => (node) => untilFound(node, appearance.hiddenUntilFound && !item.open, appearance.animate, () => onFound(item.id));
|
|
415
|
+
viewRef.current = { api, config, a: appearance, everOpened: everOpened.current, findable: findable2 };
|
|
416
|
+
return api;
|
|
417
|
+
}
|
|
418
|
+
function trackPanel(map, item, node, animate) {
|
|
419
|
+
if (!node) return;
|
|
420
|
+
const prev = map.get(item.id);
|
|
421
|
+
map.set(item.id, { node, open: item.open, timer: prev == null ? void 0 : prev.timer });
|
|
422
|
+
if (!prev || prev.node !== node || prev.open === item.open || !animate) return;
|
|
423
|
+
if (prev.timer) clearTimeout(prev.timer);
|
|
424
|
+
node.setAttribute("data-transition", item.open ? "opening" : "closing");
|
|
425
|
+
const done = () => node.removeAttribute("data-transition");
|
|
426
|
+
map.get(item.id).timer = setTimeout(done, transitionMs(node));
|
|
427
|
+
}
|
|
428
|
+
var findable = /* @__PURE__ */ new WeakMap();
|
|
429
|
+
function untilFound(node, hide, animate, onFound) {
|
|
430
|
+
var _a;
|
|
431
|
+
if (!node) return;
|
|
432
|
+
const prev = findable.get(node);
|
|
433
|
+
findable.set(node, { onFound, hide });
|
|
434
|
+
if (!prev) node.addEventListener("beforematch", () => {
|
|
435
|
+
var _a2;
|
|
436
|
+
return (_a2 = findable.get(node)) == null ? void 0 : _a2.onFound();
|
|
437
|
+
});
|
|
438
|
+
if (!hide) {
|
|
439
|
+
if (node.hasAttribute("hidden")) node.removeAttribute("hidden");
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
if (node.getAttribute("hidden") === "until-found") return;
|
|
443
|
+
const apply = () => {
|
|
444
|
+
var _a2;
|
|
445
|
+
if ((_a2 = findable.get(node)) == null ? void 0 : _a2.hide) node.setAttribute("hidden", "until-found");
|
|
446
|
+
};
|
|
447
|
+
const wait = animate && prev && !prev.hide ? transitionMs((_a = node.parentElement) != null ? _a : node) : 0;
|
|
448
|
+
if (wait) setTimeout(apply, wait);
|
|
449
|
+
else apply();
|
|
450
|
+
}
|
|
451
|
+
function transitionMs(node) {
|
|
452
|
+
if (typeof getComputedStyle === "undefined") return 0;
|
|
453
|
+
const style = getComputedStyle(node);
|
|
454
|
+
const parse = (list) => list.split(",").map((s) => (s.trim().endsWith("ms") ? parseFloat(s) : parseFloat(s) * 1e3) || 0);
|
|
455
|
+
const durations = parse(style.transitionDuration || "0s");
|
|
456
|
+
const delays = parse(style.transitionDelay || "0s");
|
|
457
|
+
return Math.max(0, ...durations.map((d, i) => {
|
|
458
|
+
var _a;
|
|
459
|
+
return d + ((_a = delays[i]) != null ? _a : 0);
|
|
460
|
+
}));
|
|
461
|
+
}
|
|
462
|
+
function readHash() {
|
|
463
|
+
const raw = typeof location !== "undefined" ? location.hash.slice(1) : "";
|
|
464
|
+
if (!raw) return null;
|
|
465
|
+
try {
|
|
466
|
+
return decodeURIComponent(raw);
|
|
467
|
+
} catch (e) {
|
|
468
|
+
return raw;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function writeHash(id) {
|
|
472
|
+
if (typeof history === "undefined") return;
|
|
473
|
+
const url = location.pathname + location.search + (id != null ? "#" + encodeURIComponent(id) : "");
|
|
474
|
+
history.replaceState(history.state, "", url);
|
|
475
|
+
}
|
|
476
|
+
function defined(obj) {
|
|
477
|
+
const out = {};
|
|
478
|
+
for (const k in obj) if (obj[k] !== void 0) out[k] = obj[k];
|
|
479
|
+
return out;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// src/accordion/Accordion.tsx
|
|
483
|
+
function Accordion(config) {
|
|
484
|
+
return useAccordion(config).render();
|
|
485
|
+
}
|
|
486
|
+
Accordion.displayName = "Accordion";
|
|
487
|
+
export {
|
|
488
|
+
Accordion,
|
|
489
|
+
useAccordion
|
|
490
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var client_cjs = require('./client.cjs');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
27
|
+
|
|
28
|
+
// src/accordion/index.ts
|
|
29
|
+
function defineAccordion(config) {
|
|
30
|
+
const Tag = client_cjs.Accordion;
|
|
31
|
+
const Defined = ((props) => React__namespace.createElement(Tag, { ...config, ...props }));
|
|
32
|
+
Defined.config = config;
|
|
33
|
+
Defined.displayName = "DefinedAccordion";
|
|
34
|
+
return Defined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Object.defineProperty(exports, "Accordion", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
get: function () { return client_cjs.Accordion; }
|
|
40
|
+
});
|
|
41
|
+
Object.defineProperty(exports, "default", {
|
|
42
|
+
enumerable: true,
|
|
43
|
+
get: function () { return client_cjs.Accordion; }
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(exports, "useAccordion", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: function () { return client_cjs.useAccordion; }
|
|
48
|
+
});
|
|
49
|
+
exports.defineAccordion = defineAccordion;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { A as AccordionConfig, a as AccordionMappedConfig, b as AccordionApi, c as AnyAccordionConfig, d as AccordionRootProps } from '../types-N0Yo4zGa.cjs';
|
|
3
|
+
export { e as AccordionAppearanceConfig, f as AccordionBehaviourConfig, g as AccordionDimensions, h as AccordionGap, i as AccordionIndicator, j as AccordionItemConfig, k as AccordionItemId, l as AccordionItemState, m as AccordionNode, n as AccordionOptions, o as AccordionOverflow, p as AccordionPartProps, q as AccordionParts, r as AccordionRadius, s as AccordionSlot, t as AccordionState, u as AccordionValueDetails, v as AccordionVariant } from '../types-N0Yo4zGa.cjs';
|
|
4
|
+
import '@pinfold/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Thin JSX wrapper over `useAccordion()`, for one-off accordions that never
|
|
8
|
+
* need the controller. It adds nothing the hook does not already do.
|
|
9
|
+
*/
|
|
10
|
+
declare function Accordion<Id extends string = string>(config: AccordionConfig<Id>): React.ReactElement;
|
|
11
|
+
declare function Accordion<Row extends object>(config: AccordionMappedConfig<Row>): React.ReactElement;
|
|
12
|
+
declare namespace Accordion {
|
|
13
|
+
var displayName: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The accordion, as a hook that hands back a component.
|
|
18
|
+
*
|
|
19
|
+
* const Faq = useAccordion({ items });
|
|
20
|
+
* return <Faq className="mt-8" />;
|
|
21
|
+
*
|
|
22
|
+
* The same value is the controller (`Faq.toggle(id)`, `Faq.value`) and carries
|
|
23
|
+
* its own parts (`<Faq.Trigger id="a" />`) for layouts the config cannot
|
|
24
|
+
* express. One object, three levels of commitment.
|
|
25
|
+
*
|
|
26
|
+
* Implements the WAI-ARIA Accordion pattern: button triggers inside headings,
|
|
27
|
+
* `aria-expanded` / `aria-controls`, panels as labelled regions, and
|
|
28
|
+
* Arrow/Home/End navigation between headers. Behaviour rules live in
|
|
29
|
+
* `@pinfold/core` (accordion.logic.ts); this hook wires them to React.
|
|
30
|
+
*/
|
|
31
|
+
declare function useAccordion<Id extends string = string>(config: AccordionConfig<Id>): AccordionApi<Id>;
|
|
32
|
+
/** Raw records, mapped onto rows by `fields`. Ids come from the data, so they are `string`. */
|
|
33
|
+
declare function useAccordion<Row extends object>(config: AccordionMappedConfig<Row>): AccordionApi;
|
|
34
|
+
|
|
35
|
+
/** What `defineAccordion` returns: a component with the config baked in. */
|
|
36
|
+
type DefinedAccordion<Config = AnyAccordionConfig> = ((props: AccordionRootProps) => React.ReactElement) & {
|
|
37
|
+
config: Config;
|
|
38
|
+
displayName?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The non-hook twin of `useAccordion`, for Server Components (and anywhere a
|
|
42
|
+
* hook can't run). Same config, same tag:
|
|
43
|
+
*
|
|
44
|
+
* const Faq = defineAccordion({ items: await getFaq() });
|
|
45
|
+
* return <Faq />;
|
|
46
|
+
*
|
|
47
|
+
* The server renders the full HTML (every title and panel) and the client
|
|
48
|
+
* hydrates it. From a Server Component the config must be serialisable: plain
|
|
49
|
+
* data and server-rendered JSX, no functions. For a controller (`Faq.toggle`)
|
|
50
|
+
* use `useAccordion` in a client component.
|
|
51
|
+
*/
|
|
52
|
+
declare function defineAccordion<Id extends string = string>(config: AccordionConfig<Id>): DefinedAccordion<AccordionConfig<Id>>;
|
|
53
|
+
declare function defineAccordion<Row extends object>(config: AccordionMappedConfig<Row>): DefinedAccordion<AccordionMappedConfig<Row>>;
|
|
54
|
+
|
|
55
|
+
export { Accordion, AccordionApi, AccordionConfig, AccordionMappedConfig, AccordionRootProps, AnyAccordionConfig, Accordion as default, defineAccordion, useAccordion };
|
|
56
|
+
export type { DefinedAccordion };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { A as AccordionConfig, a as AccordionMappedConfig, b as AccordionApi, c as AnyAccordionConfig, d as AccordionRootProps } from '../types-N0Yo4zGa.js';
|
|
3
|
+
export { e as AccordionAppearanceConfig, f as AccordionBehaviourConfig, g as AccordionDimensions, h as AccordionGap, i as AccordionIndicator, j as AccordionItemConfig, k as AccordionItemId, l as AccordionItemState, m as AccordionNode, n as AccordionOptions, o as AccordionOverflow, p as AccordionPartProps, q as AccordionParts, r as AccordionRadius, s as AccordionSlot, t as AccordionState, u as AccordionValueDetails, v as AccordionVariant } from '../types-N0Yo4zGa.js';
|
|
4
|
+
import '@pinfold/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Thin JSX wrapper over `useAccordion()`, for one-off accordions that never
|
|
8
|
+
* need the controller. It adds nothing the hook does not already do.
|
|
9
|
+
*/
|
|
10
|
+
declare function Accordion<Id extends string = string>(config: AccordionConfig<Id>): React.ReactElement;
|
|
11
|
+
declare function Accordion<Row extends object>(config: AccordionMappedConfig<Row>): React.ReactElement;
|
|
12
|
+
declare namespace Accordion {
|
|
13
|
+
var displayName: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The accordion, as a hook that hands back a component.
|
|
18
|
+
*
|
|
19
|
+
* const Faq = useAccordion({ items });
|
|
20
|
+
* return <Faq className="mt-8" />;
|
|
21
|
+
*
|
|
22
|
+
* The same value is the controller (`Faq.toggle(id)`, `Faq.value`) and carries
|
|
23
|
+
* its own parts (`<Faq.Trigger id="a" />`) for layouts the config cannot
|
|
24
|
+
* express. One object, three levels of commitment.
|
|
25
|
+
*
|
|
26
|
+
* Implements the WAI-ARIA Accordion pattern: button triggers inside headings,
|
|
27
|
+
* `aria-expanded` / `aria-controls`, panels as labelled regions, and
|
|
28
|
+
* Arrow/Home/End navigation between headers. Behaviour rules live in
|
|
29
|
+
* `@pinfold/core` (accordion.logic.ts); this hook wires them to React.
|
|
30
|
+
*/
|
|
31
|
+
declare function useAccordion<Id extends string = string>(config: AccordionConfig<Id>): AccordionApi<Id>;
|
|
32
|
+
/** Raw records, mapped onto rows by `fields`. Ids come from the data, so they are `string`. */
|
|
33
|
+
declare function useAccordion<Row extends object>(config: AccordionMappedConfig<Row>): AccordionApi;
|
|
34
|
+
|
|
35
|
+
/** What `defineAccordion` returns: a component with the config baked in. */
|
|
36
|
+
type DefinedAccordion<Config = AnyAccordionConfig> = ((props: AccordionRootProps) => React.ReactElement) & {
|
|
37
|
+
config: Config;
|
|
38
|
+
displayName?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The non-hook twin of `useAccordion`, for Server Components (and anywhere a
|
|
42
|
+
* hook can't run). Same config, same tag:
|
|
43
|
+
*
|
|
44
|
+
* const Faq = defineAccordion({ items: await getFaq() });
|
|
45
|
+
* return <Faq />;
|
|
46
|
+
*
|
|
47
|
+
* The server renders the full HTML (every title and panel) and the client
|
|
48
|
+
* hydrates it. From a Server Component the config must be serialisable: plain
|
|
49
|
+
* data and server-rendered JSX, no functions. For a controller (`Faq.toggle`)
|
|
50
|
+
* use `useAccordion` in a client component.
|
|
51
|
+
*/
|
|
52
|
+
declare function defineAccordion<Id extends string = string>(config: AccordionConfig<Id>): DefinedAccordion<AccordionConfig<Id>>;
|
|
53
|
+
declare function defineAccordion<Row extends object>(config: AccordionMappedConfig<Row>): DefinedAccordion<AccordionMappedConfig<Row>>;
|
|
54
|
+
|
|
55
|
+
export { Accordion, AccordionApi, AccordionConfig, AccordionMappedConfig, AccordionRootProps, AnyAccordionConfig, Accordion as default, defineAccordion, useAccordion };
|
|
56
|
+
export type { DefinedAccordion };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Accordion } from './client.js';
|
|
2
|
+
export { Accordion, Accordion as default, useAccordion } from './client.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
// src/accordion/index.ts
|
|
6
|
+
function defineAccordion(config) {
|
|
7
|
+
const Tag = Accordion;
|
|
8
|
+
const Defined = ((props) => React.createElement(Tag, { ...config, ...props }));
|
|
9
|
+
Defined.config = config;
|
|
10
|
+
Defined.displayName = "DefinedAccordion";
|
|
11
|
+
return Defined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { defineAccordion };
|