@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.
Files changed (41) hide show
  1. package/README.md +58 -2
  2. package/accordion/lazy/package.json +6 -0
  3. package/accordion/package.json +6 -0
  4. package/dist/accordion/client.cjs +491 -0
  5. package/dist/accordion/client.d.cts +34 -0
  6. package/dist/accordion/client.d.ts +34 -0
  7. package/dist/accordion/client.js +490 -0
  8. package/dist/accordion/index.cjs +49 -0
  9. package/dist/accordion/index.d.cts +56 -0
  10. package/dist/accordion/index.d.ts +56 -0
  11. package/dist/accordion/index.js +14 -0
  12. package/dist/accordion/lazy.cjs +17 -0
  13. package/dist/accordion/lazy.d.cts +16 -0
  14. package/dist/accordion/lazy.d.ts +16 -0
  15. package/dist/accordion/lazy.js +16 -0
  16. package/dist/chunk-5ZMK623A.js +61 -0
  17. package/dist/chunk-BPPCPHHU.js +70 -0
  18. package/dist/chunk-DQWSDHRY.cjs +71 -0
  19. package/dist/chunk-Q232PTPW.js +115 -0
  20. package/dist/chunk-RJPT3NTP.cjs +62 -0
  21. package/dist/chunk-VPKVOJHA.cjs +116 -0
  22. package/dist/client.cjs +30 -0
  23. package/dist/client.d.cts +120 -0
  24. package/dist/client.d.ts +120 -0
  25. package/dist/client.js +29 -0
  26. package/dist/index.cjs +52 -0
  27. package/dist/index.d.cts +123 -0
  28. package/dist/index.d.ts +123 -0
  29. package/dist/index.js +10 -0
  30. package/dist/types-CkcgnWwL.d.cts +367 -0
  31. package/dist/types-CkcgnWwL.d.ts +367 -0
  32. package/dist/types-N0Yo4zGa.d.cts +374 -0
  33. package/dist/types-N0Yo4zGa.d.ts +374 -0
  34. package/dist/validate-EQHBH4NH.cjs +42 -0
  35. package/dist/validate-WKHQNNGD.js +41 -0
  36. package/llms-full.txt +140 -0
  37. package/llms.txt +26 -0
  38. package/package.json +92 -4
  39. package/registry/accordion.json +20 -0
  40. package/registry/registry.json +25 -0
  41. 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 };