@carlonicora/nextjs-jsonapi 1.47.2 → 1.48.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 (32) hide show
  1. package/dist/{BlockNoteEditor-JQNYMLFY.js → BlockNoteEditor-4ZNFPFIR.js} +8 -8
  2. package/dist/{BlockNoteEditor-JQNYMLFY.js.map → BlockNoteEditor-4ZNFPFIR.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-CZXTJL3R.mjs → BlockNoteEditor-MY2WUSZY.mjs} +4 -4
  4. package/dist/{BlockNoteEditor-CZXTJL3R.mjs.map → BlockNoteEditor-MY2WUSZY.mjs.map} +1 -1
  5. package/dist/billing/index.js +299 -299
  6. package/dist/billing/index.mjs +1 -1
  7. package/dist/{chunk-3AYMUFM6.mjs → chunk-56YOTJYS.mjs} +2570 -2053
  8. package/dist/chunk-56YOTJYS.mjs.map +1 -0
  9. package/dist/{chunk-SUJ4GXAI.js → chunk-6RE6272L.js} +768 -251
  10. package/dist/chunk-6RE6272L.js.map +1 -0
  11. package/dist/client/index.js +2 -2
  12. package/dist/client/index.mjs +1 -1
  13. package/dist/components/index.d.mts +94 -2
  14. package/dist/components/index.d.ts +94 -2
  15. package/dist/components/index.js +6 -2
  16. package/dist/components/index.js.map +1 -1
  17. package/dist/components/index.mjs +5 -1
  18. package/dist/contexts/index.js +2 -2
  19. package/dist/contexts/index.mjs +1 -1
  20. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.d.ts.map +1 -1
  21. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js +52 -54
  22. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js.map +1 -1
  23. package/package.json +1 -1
  24. package/scripts/generate-web-module/templates/components/multi-selector.template.ts +52 -54
  25. package/src/components/editors/BlockNoteEditor.tsx +2 -2
  26. package/src/features/company/hooks/useSubscriptionStatus.ts +12 -0
  27. package/src/features/user/components/forms/UserMultiSelect.tsx +82 -64
  28. package/src/shadcnui/custom/multi-select.tsx +86 -22
  29. package/src/shadcnui/custom/multiple-selector.tsx +608 -0
  30. package/src/shadcnui/index.ts +1 -0
  31. package/dist/chunk-3AYMUFM6.mjs.map +0 -1
  32. package/dist/chunk-SUJ4GXAI.js.map +0 -1
@@ -49,12 +49,16 @@ interface MultiSelectProps
49
49
  * Each option object has a label, value, and an optional icon.
50
50
  */
51
51
  options: {
52
- /** The text to display for the option. */
52
+ /** The text to display for the option in the dropdown. */
53
53
  label: string;
54
54
  /** The unique value associated with the option. */
55
55
  value: string;
56
+ /** Optional text to display when selected (in badges). Falls back to label if not provided. */
57
+ selectedLabel?: string;
56
58
  /** Optional icon component to display alongside the option. */
57
59
  icon?: React.ComponentType<{ className?: string }>;
60
+ /** Optional custom className for the icon. */
61
+ iconClassName?: string;
58
62
  }[];
59
63
 
60
64
  /**
@@ -126,6 +130,19 @@ interface MultiSelectProps
126
130
  * Optional, defaults to "No results found.".
127
131
  */
128
132
  emptyText?: string;
133
+
134
+ /**
135
+ * Whether to hide the "Select All" option.
136
+ * Optional, defaults to false.
137
+ */
138
+ hideSelectAll?: boolean;
139
+
140
+ /**
141
+ * Custom function to determine if an option should appear selected.
142
+ * Useful when option values differ from selected values (e.g., prefixed values).
143
+ * If not provided, uses default check: selectedValues.includes(option.value)
144
+ */
145
+ isOptionSelected?: (optionValue: string, selectedValues: string[]) => boolean;
129
146
  }
130
147
 
131
148
  export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
@@ -145,6 +162,8 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
145
162
  loading = false,
146
163
  loadingText = "Searching...",
147
164
  emptyText = "No results found.",
165
+ hideSelectAll = false,
166
+ isOptionSelected,
148
167
  ...props
149
168
  },
150
169
  _ref,
@@ -158,6 +177,17 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
158
177
  const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
159
178
  const [isAnimating, setIsAnimating] = React.useState(false);
160
179
 
180
+ // Ref and state to match popover width to trigger width
181
+ const triggerRef = React.useRef<HTMLButtonElement>(null);
182
+ const [triggerWidth, setTriggerWidth] = React.useState<number>(0);
183
+
184
+ // Measure trigger width when popover opens
185
+ React.useEffect(() => {
186
+ if (isPopoverOpen && triggerRef.current) {
187
+ setTriggerWidth(triggerRef.current.offsetWidth);
188
+ }
189
+ }, [isPopoverOpen]);
190
+
161
191
  const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
162
192
  if (event.key === "Enter") {
163
193
  setIsPopoverOpen(true);
@@ -199,7 +229,12 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
199
229
  onValueChange([]);
200
230
  };
201
231
 
