@marigold/components 16.1.0 → 17.0.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.
@@ -0,0 +1,431 @@
1
+ import { Button, Checkbox, CheckboxContext, CheckboxGroup, CheckboxGroupStateContext, Disclosure, DisclosurePanel, FieldError, FieldErrorContext, Heading, Label, Provider, Text, TextContext } from "react-aria-components";
2
+ import { cn, createWidthVar, isFraction, useClassNames } from "@marigold/system";
3
+ import { Children, createContext, forwardRef, isValidElement, useContext, useState } from "react";
4
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+ import { useLocalizedStringFormatter } from "@react-aria/i18n";
6
+ import { useId } from "@react-aria/utils";
7
+
8
+ //#region src/intl/messages.ts
9
+ const intlMessages = {
10
+ "de-DE": {
11
+ bulkActionsAriaLabel: "Massenaktionen",
12
+ cancel: "Abbrechen",
13
+ close: "Schließen",
14
+ clearSelectionAriaLabel: "Auswahl löschen",
15
+ dropZoneLabel: "Dateien hierher ziehen",
16
+ edit: "Bearbeiten",
17
+ editCell: "Zelle bearbeiten",
18
+ help: "Hilfe",
19
+ hiddenBreadcrumbs: "Diese Breadcrumbs sind ausgeblendet",
20
+ items: "Elemente",
21
+ loadingMessage: "Lade...",
22
+ moreInfo: "Mehr Informationen",
23
+ noResultsFound: "Kein Ergebnis gefunden",
24
+ save: "Speichern",
25
+ removeAll: "Alle entfernen",
26
+ removeFile: "Datei entfernen",
27
+ showLess: "Weniger anzeigen",
28
+ showLessCount: "{count} weniger anzeigen",
29
+ showMore: "Mehr anzeigen",
30
+ showMoreCount: "{count} weitere anzeigen",
31
+ uploadLabel: "Hochladen"
32
+ },
33
+ "en-US": {
34
+ bulkActionsAriaLabel: "Bulk Actions",
35
+ cancel: "Cancel",
36
+ close: "Close",
37
+ clearSelectionAriaLabel: "Clear selection",
38
+ dropZoneLabel: "Drop files here",
39
+ edit: "Edit",
40
+ editCell: "Edit cell",
41
+ help: "Help",
42
+ hiddenBreadcrumbs: "These breadcrumbs are hidden",
43
+ items: "Items",
44
+ loadingMessage: "Loading...",
45
+ moreInfo: "More information",
46
+ noResultsFound: "No result found",
47
+ save: "Save",
48
+ removeAll: "Remove all",
49
+ removeFile: "Remove file",
50
+ showLess: "Show less",
51
+ showLessCount: "Show {count} less",
52
+ showMore: "Show more",
53
+ showMoreCount: "Show {count} more",
54
+ uploadLabel: "Upload"
55
+ }
56
+ };
57
+
58
+ //#endregion
59
+ //#region src/icons/TriangleAlert.tsx
60
+ const TriangleAlert = ({ size = 24, className, ...props }) => /* @__PURE__ */ jsxs("svg", {
61
+ xmlns: "http://www.w3.org/2000/svg",
62
+ width: size,
63
+ height: size,
64
+ viewBox: "0 0 24 24",
65
+ fill: "none",
66
+ stroke: "currentColor",
67
+ strokeWidth: "2",
68
+ strokeLinecap: "round",
69
+ strokeLinejoin: "round",
70
+ className: cn("shrink-0", className),
71
+ ...props,
72
+ children: [
73
+ /* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
74
+ /* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
75
+ /* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
76
+ ]
77
+ });
78
+
79
+ //#endregion
80
+ //#region src/HelpText/HelpText.tsx
81
+ const HelpText = ({ variant, size, description, errorMessage, ...props }) => {
82
+ const classNames = useClassNames({
83
+ component: "HelpText",
84
+ variant,
85
+ size
86
+ });
87
+ const ctx = useContext(FieldErrorContext);
88
+ if (!description && !ctx?.isInvalid) return null;
89
+ return /* @__PURE__ */ jsxs("div", {
90
+ className: cn(classNames.container),
91
+ children: [/* @__PURE__ */ jsx(FieldError, {
92
+ ...props,
93
+ className: "flex flex-col",
94
+ children: (validation) => {
95
+ /**
96
+ * Prefer custom error messages, fallback to native errors ones.
97
+ *
98
+ * Note that we can not merge custom and native error messages,
99
+ * because we can not distinguish the type of error messages
100
+ * in the native ones since it is just an array of strings.
101
+ */
102
+ const messages = (typeof errorMessage === "function" ? errorMessage(validation) : errorMessage) || validation.validationErrors;
103
+ return Array.isArray(messages) ? messages.map((msg, idx) => /* @__PURE__ */ jsxs("div", {
104
+ className: "flex items-center justify-start gap-1",
105
+ children: [/* @__PURE__ */ jsx(TriangleAlert, { className: cn("h-4 w-4 shrink-0", classNames.icon) }), msg]
106
+ }, idx)) : /* @__PURE__ */ jsxs("div", {
107
+ className: "flex items-start justify-start gap-1",
108
+ children: [/* @__PURE__ */ jsx(TriangleAlert, { className: cn("h-4 w-4 shrink-0", classNames.icon) }), messages]
109
+ });
110
+ }
111
+ }), ctx && ctx.isInvalid ? null : /* @__PURE__ */ jsx(Text, {
112
+ slot: "description",
113
+ children: description
114
+ })]
115
+ });
116
+ };
117
+
118
+ //#endregion
119
+ //#region src/Label/Label.tsx
120
+ const _Label = ({ size, variant, children, ...props }) => {
121
+ const className = useClassNames({
122
+ component: "Label",
123
+ size,
124
+ variant
125
+ });
126
+ return /* @__PURE__ */ jsx(Label, {
127
+ ...props,
128
+ className: cn(className, "inline-flex"),
129
+ children
130
+ });
131
+ };
132
+
133
+ //#endregion
134
+ //#region src/FieldBase/FieldBase.tsx
135
+ const fixedForwardRef = forwardRef;
136
+ const _FieldBase = (props, ref) => {
137
+ const { as: Component$1 = "div", children, label, size, variant, width: width$1, description, errorMessage, className, ...rest } = props;
138
+ const classNames = useClassNames({
139
+ component: "Field",
140
+ variant,
141
+ size
142
+ });
143
+ const isFractionWidth = width$1 ? isFraction(`${width$1}`) : false;
144
+ return /* @__PURE__ */ jsxs(Component$1, {
145
+ ref,
146
+ className: cn(
147
+ "group/field flex min-w-0 flex-col",
148
+ /**
149
+ * Width handling strategy:
150
+ * - For fixed widths (numeric scale values) and keyword widths (fit, full): Use `w-auto` to prevent layout shifts
151
+ * - For fraction widths (e.g., "1/2", "2/3"): Use the corresponding Tailwind class
152
+ * (e.g., `w-1/2`) which allows the field to properly respond to its container's width
153
+ */
154
+ width$1 && !isFractionWidth ? "w-auto" : `w-(--container-width)`,
155
+ classNames,
156
+ className
157
+ ),
158
+ style: {
159
+ ...createWidthVar("container-width", width$1 ? `${width$1}` : "full"),
160
+ ...createWidthVar("field-width", width$1 && !isFractionWidth ? `${width$1}` : "full")
161
+ },
162
+ "data-required": props.isRequired ? true : void 0,
163
+ "data-error": props.isInvalid ? true : void 0,
164
+ ...rest,
165
+ children: [
166
+ label ? /* @__PURE__ */ jsx(_Label, {
167
+ variant,
168
+ size,
169
+ children: label
170
+ }) : null,
171
+ children,
172
+ /* @__PURE__ */ jsx(HelpText, {
173
+ variant,
174
+ size,
175
+ description,
176
+ errorMessage
177
+ })
178
+ ]
179
+ });
180
+ };
181
+ const FieldBase = fixedForwardRef(_FieldBase);
182
+
183
+ //#endregion
184
+ //#region src/icons/Check.tsx
185
+ const Check = ({ size = 24, className, ...props }) => /* @__PURE__ */ jsx("svg", {
186
+ xmlns: "http://www.w3.org/2000/svg",
187
+ width: size,
188
+ height: size,
189
+ viewBox: "0 0 24 24",
190
+ fill: "none",
191
+ stroke: "currentColor",
192
+ strokeWidth: "2",
193
+ strokeLinecap: "round",
194
+ strokeLinejoin: "round",
195
+ className: cn("shrink-0", className),
196
+ ...props,
197
+ children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" })
198
+ });
199
+
200
+ //#endregion
201
+ //#region src/Collapsible/Context.tsx
202
+ const CollapsibleContext = createContext(void 0);
203
+ const CollapsibleProvider = ({ value, children }) => /* @__PURE__ */ jsx(CollapsibleContext.Provider, {
204
+ value,
205
+ children
206
+ });
207
+
208
+ //#endregion
209
+ //#region src/Collapsible/CollapsibleContent.tsx
210
+ const CollapsibleContent = ({ variant, size, children, ...props }) => {
211
+ const classNames = useClassNames({
212
+ component: "Collapsible",
213
+ variant,
214
+ size,
215
+ context: CollapsibleContext
216
+ });
217
+ return /* @__PURE__ */ jsx(DisclosurePanel, {
218
+ ...props,
219
+ className: classNames.content,
220
+ children
221
+ });
222
+ };
223
+
224
+ //#endregion
225
+ //#region src/Collapsible/CollapsibleTrigger.tsx
226
+ const CollapsibleTrigger = ({ variant, size, children, level, ...props }) => {
227
+ const classNames = useClassNames({
228
+ component: "Collapsible",
229
+ variant,
230
+ size,
231
+ context: CollapsibleContext
232
+ });
233
+ return /* @__PURE__ */ jsx(Heading, {
234
+ level,
235
+ children: /* @__PURE__ */ jsx(Button, {
236
+ ...props,
237
+ slot: "trigger",
238
+ className: classNames.trigger,
239
+ children
240
+ })
241
+ });
242
+ };
243
+
244
+ //#endregion
245
+ //#region src/Collapsible/Collapsible.tsx
246
+ const Collapsible = ({ variant, size, children, unstyled, ...props }) => {
247
+ const classNames = useClassNames({
248
+ component: "Collapsible",
249
+ variant,
250
+ size
251
+ });
252
+ return /* @__PURE__ */ jsx(CollapsibleProvider, {
253
+ value: {
254
+ variant,
255
+ size
256
+ },
257
+ children: /* @__PURE__ */ jsx(Disclosure, {
258
+ ...props,
259
+ className: cn(classNames.container, unstyled && "expanded:contents expanded:[&_[role=group]]:contents"),
260
+ children
261
+ })
262
+ });
263
+ };
264
+ Collapsible.Trigger = CollapsibleTrigger;
265
+ Collapsible.Content = CollapsibleContent;
266
+
267
+ //#endregion
268
+ //#region src/Collapsible/More.tsx
269
+ const More = ({ children, defaultExpanded = false, unstyled = true, showCount = false, ...props }) => {
270
+ /**
271
+ * We need to add state here, because toggling on a checkbox will
272
+ * force a rerender and without the state the <Collapsible> will be collapsed.
273
+ */
274
+ const [isExpanded, setIsExpanded] = useState(defaultExpanded);
275
+ const stringFormatter = useLocalizedStringFormatter(intlMessages, "marigold");
276
+ const count = `${Children.count(children)}`;
277
+ return /* @__PURE__ */ jsxs(Collapsible, {
278
+ variant: "link",
279
+ unstyled,
280
+ isExpanded,
281
+ ...props,
282
+ children: [/* @__PURE__ */ jsx(Collapsible.Content, { children }), /* @__PURE__ */ jsx(Collapsible.Trigger, {
283
+ onPress: () => setIsExpanded(!isExpanded),
284
+ children: isExpanded ? stringFormatter.format(showCount ? "showLessCount" : "showLess").replace("{count}", count) : stringFormatter.format(showCount ? "showMoreCount" : "showMore").replace("{count}", count)
285
+ })]
286
+ });
287
+ };
288
+
289
+ //#endregion
290
+ //#region src/utils/children.utils.ts
291
+ const splitChildren = (children, at) => {
292
+ const childArray = Children.toArray(children);
293
+ if (at === void 0) return [childArray, []];
294
+ return [childArray.slice(0, at), childArray.slice(at)];
295
+ };
296
+
297
+ //#endregion
298
+ //#region src/Checkbox/Context.tsx
299
+ const CheckboxGroupContext = createContext(null);
300
+ const useCheckboxGroupContext = () => useContext(CheckboxGroupContext);
301
+
302
+ //#endregion
303
+ //#region src/Checkbox/CheckboxGroup.tsx
304
+ const CollapsibleGroup = ({ children }) => {
305
+ const state = useContext(CheckboxGroupStateContext);
306
+ if (!children || children.length === 0) return null;
307
+ return /* @__PURE__ */ jsx(More, {
308
+ defaultExpanded: children.some((child) => isValidElement(child) && state.value.includes(child.props.value)),
309
+ showCount: true,
310
+ children
311
+ });
312
+ };
313
+ const _CheckboxGroup = ({ children, variant, size, required, disabled, readOnly, error, width: width$1, orientation = "vertical", collapseAt, ...rest }) => {
314
+ const classNames = useClassNames({
315
+ component: "Checkbox",
316
+ variant,
317
+ size,
318
+ className: { group: "gap-x-2" }
319
+ });
320
+ const props = {
321
+ className: classNames.group,
322
+ isRequired: required,
323
+ isDisabled: disabled,
324
+ isReadOnly: readOnly,
325
+ isInvalid: error,
326
+ ...rest
327
+ };
328
+ const [visibleChildren, collapsedChildren] = splitChildren(children, collapseAt);
329
+ return /* @__PURE__ */ jsx(FieldBase, {
330
+ as: CheckboxGroup,
331
+ width: width$1,
332
+ ...props,
333
+ children: /* @__PURE__ */ jsx("div", {
334
+ role: "presentation",
335
+ "data-orientation": orientation,
336
+ className: cn(classNames.group, "group/checkboxgroup flex items-start", orientation === "vertical" ? "flex-col gap-[0.5ch]" : "flex-row gap-[1.5ch]"),
337
+ children: /* @__PURE__ */ jsxs(CheckboxGroupContext.Provider, {
338
+ value: {
339
+ width: width$1,
340
+ variant,
341
+ size
342
+ },
343
+ children: [visibleChildren, /* @__PURE__ */ jsx(CollapsibleGroup, { children: collapsedChildren })]
344
+ })
345
+ })
346
+ });
347
+ };
348
+
349
+ //#endregion
350
+ //#region src/icons/Minus.tsx
351
+ const Minus = ({ size = 24, className, ...props }) => /* @__PURE__ */ jsx("svg", {
352
+ xmlns: "http://www.w3.org/2000/svg",
353
+ width: size,
354
+ height: size,
355
+ viewBox: "0 0 24 24",
356
+ fill: "none",
357
+ stroke: "currentColor",
358
+ strokeWidth: "2",
359
+ strokeLinecap: "round",
360
+ strokeLinejoin: "round",
361
+ className: cn("shrink-0", className),
362
+ ...props,
363
+ children: /* @__PURE__ */ jsx("path", { d: "M5 12h14" })
364
+ });
365
+
366
+ //#endregion
367
+ //#region src/Checkbox/Checkbox.tsx
368
+ const Field = ({ description, children }) => {
369
+ const className = useClassNames({ component: "Field" });
370
+ const descriptionId = useId();
371
+ if (!description) return children;
372
+ return /* @__PURE__ */ jsx("div", {
373
+ className,
374
+ children: /* @__PURE__ */ jsxs(Provider, {
375
+ values: [[CheckboxContext, { "aria-describedby": descriptionId }], [TextContext, { id: descriptionId }]],
376
+ children: [children, /* @__PURE__ */ jsx(HelpText, { description })]
377
+ })
378
+ });
379
+ };
380
+ const Icon = ({ className, checked, indeterminate, ...props }) => {
381
+ return /* @__PURE__ */ jsx("div", {
382
+ "aria-hidden": "true",
383
+ className: cn("flex shrink-0 grow-0 basis-4 items-center justify-center", "h-4 w-4 p-px", "bg-white", "rounded-[3px] border border-solid border-black", className),
384
+ ...props,
385
+ children: indeterminate ? /* @__PURE__ */ jsx(Minus, {
386
+ size: "12",
387
+ strokeWidth: "4"
388
+ }) : checked ? /* @__PURE__ */ jsx(Check, {
389
+ size: "12",
390
+ strokeWidth: "4"
391
+ }) : null
392
+ });
393
+ };
394
+ const _Checkbox = forwardRef(({ error, disabled, readOnly, required, checked, defaultChecked, indeterminate, variant, size, label, description, ...rest }, ref) => {
395
+ const props = {
396
+ isIndeterminate: indeterminate,
397
+ isDisabled: disabled,
398
+ isReadOnly: readOnly,
399
+ isRequired: required,
400
+ isInvalid: error,
401
+ isSelected: checked,
402
+ defaultSelected: defaultChecked,
403
+ ...rest
404
+ };
405
+ const group = useCheckboxGroupContext();
406
+ const classNames = useClassNames({
407
+ component: "Checkbox",
408
+ variant: variant || group?.variant,
409
+ size: size || group?.size
410
+ });
411
+ return /* @__PURE__ */ jsx(Field, {
412
+ description,
413
+ children: /* @__PURE__ */ jsx(Checkbox, {
414
+ ref,
415
+ className: cn("group/checkbox flex items-center", "cursor-pointer data-disabled:cursor-not-allowed", classNames.container),
416
+ ...props,
417
+ children: ({ isSelected, isIndeterminate }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Icon, {
418
+ checked: isSelected,
419
+ indeterminate: isIndeterminate,
420
+ className: classNames.checkbox
421
+ }), label && /* @__PURE__ */ jsx("div", {
422
+ className: classNames.label,
423
+ children: label
424
+ })] })
425
+ })
426
+ });
427
+ });
428
+ _Checkbox.Group = _CheckboxGroup;
429
+
430
+ //#endregion
431
+ export { More as a, FieldBase as c, TriangleAlert as d, intlMessages as f, splitChildren as i, _Label as l, Minus as n, Collapsible as o, _CheckboxGroup as r, Check as s, _Checkbox as t, HelpText as u };