@carlonicora/nextjs-jsonapi 3.5.7 → 3.5.9

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 (30) hide show
  1. package/dist/{BlockNoteEditor-PZ5HOXFK.mjs → BlockNoteEditor-5AQQQQY3.mjs} +2 -2
  2. package/dist/{BlockNoteEditor-JSZ2YZVY.js → BlockNoteEditor-EWMWY4SK.js} +9 -9
  3. package/dist/{BlockNoteEditor-JSZ2YZVY.js.map → BlockNoteEditor-EWMWY4SK.js.map} +1 -1
  4. package/dist/billing/index.js +333 -333
  5. package/dist/billing/index.mjs +1 -1
  6. package/dist/{chunk-N73QMKQU.js → chunk-EJIWXCXI.js} +319 -213
  7. package/dist/chunk-EJIWXCXI.js.map +1 -0
  8. package/dist/{chunk-C7I6YFTA.mjs → chunk-OE2WEAPU.mjs} +126 -20
  9. package/dist/chunk-OE2WEAPU.mjs.map +1 -0
  10. package/dist/client/index.js +2 -2
  11. package/dist/client/index.mjs +1 -1
  12. package/dist/components/index.d.mts +21 -1
  13. package/dist/components/index.d.ts +21 -1
  14. package/dist/components/index.js +4 -2
  15. package/dist/components/index.js.map +1 -1
  16. package/dist/components/index.mjs +3 -1
  17. package/dist/contexts/index.js +2 -2
  18. package/dist/contexts/index.mjs +1 -1
  19. package/dist/features/help/index.js +31 -31
  20. package/dist/features/help/index.mjs +1 -1
  21. package/dist/features/tokenusage/index.js +75 -75
  22. package/dist/features/tokenusage/index.mjs +1 -1
  23. package/package.json +1 -1
  24. package/src/components/forms/EditorSheet.tsx +44 -22
  25. package/src/components/forms/FileUploader.tsx +18 -2
  26. package/src/components/forms/MultiFileUploader.tsx +23 -5
  27. package/src/components/forms/index.ts +1 -1
  28. package/dist/chunk-C7I6YFTA.mjs.map +0 -1
  29. package/dist/chunk-N73QMKQU.js.map +0 -1
  30. /package/dist/{BlockNoteEditor-PZ5HOXFK.mjs.map → BlockNoteEditor-5AQQQQY3.mjs.map} +0 -0