202
- const handleTogglePopover = () => {
232
+ const handleTogglePopover = (event: React.MouseEvent) => {
233
+ // Don't toggle if clicking on X buttons (clear icons)
234
+ const target = event.target as HTMLElement;
235
+ if (target.closest("[data-remove-button]")) {
236
+ return;
237
+ }
203
238
  setIsPopoverOpen((prev) => !prev);
204
239
  };
205
240
 
@@ -237,6 +272,7 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
237
272
  <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal={modalPopover}>
238
273
  <PopoverTrigger
239
274
  {...props}
275
+ ref={triggerRef}
240
276
  onClick={handleTogglePopover}
241
277
  className={cn(
242
278
  "flex h-auto min-h-10 w-full items-center justify-between rounded-md border bg-inherit p-1 hover:bg-inherit [&_svg]:pointer-events-auto",
@@ -256,11 +292,17 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
256
292
  style={{ animationDuration: `${animation}s` }}
257
293
  >
258
294
  {IconComponent && <IconComponent className="mr-2 h-4 w-4" />}
259
- {option?.label}
295
+ {option?.selectedLabel ?? option?.label}
260
296
  <XCircle
297
+ data-remove-button
261
298
  className="ml-2 h-4 w-4 cursor-pointer"
299
+ onPointerDown={(event) => {
300
+ event.stopPropagation();
301
+ event.preventDefault();
302
+ }}
262
303
  onClick={(event) => {
263
304
  event.stopPropagation();
305
+ event.preventDefault();
264
306
  toggleOption(value);
265
307
  }}
266
308
  />
@@ -278,9 +320,15 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
278
320
  >
279
321
  {`+ ${selectedValues.length - maxCount} more`}
280
322
  <XCircle
323
+ data-remove-button
281
324
  className="ml-2 h-4 w-4 cursor-pointer"
325
+ onPointerDown={(event) => {
326
+ event.stopPropagation();
327
+ event.preventDefault();
328
+ }}
282
329
  onClick={(event) => {
283
330
  event.stopPropagation();
331
+ event.preventDefault();
284
332
  clearExtraOptions();
285
333
  }}
286
334
  />
@@ -289,9 +337,15 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
289
337
  </div>
290
338
  <div className="flex items-center justify-between">
291
339
  <XIcon
340
+ data-remove-button
292
341
  className="text-muted-foreground mx-2 h-4 cursor-pointer"
342
+ onPointerDown={(event) => {
343
+ event.stopPropagation();
344
+ event.preventDefault();
345
+ }}
293
346
  onClick={(event) => {
294
347
  event.stopPropagation();
348
+ event.preventDefault();
295
349
  handleClear();
296
350
  }}
297
351
  />
@@ -306,7 +360,11 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
306
360
  </div>
307
361
  )}
308
362
  </PopoverTrigger>
309
- <PopoverContent className="w-auto p-0" align="start">
363
+ <PopoverContent
364
+ className="w-auto p-0"
365
+ style={{ minWidth: triggerWidth > 0 ? triggerWidth : undefined }}
366
+ align="start"
367
+ >
310
368
  <Command>
311
369
  <CommandInput
312
370
  autoFocus
@@ -322,25 +380,29 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
322
380
  <CommandList>
323
381
  <CommandEmpty>{loading ? loadingText : emptyText}</CommandEmpty>
324
382
  <CommandGroup>
325
- <CommandItem
326
- key="all"
327
- onSelect={toggleAll}
328
- className="cursor-pointer hover:bg-muted data-selected:hover:bg-muted bg-transparent data-selected:bg-transparent"
329
- >
330
- <div
331
- className={cn(
332
- "border-primary mr-2 flex h-4 w-4 items-center justify-center rounded-sm border",
333
- selectedValues.length === options.length
334
- ? "bg-primary text-primary-foreground"
335
- : "opacity-50 [&_svg]:invisible",
336
- )}
383
+ {!hideSelectAll && (
384
+ <CommandItem
385
+ key="all"
386
+ onSelect={toggleAll}
387
+ className="cursor-pointer hover:bg-muted data-selected:hover:bg-muted bg-transparent data-selected:bg-transparent"
337
388
  >
338
- <CheckIcon className="h-4 w-4" />
339
- </div>
340
- <span>(Select All)</span>
341
- </CommandItem>
389
+ <div
390
+ className={cn(
391
+ "border-primary mr-2 flex h-4 w-4 items-center justify-center rounded-sm border",
392
+ selectedValues.length === options.length
393
+ ? "bg-primary text-primary-foreground"
394
+ : "opacity-50 [&_svg]:invisible",
395
+ )}
396
+ >
397
+ <CheckIcon className="h-4 w-4" />
398
+ </div>
399
+ <span>(Select All)</span>
400
+ </CommandItem>
401
+ )}
342
402
  {options.map((option) => {
343
- const isSelected = selectedValues.includes(option.value);
403
+ const isSelected = isOptionSelected
404
+ ? isOptionSelected(option.value, selectedValues)
405
+ : selectedValues.includes(option.value);
344
406
  return (
345
407
  <CommandItem
346
408
  key={option.value}
@@ -355,7 +417,9 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
355
417
  >
356
418
  <CheckIcon className="h-4 w-4" />
357
419
  </div>
358
- {option.icon && <option.icon className="text-muted-foreground mr-2 h-4 w-4" />}
420
+ {option.icon && (
421
+ <option.icon className={option.iconClassName ?? "text-muted-foreground mr-2 h-4 w-4"} />
422
+ )}
359
423
  <span>{option.label}</span>
360
424
  </CommandItem>
361
425
  );