analytica-frontend-lib 1.0.12 → 1.0.14
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/index.css +35 -0
- package/dist/index.d.mts +79 -1
- package/dist/index.d.ts +79 -1
- package/dist/index.js +263 -0
- package/dist/index.mjs +265 -0
- package/package.json +1 -1
package/dist/index.css
CHANGED
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
55
55
|
--default-font-family: var(--font-sans);
|
|
56
56
|
--default-mono-font-family: var(--font-mono);
|
|
57
|
+
--color-primary-50: #999999;
|
|
57
58
|
--color-primary-400: #525252;
|
|
58
59
|
--color-primary-500: #333333;
|
|
59
60
|
--color-primary-600: #292929;
|
|
@@ -427,6 +428,9 @@
|
|
|
427
428
|
.justify-start {
|
|
428
429
|
justify-content: flex-start;
|
|
429
430
|
}
|
|
431
|
+
.gap-0\.5 {
|
|
432
|
+
gap: calc(var(--spacing) * 0.5);
|
|
433
|
+
}
|
|
430
434
|
.gap-2 {
|
|
431
435
|
gap: calc(var(--spacing) * 2);
|
|
432
436
|
}
|
|
@@ -521,6 +525,9 @@
|
|
|
521
525
|
.bg-error-500 {
|
|
522
526
|
background-color: var(--color-error-500);
|
|
523
527
|
}
|
|
528
|
+
.bg-primary-50 {
|
|
529
|
+
background-color: var(--color-primary-50);
|
|
530
|
+
}
|
|
524
531
|
.bg-primary-950 {
|
|
525
532
|
background-color: var(--color-primary-950);
|
|
526
533
|
}
|
|
@@ -560,6 +567,12 @@
|
|
|
560
567
|
.px-7 {
|
|
561
568
|
padding-inline: calc(var(--spacing) * 7);
|
|
562
569
|
}
|
|
570
|
+
.px-12 {
|
|
571
|
+
padding-inline: calc(var(--spacing) * 12);
|
|
572
|
+
}
|
|
573
|
+
.py-1 {
|
|
574
|
+
padding-block: calc(var(--spacing) * 1);
|
|
575
|
+
}
|
|
563
576
|
.py-2 {
|
|
564
577
|
padding-block: calc(var(--spacing) * 2);
|
|
565
578
|
}
|
|
@@ -660,6 +673,9 @@
|
|
|
660
673
|
--tw-font-weight: var(--font-weight-semibold);
|
|
661
674
|
font-weight: var(--font-weight-semibold);
|
|
662
675
|
}
|
|
676
|
+
.whitespace-nowrap {
|
|
677
|
+
white-space: nowrap;
|
|
678
|
+
}
|
|
663
679
|
.text-error-500 {
|
|
664
680
|
color: var(--color-error-500);
|
|
665
681
|
}
|
|
@@ -837,6 +853,13 @@
|
|
|
837
853
|
}
|
|
838
854
|
}
|
|
839
855
|
}
|
|
856
|
+
.hover\:bg-primary-600 {
|
|
857
|
+
&:hover {
|
|
858
|
+
@media (hover: hover) {
|
|
859
|
+
background-color: var(--color-primary-600);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
840
863
|
.hover\:bg-primary-800 {
|
|
841
864
|
&:hover {
|
|
842
865
|
@media (hover: hover) {
|
|
@@ -872,6 +895,13 @@
|
|
|
872
895
|
}
|
|
873
896
|
}
|
|
874
897
|
}
|
|
898
|
+
.hover\:text-text {
|
|
899
|
+
&:hover {
|
|
900
|
+
@media (hover: hover) {
|
|
901
|
+
color: var(--color-text);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
875
905
|
.hover\:shadow-hard-shadow-1 {
|
|
876
906
|
&:hover {
|
|
877
907
|
@media (hover: hover) {
|
|
@@ -1049,6 +1079,11 @@
|
|
|
1049
1079
|
--tw-ring-offset-shadow: var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
|
1050
1080
|
}
|
|
1051
1081
|
}
|
|
1082
|
+
.disabled\:pointer-events-none {
|
|
1083
|
+
&:disabled {
|
|
1084
|
+
pointer-events: none;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1052
1087
|
.disabled\:cursor-not-allowed {
|
|
1053
1088
|
&:disabled {
|
|
1054
1089
|
cursor: not-allowed;
|
package/dist/index.d.mts
CHANGED
|
@@ -197,4 +197,82 @@ declare const TableHead: react.ForwardRefExoticComponent<TdHTMLAttributes<HTMLTa
|
|
|
197
197
|
declare const TableCell: react.ForwardRefExoticComponent<TdHTMLAttributes<HTMLTableCellElement> & react.RefAttributes<HTMLTableCellElement>>;
|
|
198
198
|
declare const TableCaption: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableCaptionElement> & react.RefAttributes<HTMLTableCaptionElement>>;
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
interface DropdownMenuProps {
|
|
201
|
+
children: ReactNode;
|
|
202
|
+
open?: boolean;
|
|
203
|
+
onOpenChange?: (open: boolean) => void;
|
|
204
|
+
}
|
|
205
|
+
declare const DropdownMenu: ({ children, open, onOpenChange }: DropdownMenuProps) => react_jsx_runtime.JSX.Element;
|
|
206
|
+
declare const DropdownMenuTrigger: react.ForwardRefExoticComponent<ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>;
|
|
207
|
+
declare const MenuLabel: react.ForwardRefExoticComponent<HTMLAttributes<HTMLFieldSetElement> & {
|
|
208
|
+
inset?: boolean;
|
|
209
|
+
} & react.RefAttributes<HTMLFieldSetElement>>;
|
|
210
|
+
declare const MenuContent: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
211
|
+
align?: "start" | "center" | "end";
|
|
212
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
213
|
+
sideOffset?: number;
|
|
214
|
+
} & react.RefAttributes<HTMLDivElement>>;
|
|
215
|
+
declare const MenuItem: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
216
|
+
inset?: boolean;
|
|
217
|
+
size?: "small" | "medium";
|
|
218
|
+
iconLeft?: ReactNode;
|
|
219
|
+
iconRight?: ReactNode;
|
|
220
|
+
disabled?: boolean;
|
|
221
|
+
} & react.RefAttributes<HTMLDivElement>>;
|
|
222
|
+
declare const MenuSeparator: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* NavButton component for Analytica Ensino platforms
|
|
226
|
+
*
|
|
227
|
+
* Um botão de navegação com ícone e texto para navegação principal.
|
|
228
|
+
* Ideal para menus de navegação, sidebar, tabs de navegação, etc.
|
|
229
|
+
* Compatível com Next.js 15 e React 19.
|
|
230
|
+
* Suporta forwardRef para acesso programático ao elemento DOM.
|
|
231
|
+
*
|
|
232
|
+
* @param icon - O ícone a ser exibido no botão
|
|
233
|
+
* @param label - O texto/label a ser exibido
|
|
234
|
+
* @param selected - Estado de seleção do botão
|
|
235
|
+
* @param className - Classes CSS adicionais
|
|
236
|
+
* @param props - Todos os outros atributos HTML padrão de button
|
|
237
|
+
* @returns Um elemento button estilizado para navegação
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```tsx
|
|
241
|
+
* <NavButton
|
|
242
|
+
* icon={<HomeIcon />}
|
|
243
|
+
* label="Início"
|
|
244
|
+
* selected={false}
|
|
245
|
+
* onClick={() => navigate('/')}
|
|
246
|
+
* />
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```tsx
|
|
251
|
+
* // Usando ref para foco programático
|
|
252
|
+
* const buttonRef = useRef<HTMLButtonElement>(null);
|
|
253
|
+
*
|
|
254
|
+
* const handleFocus = () => {
|
|
255
|
+
* buttonRef.current?.focus();
|
|
256
|
+
* };
|
|
257
|
+
*
|
|
258
|
+
* <NavButton
|
|
259
|
+
* ref={buttonRef}
|
|
260
|
+
* icon={<HomeIcon />}
|
|
261
|
+
* label="Dashboard"
|
|
262
|
+
* selected={isActive}
|
|
263
|
+
* onClick={() => setActiveTab('dashboard')}
|
|
264
|
+
* />
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
declare const NavButton: react.ForwardRefExoticComponent<{
|
|
268
|
+
/** Ícone a ser exibido no botão */
|
|
269
|
+
icon: ReactNode;
|
|
270
|
+
/** Texto/label a ser exibido ao lado do ícone */
|
|
271
|
+
label: string;
|
|
272
|
+
/** Estado de seleção do botão */
|
|
273
|
+
selected?: boolean;
|
|
274
|
+
/** Additional CSS classes to apply */
|
|
275
|
+
className?: string;
|
|
276
|
+
} & ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>;
|
|
277
|
+
|
|
278
|
+
export { Button, DropdownMenu, DropdownMenuTrigger, IconRoundedButton, MenuContent, MenuItem, MenuLabel, MenuSeparator, NavButton, SelectionButton, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Text };
|
package/dist/index.d.ts
CHANGED
|
@@ -197,4 +197,82 @@ declare const TableHead: react.ForwardRefExoticComponent<TdHTMLAttributes<HTMLTa
|
|
|
197
197
|
declare const TableCell: react.ForwardRefExoticComponent<TdHTMLAttributes<HTMLTableCellElement> & react.RefAttributes<HTMLTableCellElement>>;
|
|
198
198
|
declare const TableCaption: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableCaptionElement> & react.RefAttributes<HTMLTableCaptionElement>>;
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
interface DropdownMenuProps {
|
|
201
|
+
children: ReactNode;
|
|
202
|
+
open?: boolean;
|
|
203
|
+
onOpenChange?: (open: boolean) => void;
|
|
204
|
+
}
|
|
205
|
+
declare const DropdownMenu: ({ children, open, onOpenChange }: DropdownMenuProps) => react_jsx_runtime.JSX.Element;
|
|
206
|
+
declare const DropdownMenuTrigger: react.ForwardRefExoticComponent<ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>;
|
|
207
|
+
declare const MenuLabel: react.ForwardRefExoticComponent<HTMLAttributes<HTMLFieldSetElement> & {
|
|
208
|
+
inset?: boolean;
|
|
209
|
+
} & react.RefAttributes<HTMLFieldSetElement>>;
|
|
210
|
+
declare const MenuContent: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
211
|
+
align?: "start" | "center" | "end";
|
|
212
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
213
|
+
sideOffset?: number;
|
|
214
|
+
} & react.RefAttributes<HTMLDivElement>>;
|
|
215
|
+
declare const MenuItem: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
216
|
+
inset?: boolean;
|
|
217
|
+
size?: "small" | "medium";
|
|
218
|
+
iconLeft?: ReactNode;
|
|
219
|
+
iconRight?: ReactNode;
|
|
220
|
+
disabled?: boolean;
|
|
221
|
+
} & react.RefAttributes<HTMLDivElement>>;
|
|
222
|
+
declare const MenuSeparator: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* NavButton component for Analytica Ensino platforms
|
|
226
|
+
*
|
|
227
|
+
* Um botão de navegação com ícone e texto para navegação principal.
|
|
228
|
+
* Ideal para menus de navegação, sidebar, tabs de navegação, etc.
|
|
229
|
+
* Compatível com Next.js 15 e React 19.
|
|
230
|
+
* Suporta forwardRef para acesso programático ao elemento DOM.
|
|
231
|
+
*
|
|
232
|
+
* @param icon - O ícone a ser exibido no botão
|
|
233
|
+
* @param label - O texto/label a ser exibido
|
|
234
|
+
* @param selected - Estado de seleção do botão
|
|
235
|
+
* @param className - Classes CSS adicionais
|
|
236
|
+
* @param props - Todos os outros atributos HTML padrão de button
|
|
237
|
+
* @returns Um elemento button estilizado para navegação
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```tsx
|
|
241
|
+
* <NavButton
|
|
242
|
+
* icon={<HomeIcon />}
|
|
243
|
+
* label="Início"
|
|
244
|
+
* selected={false}
|
|
245
|
+
* onClick={() => navigate('/')}
|
|
246
|
+
* />
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```tsx
|
|
251
|
+
* // Usando ref para foco programático
|
|
252
|
+
* const buttonRef = useRef<HTMLButtonElement>(null);
|
|
253
|
+
*
|
|
254
|
+
* const handleFocus = () => {
|
|
255
|
+
* buttonRef.current?.focus();
|
|
256
|
+
* };
|
|
257
|
+
*
|
|
258
|
+
* <NavButton
|
|
259
|
+
* ref={buttonRef}
|
|
260
|
+
* icon={<HomeIcon />}
|
|
261
|
+
* label="Dashboard"
|
|
262
|
+
* selected={isActive}
|
|
263
|
+
* onClick={() => setActiveTab('dashboard')}
|
|
264
|
+
* />
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
declare const NavButton: react.ForwardRefExoticComponent<{
|
|
268
|
+
/** Ícone a ser exibido no botão */
|
|
269
|
+
icon: ReactNode;
|
|
270
|
+
/** Texto/label a ser exibido ao lado do ícone */
|
|
271
|
+
label: string;
|
|
272
|
+
/** Estado de seleção do botão */
|
|
273
|
+
selected?: boolean;
|
|
274
|
+
/** Additional CSS classes to apply */
|
|
275
|
+
className?: string;
|
|
276
|
+
} & ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>;
|
|
277
|
+
|
|
278
|
+
export { Button, DropdownMenu, DropdownMenuTrigger, IconRoundedButton, MenuContent, MenuItem, MenuLabel, MenuSeparator, NavButton, SelectionButton, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Text };
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
Button: () => Button,
|
|
24
|
+
DropdownMenu: () => DropdownMenu,
|
|
25
|
+
DropdownMenuTrigger: () => DropdownMenuTrigger,
|
|
24
26
|
IconRoundedButton: () => IconRoundedButton,
|
|
27
|
+
MenuContent: () => MenuContent,
|
|
28
|
+
MenuItem: () => MenuItem,
|
|
29
|
+
MenuLabel: () => MenuLabel,
|
|
30
|
+
MenuSeparator: () => MenuSeparator,
|
|
31
|
+
NavButton: () => NavButton,
|
|
25
32
|
SelectionButton: () => SelectionButton,
|
|
26
33
|
Table: () => Table,
|
|
27
34
|
TableBody: () => TableBody,
|
|
@@ -340,10 +347,266 @@ var TableCaption = (0, import_react2.forwardRef)(({ className, ...props }, ref)
|
|
|
340
347
|
}
|
|
341
348
|
));
|
|
342
349
|
TableCaption.displayName = "TableCaption";
|
|
350
|
+
|
|
351
|
+
// src/components/DropdownMenu/DropdownMenu.tsx
|
|
352
|
+
var import_react3 = require("react");
|
|
353
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
354
|
+
var DropdownMenuContext = (0, import_react3.createContext)(
|
|
355
|
+
void 0
|
|
356
|
+
);
|
|
357
|
+
var DropdownMenu = ({ children, open, onOpenChange }) => {
|
|
358
|
+
const [internalOpen, setInternalOpen] = (0, import_react3.useState)(false);
|
|
359
|
+
const isControlled = open !== void 0;
|
|
360
|
+
const currentOpen = isControlled ? open : internalOpen;
|
|
361
|
+
const setOpen = (0, import_react3.useCallback)(
|
|
362
|
+
(newOpen) => {
|
|
363
|
+
if (onOpenChange) onOpenChange(newOpen);
|
|
364
|
+
if (!isControlled) setInternalOpen(newOpen);
|
|
365
|
+
},
|
|
366
|
+
[isControlled, onOpenChange]
|
|
367
|
+
);
|
|
368
|
+
const menuRef = (0, import_react3.useRef)(null);
|
|
369
|
+
const handleEscape = (event) => {
|
|
370
|
+
if (event.key === "Escape") {
|
|
371
|
+
setOpen(false);
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
const handleClickOutside = (event) => {
|
|
375
|
+
if (menuRef.current && !menuRef.current.contains(event.target)) {
|
|
376
|
+
setOpen(false);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
(0, import_react3.useEffect)(() => {
|
|
380
|
+
if (currentOpen) {
|
|
381
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
382
|
+
document.addEventListener("keydown", handleEscape);
|
|
383
|
+
}
|
|
384
|
+
return () => {
|
|
385
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
386
|
+
document.removeEventListener("keydown", handleEscape);
|
|
387
|
+
};
|
|
388
|
+
}, [currentOpen]);
|
|
389
|
+
const value = (0, import_react3.useMemo)(
|
|
390
|
+
() => ({ open: currentOpen, setOpen }),
|
|
391
|
+
[currentOpen, setOpen]
|
|
392
|
+
);
|
|
393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "relative", ref: menuRef, children }) });
|
|
394
|
+
};
|
|
395
|
+
var DropdownMenuTrigger = (0, import_react3.forwardRef)(({ className, children, onClick, ...props }, ref) => {
|
|
396
|
+
const context = (0, import_react3.useContext)(DropdownMenuContext);
|
|
397
|
+
if (!context)
|
|
398
|
+
throw new Error("DropdownMenuTrigger must be used within a DropdownMenu");
|
|
399
|
+
const { open, setOpen } = context;
|
|
400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
401
|
+
"button",
|
|
402
|
+
{
|
|
403
|
+
ref,
|
|
404
|
+
className: `border border-border-200 cursor-pointer bg-background-muted hover:bg-background-200 transition-colors px-4 py-2 rounded-sm ${className}`,
|
|
405
|
+
onClick: (e) => {
|
|
406
|
+
e.stopPropagation();
|
|
407
|
+
setOpen(!open);
|
|
408
|
+
if (onClick) onClick(e);
|
|
409
|
+
},
|
|
410
|
+
"aria-expanded": open,
|
|
411
|
+
...props,
|
|
412
|
+
children
|
|
413
|
+
}
|
|
414
|
+
);
|
|
415
|
+
});
|
|
416
|
+
DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
|
|
417
|
+
var ITEM_SIZE_CLASSES = {
|
|
418
|
+
small: "text-sm",
|
|
419
|
+
medium: "text-md"
|
|
420
|
+
};
|
|
421
|
+
var SIDE_CLASSES = {
|
|
422
|
+
top: "bottom-full",
|
|
423
|
+
right: "top-full",
|
|
424
|
+
bottom: "top-full",
|
|
425
|
+
left: "top-full"
|
|
426
|
+
};
|
|
427
|
+
var ALIGN_CLASSES = {
|
|
428
|
+
start: "left-0",
|
|
429
|
+
center: "left-1/2 -translate-x-1/2",
|
|
430
|
+
end: "right-0"
|
|
431
|
+
};
|
|
432
|
+
var MenuLabel = (0, import_react3.forwardRef)(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
433
|
+
"fieldset",
|
|
434
|
+
{
|
|
435
|
+
ref,
|
|
436
|
+
role: "group",
|
|
437
|
+
className: `text-sm w-full ${inset ? "pl-8" : ""} ${className ?? ""}`,
|
|
438
|
+
...props
|
|
439
|
+
}
|
|
440
|
+
));
|
|
441
|
+
MenuLabel.displayName = "MenuLabel";
|
|
442
|
+
var MenuContent = (0, import_react3.forwardRef)(
|
|
443
|
+
({
|
|
444
|
+
className,
|
|
445
|
+
align = "start",
|
|
446
|
+
side = "bottom",
|
|
447
|
+
sideOffset = 4,
|
|
448
|
+
children,
|
|
449
|
+
...props
|
|
450
|
+
}, ref) => {
|
|
451
|
+
const { open } = (0, import_react3.useContext)(DropdownMenuContext);
|
|
452
|
+
const [isVisible, setIsVisible] = (0, import_react3.useState)(open);
|
|
453
|
+
(0, import_react3.useEffect)(() => {
|
|
454
|
+
if (open) {
|
|
455
|
+
setIsVisible(true);
|
|
456
|
+
} else {
|
|
457
|
+
const timer = setTimeout(() => setIsVisible(false), 200);
|
|
458
|
+
return () => clearTimeout(timer);
|
|
459
|
+
}
|
|
460
|
+
}, [open]);
|
|
461
|
+
if (!isVisible) return null;
|
|
462
|
+
const getPositionClasses = () => {
|
|
463
|
+
const vertical = SIDE_CLASSES[side];
|
|
464
|
+
const horizontal = ALIGN_CLASSES[align];
|
|
465
|
+
return `absolute ${vertical} ${horizontal}`;
|
|
466
|
+
};
|
|
467
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
468
|
+
"div",
|
|
469
|
+
{
|
|
470
|
+
ref,
|
|
471
|
+
role: "menu",
|
|
472
|
+
className: `
|
|
473
|
+
bg-background z-50 min-w-[210px] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md border-border-100
|
|
474
|
+
${open ? "animate-in fade-in-0 zoom-in-95" : "animate-out fade-out-0 zoom-out-95"}
|
|
475
|
+
${getPositionClasses()}
|
|
476
|
+
${className}
|
|
477
|
+
`,
|
|
478
|
+
style: {
|
|
479
|
+
marginTop: side === "bottom" ? sideOffset : void 0,
|
|
480
|
+
marginBottom: side === "top" ? sideOffset : void 0,
|
|
481
|
+
marginLeft: side === "right" ? sideOffset : void 0,
|
|
482
|
+
marginRight: side === "left" ? sideOffset : void 0
|
|
483
|
+
},
|
|
484
|
+
...props,
|
|
485
|
+
children
|
|
486
|
+
}
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
);
|
|
490
|
+
MenuContent.displayName = "MenuContent";
|
|
491
|
+
var MenuItem = (0, import_react3.forwardRef)(
|
|
492
|
+
({
|
|
493
|
+
className,
|
|
494
|
+
inset,
|
|
495
|
+
size = "small",
|
|
496
|
+
children,
|
|
497
|
+
iconRight,
|
|
498
|
+
iconLeft,
|
|
499
|
+
disabled = false,
|
|
500
|
+
onClick,
|
|
501
|
+
...props
|
|
502
|
+
}, ref) => {
|
|
503
|
+
const sizeClasses = ITEM_SIZE_CLASSES[size];
|
|
504
|
+
const handleClick = (e) => {
|
|
505
|
+
if (disabled) {
|
|
506
|
+
e.preventDefault();
|
|
507
|
+
e.stopPropagation();
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
onClick?.(e);
|
|
511
|
+
};
|
|
512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
513
|
+
"div",
|
|
514
|
+
{
|
|
515
|
+
ref,
|
|
516
|
+
role: "menuitem",
|
|
517
|
+
"aria-disabled": disabled,
|
|
518
|
+
className: `
|
|
519
|
+
relative flex select-none items-center gap-2 rounded-sm p-3 text-sm outline-none transition-colors [&>svg]:size-4 [&>svg]:shrink-0
|
|
520
|
+
${inset && "pl-8"}
|
|
521
|
+
${sizeClasses}
|
|
522
|
+
${className}
|
|
523
|
+
${disabled ? "cursor-not-allowed text-text-400" : "cursor-pointer hover:bg-background-50 text-text-700 focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground"}
|
|
524
|
+
`,
|
|
525
|
+
onClick: handleClick,
|
|
526
|
+
onKeyDown: (e) => {
|
|
527
|
+
if (e.key === "Enter" || e.key === " ") handleClick(e);
|
|
528
|
+
},
|
|
529
|
+
tabIndex: disabled ? -1 : 0,
|
|
530
|
+
...props,
|
|
531
|
+
children: [
|
|
532
|
+
iconLeft,
|
|
533
|
+
children,
|
|
534
|
+
iconRight
|
|
535
|
+
]
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
);
|
|
540
|
+
MenuItem.displayName = "MenuItem";
|
|
541
|
+
var MenuSeparator = (0, import_react3.forwardRef)(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
542
|
+
"div",
|
|
543
|
+
{
|
|
544
|
+
ref,
|
|
545
|
+
className: `my-1 h-px bg-border-200 ${className}`,
|
|
546
|
+
...props
|
|
547
|
+
}
|
|
548
|
+
));
|
|
549
|
+
MenuSeparator.displayName = "MenuSeparator";
|
|
550
|
+
|
|
551
|
+
// src/components/NavButton/NavButton.tsx
|
|
552
|
+
var import_react4 = require("react");
|
|
553
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
554
|
+
var NavButton = (0, import_react4.forwardRef)(
|
|
555
|
+
({ icon, label, selected = false, className = "", disabled, ...props }, ref) => {
|
|
556
|
+
const baseClasses = [
|
|
557
|
+
"flex",
|
|
558
|
+
"flex-col",
|
|
559
|
+
"items-center",
|
|
560
|
+
"justify-center",
|
|
561
|
+
"gap-0.5",
|
|
562
|
+
"px-12",
|
|
563
|
+
"py-1",
|
|
564
|
+
"rounded-sm",
|
|
565
|
+
"cursor-pointer",
|
|
566
|
+
"text-text-950",
|
|
567
|
+
"text-xs",
|
|
568
|
+
"font-medium",
|
|
569
|
+
"hover:text-text",
|
|
570
|
+
"hover:bg-primary-600",
|
|
571
|
+
"focus-visible:outline-none",
|
|
572
|
+
"focus-visible:ring-2",
|
|
573
|
+
"focus-visible:ring-offset-0",
|
|
574
|
+
"focus-visible:ring-indicator-info",
|
|
575
|
+
"disabled:opacity-50",
|
|
576
|
+
"disabled:cursor-not-allowed",
|
|
577
|
+
"disabled:pointer-events-none"
|
|
578
|
+
];
|
|
579
|
+
const stateClasses = selected ? ["bg-primary-50", "text-primary-950"] : [];
|
|
580
|
+
const allClasses = [...baseClasses, ...stateClasses].join(" ");
|
|
581
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
582
|
+
"button",
|
|
583
|
+
{
|
|
584
|
+
ref,
|
|
585
|
+
type: "button",
|
|
586
|
+
className: `${allClasses} ${className}`,
|
|
587
|
+
disabled,
|
|
588
|
+
"aria-pressed": selected,
|
|
589
|
+
...props,
|
|
590
|
+
children: [
|
|
591
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "flex items-center justify-center w-5 h-5", children: icon }),
|
|
592
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "whitespace-nowrap", children: label })
|
|
593
|
+
]
|
|
594
|
+
}
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
);
|
|
598
|
+
NavButton.displayName = "NavButton";
|
|
343
599
|
// Annotate the CommonJS export names for ESM import in node:
|
|
344
600
|
0 && (module.exports = {
|
|
345
601
|
Button,
|
|
602
|
+
DropdownMenu,
|
|
603
|
+
DropdownMenuTrigger,
|
|
346
604
|
IconRoundedButton,
|
|
605
|
+
MenuContent,
|
|
606
|
+
MenuItem,
|
|
607
|
+
MenuLabel,
|
|
608
|
+
MenuSeparator,
|
|
609
|
+
NavButton,
|
|
347
610
|
SelectionButton,
|
|
348
611
|
Table,
|
|
349
612
|
TableBody,
|
package/dist/index.mjs
CHANGED
|
@@ -303,9 +303,274 @@ var TableCaption = forwardRef2(({ className, ...props }, ref) => /* @__PURE__ */
|
|
|
303
303
|
}
|
|
304
304
|
));
|
|
305
305
|
TableCaption.displayName = "TableCaption";
|
|
306
|
+
|
|
307
|
+
// src/components/DropdownMenu/DropdownMenu.tsx
|
|
308
|
+
import {
|
|
309
|
+
createContext,
|
|
310
|
+
useState,
|
|
311
|
+
useCallback,
|
|
312
|
+
useContext,
|
|
313
|
+
forwardRef as forwardRef3,
|
|
314
|
+
useEffect,
|
|
315
|
+
useRef,
|
|
316
|
+
useMemo
|
|
317
|
+
} from "react";
|
|
318
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
319
|
+
var DropdownMenuContext = createContext(
|
|
320
|
+
void 0
|
|
321
|
+
);
|
|
322
|
+
var DropdownMenu = ({ children, open, onOpenChange }) => {
|
|
323
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
324
|
+
const isControlled = open !== void 0;
|
|
325
|
+
const currentOpen = isControlled ? open : internalOpen;
|
|
326
|
+
const setOpen = useCallback(
|
|
327
|
+
(newOpen) => {
|
|
328
|
+
if (onOpenChange) onOpenChange(newOpen);
|
|
329
|
+
if (!isControlled) setInternalOpen(newOpen);
|
|
330
|
+
},
|
|
331
|
+
[isControlled, onOpenChange]
|
|
332
|
+
);
|
|
333
|
+
const menuRef = useRef(null);
|
|
334
|
+
const handleEscape = (event) => {
|
|
335
|
+
if (event.key === "Escape") {
|
|
336
|
+
setOpen(false);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
const handleClickOutside = (event) => {
|
|
340
|
+
if (menuRef.current && !menuRef.current.contains(event.target)) {
|
|
341
|
+
setOpen(false);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
useEffect(() => {
|
|
345
|
+
if (currentOpen) {
|
|
346
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
347
|
+
document.addEventListener("keydown", handleEscape);
|
|
348
|
+
}
|
|
349
|
+
return () => {
|
|
350
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
351
|
+
document.removeEventListener("keydown", handleEscape);
|
|
352
|
+
};
|
|
353
|
+
}, [currentOpen]);
|
|
354
|
+
const value = useMemo(
|
|
355
|
+
() => ({ open: currentOpen, setOpen }),
|
|
356
|
+
[currentOpen, setOpen]
|
|
357
|
+
);
|
|
358
|
+
return /* @__PURE__ */ jsx6(DropdownMenuContext.Provider, { value, children: /* @__PURE__ */ jsx6("div", { className: "relative", ref: menuRef, children }) });
|
|
359
|
+
};
|
|
360
|
+
var DropdownMenuTrigger = forwardRef3(({ className, children, onClick, ...props }, ref) => {
|
|
361
|
+
const context = useContext(DropdownMenuContext);
|
|
362
|
+
if (!context)
|
|
363
|
+
throw new Error("DropdownMenuTrigger must be used within a DropdownMenu");
|
|
364
|
+
const { open, setOpen } = context;
|
|
365
|
+
return /* @__PURE__ */ jsx6(
|
|
366
|
+
"button",
|
|
367
|
+
{
|
|
368
|
+
ref,
|
|
369
|
+
className: `border border-border-200 cursor-pointer bg-background-muted hover:bg-background-200 transition-colors px-4 py-2 rounded-sm ${className}`,
|
|
370
|
+
onClick: (e) => {
|
|
371
|
+
e.stopPropagation();
|
|
372
|
+
setOpen(!open);
|
|
373
|
+
if (onClick) onClick(e);
|
|
374
|
+
},
|
|
375
|
+
"aria-expanded": open,
|
|
376
|
+
...props,
|
|
377
|
+
children
|
|
378
|
+
}
|
|
379
|
+
);
|
|
380
|
+
});
|
|
381
|
+
DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
|
|
382
|
+
var ITEM_SIZE_CLASSES = {
|
|
383
|
+
small: "text-sm",
|
|
384
|
+
medium: "text-md"
|
|
385
|
+
};
|
|
386
|
+
var SIDE_CLASSES = {
|
|
387
|
+
top: "bottom-full",
|
|
388
|
+
right: "top-full",
|
|
389
|
+
bottom: "top-full",
|
|
390
|
+
left: "top-full"
|
|
391
|
+
};
|
|
392
|
+
var ALIGN_CLASSES = {
|
|
393
|
+
start: "left-0",
|
|
394
|
+
center: "left-1/2 -translate-x-1/2",
|
|
395
|
+
end: "right-0"
|
|
396
|
+
};
|
|
397
|
+
var MenuLabel = forwardRef3(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx6(
|
|
398
|
+
"fieldset",
|
|
399
|
+
{
|
|
400
|
+
ref,
|
|
401
|
+
role: "group",
|
|
402
|
+
className: `text-sm w-full ${inset ? "pl-8" : ""} ${className ?? ""}`,
|
|
403
|
+
...props
|
|
404
|
+
}
|
|
405
|
+
));
|
|
406
|
+
MenuLabel.displayName = "MenuLabel";
|
|
407
|
+
var MenuContent = forwardRef3(
|
|
408
|
+
({
|
|
409
|
+
className,
|
|
410
|
+
align = "start",
|
|
411
|
+
side = "bottom",
|
|
412
|
+
sideOffset = 4,
|
|
413
|
+
children,
|
|
414
|
+
...props
|
|
415
|
+
}, ref) => {
|
|
416
|
+
const { open } = useContext(DropdownMenuContext);
|
|
417
|
+
const [isVisible, setIsVisible] = useState(open);
|
|
418
|
+
useEffect(() => {
|
|
419
|
+
if (open) {
|
|
420
|
+
setIsVisible(true);
|
|
421
|
+
} else {
|
|
422
|
+
const timer = setTimeout(() => setIsVisible(false), 200);
|
|
423
|
+
return () => clearTimeout(timer);
|
|
424
|
+
}
|
|
425
|
+
}, [open]);
|
|
426
|
+
if (!isVisible) return null;
|
|
427
|
+
const getPositionClasses = () => {
|
|
428
|
+
const vertical = SIDE_CLASSES[side];
|
|
429
|
+
const horizontal = ALIGN_CLASSES[align];
|
|
430
|
+
return `absolute ${vertical} ${horizontal}`;
|
|
431
|
+
};
|
|
432
|
+
return /* @__PURE__ */ jsx6(
|
|
433
|
+
"div",
|
|
434
|
+
{
|
|
435
|
+
ref,
|
|
436
|
+
role: "menu",
|
|
437
|
+
className: `
|
|
438
|
+
bg-background z-50 min-w-[210px] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md border-border-100
|
|
439
|
+
${open ? "animate-in fade-in-0 zoom-in-95" : "animate-out fade-out-0 zoom-out-95"}
|
|
440
|
+
${getPositionClasses()}
|
|
441
|
+
${className}
|
|
442
|
+
`,
|
|
443
|
+
style: {
|
|
444
|
+
marginTop: side === "bottom" ? sideOffset : void 0,
|
|
445
|
+
marginBottom: side === "top" ? sideOffset : void 0,
|
|
446
|
+
marginLeft: side === "right" ? sideOffset : void 0,
|
|
447
|
+
marginRight: side === "left" ? sideOffset : void 0
|
|
448
|
+
},
|
|
449
|
+
...props,
|
|
450
|
+
children
|
|
451
|
+
}
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
MenuContent.displayName = "MenuContent";
|
|
456
|
+
var MenuItem = forwardRef3(
|
|
457
|
+
({
|
|
458
|
+
className,
|
|
459
|
+
inset,
|
|
460
|
+
size = "small",
|
|
461
|
+
children,
|
|
462
|
+
iconRight,
|
|
463
|
+
iconLeft,
|
|
464
|
+
disabled = false,
|
|
465
|
+
onClick,
|
|
466
|
+
...props
|
|
467
|
+
}, ref) => {
|
|
468
|
+
const sizeClasses = ITEM_SIZE_CLASSES[size];
|
|
469
|
+
const handleClick = (e) => {
|
|
470
|
+
if (disabled) {
|
|
471
|
+
e.preventDefault();
|
|
472
|
+
e.stopPropagation();
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
onClick?.(e);
|
|
476
|
+
};
|
|
477
|
+
return /* @__PURE__ */ jsxs4(
|
|
478
|
+
"div",
|
|
479
|
+
{
|
|
480
|
+
ref,
|
|
481
|
+
role: "menuitem",
|
|
482
|
+
"aria-disabled": disabled,
|
|
483
|
+
className: `
|
|
484
|
+
relative flex select-none items-center gap-2 rounded-sm p-3 text-sm outline-none transition-colors [&>svg]:size-4 [&>svg]:shrink-0
|
|
485
|
+
${inset && "pl-8"}
|
|
486
|
+
${sizeClasses}
|
|
487
|
+
${className}
|
|
488
|
+
${disabled ? "cursor-not-allowed text-text-400" : "cursor-pointer hover:bg-background-50 text-text-700 focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground"}
|
|
489
|
+
`,
|
|
490
|
+
onClick: handleClick,
|
|
491
|
+
onKeyDown: (e) => {
|
|
492
|
+
if (e.key === "Enter" || e.key === " ") handleClick(e);
|
|
493
|
+
},
|
|
494
|
+
tabIndex: disabled ? -1 : 0,
|
|
495
|
+
...props,
|
|
496
|
+
children: [
|
|
497
|
+
iconLeft,
|
|
498
|
+
children,
|
|
499
|
+
iconRight
|
|
500
|
+
]
|
|
501
|
+
}
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
MenuItem.displayName = "MenuItem";
|
|
506
|
+
var MenuSeparator = forwardRef3(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
|
|
507
|
+
"div",
|
|
508
|
+
{
|
|
509
|
+
ref,
|
|
510
|
+
className: `my-1 h-px bg-border-200 ${className}`,
|
|
511
|
+
...props
|
|
512
|
+
}
|
|
513
|
+
));
|
|
514
|
+
MenuSeparator.displayName = "MenuSeparator";
|
|
515
|
+
|
|
516
|
+
// src/components/NavButton/NavButton.tsx
|
|
517
|
+
import { forwardRef as forwardRef4 } from "react";
|
|
518
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
519
|
+
var NavButton = forwardRef4(
|
|
520
|
+
({ icon, label, selected = false, className = "", disabled, ...props }, ref) => {
|
|
521
|
+
const baseClasses = [
|
|
522
|
+
"flex",
|
|
523
|
+
"flex-col",
|
|
524
|
+
"items-center",
|
|
525
|
+
"justify-center",
|
|
526
|
+
"gap-0.5",
|
|
527
|
+
"px-12",
|
|
528
|
+
"py-1",
|
|
529
|
+
"rounded-sm",
|
|
530
|
+
"cursor-pointer",
|
|
531
|
+
"text-text-950",
|
|
532
|
+
"text-xs",
|
|
533
|
+
"font-medium",
|
|
534
|
+
"hover:text-text",
|
|
535
|
+
"hover:bg-primary-600",
|
|
536
|
+
"focus-visible:outline-none",
|
|
537
|
+
"focus-visible:ring-2",
|
|
538
|
+
"focus-visible:ring-offset-0",
|
|
539
|
+
"focus-visible:ring-indicator-info",
|
|
540
|
+
"disabled:opacity-50",
|
|
541
|
+
"disabled:cursor-not-allowed",
|
|
542
|
+
"disabled:pointer-events-none"
|
|
543
|
+
];
|
|
544
|
+
const stateClasses = selected ? ["bg-primary-50", "text-primary-950"] : [];
|
|
545
|
+
const allClasses = [...baseClasses, ...stateClasses].join(" ");
|
|
546
|
+
return /* @__PURE__ */ jsxs5(
|
|
547
|
+
"button",
|
|
548
|
+
{
|
|
549
|
+
ref,
|
|
550
|
+
type: "button",
|
|
551
|
+
className: `${allClasses} ${className}`,
|
|
552
|
+
disabled,
|
|
553
|
+
"aria-pressed": selected,
|
|
554
|
+
...props,
|
|
555
|
+
children: [
|
|
556
|
+
/* @__PURE__ */ jsx7("span", { className: "flex items-center justify-center w-5 h-5", children: icon }),
|
|
557
|
+
/* @__PURE__ */ jsx7("span", { className: "whitespace-nowrap", children: label })
|
|
558
|
+
]
|
|
559
|
+
}
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
);
|
|
563
|
+
NavButton.displayName = "NavButton";
|
|
306
564
|
export {
|
|
307
565
|
Button,
|
|
566
|
+
DropdownMenu,
|
|
567
|
+
DropdownMenuTrigger,
|
|
308
568
|
IconRoundedButton,
|
|
569
|
+
MenuContent,
|
|
570
|
+
MenuItem,
|
|
571
|
+
MenuLabel,
|
|
572
|
+
MenuSeparator,
|
|
573
|
+
NavButton,
|
|
309
574
|
SelectionButton,
|
|
310
575
|
Table,
|
|
311
576
|
TableBody,
|
package/package.json
CHANGED