@@ -65,12 +65,23 @@ function resolveTriggerIsNativeButton(trigger: ReactNode): boolean {
65
65
  * base `data-[side=left]:sm:max-w-sm`.
66
66
  */
67
67
  // rtl-ok: keyed to the resolved physical side, not to a writing direction
68
+ /**
69
+ * On a phone an editor IS the page. SheetContent's base is `w-3/4`, which
70
+ * leaves a dead 25% strip of the page showing behind the form and squeezes
71
+ * every field — so each size takes the full width and hands over to its
72
+ * `sm:max-w-*` cap from the `sm` breakpoint up. Same width utility and same
73
+ * variant as the base, so `cn`'s tailwind-merge replaces it rather than
74
+ * fighting it on specificity.
75
+ */
76
+ // rtl-ok: keyed to the resolved physical side, not to a writing direction
77
+ const fullWidthOnMobile = "data-[side=right]:w-full data-[side=left]:w-full";
78
+
68
79
  const sizeClasses: Record<EditorSheetSize, string> = {
69
- sm: "data-[side=right]:sm:max-w-2xl data-[side=left]:sm:max-w-2xl",
70
- md: "data-[side=right]:sm:max-w-3xl data-[side=left]:sm:max-w-3xl",
71
- lg: "data-[side=right]:sm:max-w-5xl data-[side=left]:sm:max-w-5xl",
72
- xl: "data-[side=right]:sm:max-w-7xl data-[side=left]:sm:max-w-7xl",
73
- "2xl": "data-[side=right]:sm:!max-w-[min(96rem,90vw)] data-[side=left]:sm:!max-w-[min(96rem,90vw)]",
80
+ sm: `${fullWidthOnMobile} data-[side=right]:sm:max-w-2xl data-[side=left]:sm:max-w-2xl`,
81
+ md: `${fullWidthOnMobile} data-[side=right]:sm:max-w-3xl data-[side=left]:sm:max-w-3xl`,
82
+ lg: `${fullWidthOnMobile} data-[side=right]:sm:max-w-5xl data-[side=left]:sm:max-w-5xl`,
83
+ xl: `${fullWidthOnMobile} data-[side=right]:sm:max-w-7xl data-[side=left]:sm:max-w-7xl`,
84
+ "2xl": `${fullWidthOnMobile} data-[side=right]:sm:!max-w-[min(96rem,90vw)] data-[side=left]:sm:!max-w-[min(96rem,90vw)]`,
74
85
  };
75
86
 
76
87
  export type EditorSheetProps<T extends FieldValues> = {
@@ -261,23 +272,34 @@ export function EditorSheet<T extends FieldValues>({
261
272
  // warned on every native-button trigger).
262
273
  <SheetTrigger nativeButton={resolveTriggerIsNativeButton(trigger)} render={trigger as ReactElement} />
263
274
  ) : (
264
- <SheetTrigger>
265
- {isEdit ? (
266
- <Button
267
- render={<div />}
268
- nativeButton={false}
269
- size="sm"
270
- variant="ghost"
271
- className="text-muted-foreground"
272
- >
273
- <PencilIcon />
274
- </Button>
275
- ) : (
276
- <Button render={<div />} nativeButton={false} size="sm" variant="outline">
277
- {t("ui.buttons.create")}
278
- </Button>
279
- )}
280
- </SheetTrigger>
275
+ // The default trigger goes through `render` for the SAME reason the
276
+ // caller-supplied one above does. As CHILDREN, the Button rendered a
277
+ // second `role="button"` inside SheetTrigger's own button: two nodes
278
+ // with one accessible name, which a screen reader announces as a
279
+ // button inside a button and which makes
280
+ // `getByRole("button", { name })` ambiguous (e2e DRQ-01 failed strict
281
+ // mode on exactly this). `nativeButton={false}` because both variants
282
+ // render a <div>, matching the element the trigger actually emits.
283
+ <SheetTrigger
284
+ nativeButton={false}
285
+ render={
286
+ isEdit ? (
287
+ <Button
288
+ render={<div />}
289
+ nativeButton={false}
290
+ size="sm"
291
+ variant="ghost"
292
+ className="text-muted-foreground"
293
+ >
294
+ <PencilIcon />
295
+ </Button>
296
+ ) : (
297
+ <Button render={<div />} nativeButton={false} size="sm" variant="outline">
298
+ {t("ui.buttons.create")}
299
+ </Button>
300
+ )
301
+ }
302
+ />
281
303
  ))}
282
304
  <SheetContent side="end" className={sizeClasses[size]}>
283
305
  <SheetHeader className="border-b px-6 py-4">
@@ -112,11 +112,27 @@ export const FileUploader = forwardRef<HTMLDivElement, FileUploaderProps & React
112
112
 
113
113
  const handleKeyDown = useCallback(
114
114
  (e: React.KeyboardEvent<HTMLDivElement>) => {
115
+ if (!value) return;
116
+
117
+ // Only swallow the keys this component actually handles. Blanket
118
+ // preventDefault() killed Space / PageDown / arrow scrolling for as long
119
+ // as focus was anywhere inside the uploader — the page simply stopped
120
+ // responding to the keyboard while a file was selected.
121
+ const handledKeys = [
122
+ "ArrowLeft",
123
+ "ArrowRight",
124
+ "ArrowUp",
125
+ "ArrowDown",
126
+ "Enter",
127
+ "Space",
128
+ "Delete",
129
+ "Backspace",
130
+ "Escape",
131
+ ];
132
+ if (!handledKeys.includes(e.key)) return;
115
133
  e.preventDefault();
116
134
  e.stopPropagation();
117
135
 
118
- if (!value) return;
119
-
120
136
  const moveNext = () => {
121
137
  const nextIndex = activeIndex + 1;
122
138
  setActiveIndex(nextIndex > value.length - 1 ? 0 : nextIndex);
@@ -10,18 +10,31 @@ import { FileInput, FileUploader } from "./FileUploader";
10
10
  type MultiFileUploaderProps = {
11
11
  files: File[];
12
12
  setFiles: (files: File[]) => void;
13
+ /**
14
+ * Let one trip through the picker return several files. OPT-IN, and it stays
15
+ * that way: every existing caller was written against one-file-at-a-time, so
16
+ * flipping the default would change behaviour in every app consuming this
17
+ * package to suit whichever one asked last.
18
+ */
19
+ multiple?: boolean;
20
+ /**
21
+ * Extra classes for the tile grid — density is the caller's business. The
22
+ * default is one column on the smallest screens, which suits a desktop form;
23
+ * a phone-first caller can ask for more columns without moving the default
24
+ * out from under anyone else.
25
+ */
26
+ className?: string;
13
27
  };
14
28
 
15
29
  const dropzone = {
16
- multiple: false,
17
30
  maxSize: 100 * 1024 * 1024,
18
31
  preventDropOnDocument: false,
19
32
  accept: {
20
33
  "application/images": [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".docx", ".xslx", ".pdf", ".txt", ".md"],
21
34
  },
22
- } satisfies DropzoneOptions;
35
+ } satisfies Omit<DropzoneOptions, "multiple">;
23
36
 
24
- export default function MultiFileUploader({ files, setFiles }: MultiFileUploaderProps) {
37
+ export default function MultiFileUploader({ files, setFiles, multiple = false, className }: MultiFileUploaderProps) {
25
38
  const uploadFiles = (newFiles: File[] | null) => {
26
39
  if (!newFiles) return;
27
40
 
@@ -33,11 +46,16 @@ export default function MultiFileUploader({ files, setFiles }: MultiFileUploader
33
46
  };
34
47
 
35
48
  return (
36
- <div className="grid w-full grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6">
49
+ <div
50
+ className={cn(
51
+ "grid w-full grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6",
52
+ className,
53
+ )}
54
+ >
37
55
  <FileUploader
38
56
  value={files}
39
57
  onValueChange={uploadFiles}
40
- dropzoneOptions={dropzone}
58
+ dropzoneOptions={{ ...dropzone, multiple }}
41
59
  className="text-muted-foreground hover:text-primary relative aspect-square h-full cursor-pointer overflow-hidden rounded-lg border"
42
60
  >
43
61
  <FileInput className={cn("text-muted-foreground flex h-full w-full flex-col items-center justify-center")}>
@@ -26,6 +26,6 @@ export * from "./FormSlider";
26
26
  export * from "./FormSwitch";
27
27
  export * from "./FormTextarea";
28
28
  export * from "./GdprConsentCheckbox";
29
- export * from "./MultiFileUploader";
29
+ export { default as MultiFileUploader } from "./MultiFileUploader";
30
30
  export * from "./PasswordInput";
31
31
  export * from "./useEditorDialog";