@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.
- package/dist/{BlockNoteEditor-JQNYMLFY.js → BlockNoteEditor-4ZNFPFIR.js} +8 -8
- package/dist/{BlockNoteEditor-JQNYMLFY.js.map → BlockNoteEditor-4ZNFPFIR.js.map} +1 -1
- package/dist/{BlockNoteEditor-CZXTJL3R.mjs → BlockNoteEditor-MY2WUSZY.mjs} +4 -4
- package/dist/{BlockNoteEditor-CZXTJL3R.mjs.map → BlockNoteEditor-MY2WUSZY.mjs.map} +1 -1
- package/dist/billing/index.js +299 -299
- package/dist/billing/index.mjs +1 -1
- package/dist/{chunk-3AYMUFM6.mjs → chunk-56YOTJYS.mjs} +2570 -2053
- package/dist/chunk-56YOTJYS.mjs.map +1 -0
- package/dist/{chunk-SUJ4GXAI.js → chunk-6RE6272L.js} +768 -251
- package/dist/chunk-6RE6272L.js.map +1 -0
- package/dist/client/index.js +2 -2
- package/dist/client/index.mjs +1 -1
- package/dist/components/index.d.mts +94 -2
- package/dist/components/index.d.ts +94 -2
- package/dist/components/index.js +6 -2
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +5 -1
- package/dist/contexts/index.js +2 -2
- package/dist/contexts/index.mjs +1 -1
- package/dist/scripts/generate-web-module/templates/components/multi-selector.template.d.ts.map +1 -1
- package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js +52 -54
- package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js.map +1 -1
- package/package.json +1 -1
- package/scripts/generate-web-module/templates/components/multi-selector.template.ts +52 -54
- package/src/components/editors/BlockNoteEditor.tsx +2 -2
- package/src/features/company/hooks/useSubscriptionStatus.ts +12 -0
- package/src/features/user/components/forms/UserMultiSelect.tsx +82 -64
- package/src/shadcnui/custom/multi-select.tsx +86 -22
- package/src/shadcnui/custom/multiple-selector.tsx +608 -0
- package/src/shadcnui/index.ts +1 -0
- package/dist/chunk-3AYMUFM6.mjs.map +0 -1
- 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
|
|
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
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
<
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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 =
|
|
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 &&
|
|
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
|
);
|