@stfrigerio/sito-template 0.1.35 → 0.1.36
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/components/atoms/EmptyState/EmptyState.d.ts +53 -0
- package/dist/components/atoms/EmptyState/EmptyState.d.ts.map +1 -0
- package/dist/components/atoms/EmptyState/index.d.ts +3 -0
- package/dist/components/atoms/EmptyState/index.d.ts.map +1 -0
- package/dist/components/atoms/Modal/Modal.d.ts +61 -0
- package/dist/components/atoms/Modal/Modal.d.ts.map +1 -0
- package/dist/components/atoms/Modal/index.d.ts +3 -0
- package/dist/components/atoms/Modal/index.d.ts.map +1 -0
- package/dist/components/atoms/index.d.ts +4 -0
- package/dist/components/atoms/index.d.ts.map +1 -1
- package/dist/index.esm.js +124 -19
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +124 -17
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the EmptyState component
|
|
4
|
+
* @interface EmptyStateProps
|
|
5
|
+
*/
|
|
6
|
+
export interface EmptyStateProps {
|
|
7
|
+
/** Optional icon (usually a lucide-react icon) rendered above the message */
|
|
8
|
+
icon?: ReactNode;
|
|
9
|
+
/** Optional heading shown above the message */
|
|
10
|
+
title?: string;
|
|
11
|
+
/** The main message describing why the state is empty and what to do next */
|
|
12
|
+
message: string;
|
|
13
|
+
/** Optional action slot (e.g. a Button CTA) rendered under the message */
|
|
14
|
+
action?: ReactNode;
|
|
15
|
+
/** Size variant — `compact` fits inline slots, `default` fills a panel, `large` fills the viewport */
|
|
16
|
+
size?: 'compact' | 'default' | 'large';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* EmptyState Component
|
|
20
|
+
*
|
|
21
|
+
* @component
|
|
22
|
+
* @description
|
|
23
|
+
* A composable placeholder for empty lists, empty sidebars, and
|
|
24
|
+
* "nothing to show" panels. Renders an icon, optional title, message,
|
|
25
|
+
* and optional action CTA in a vertically-centered stack. Pure layout —
|
|
26
|
+
* no fetching, no state.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Minimal: just a message
|
|
30
|
+
* <EmptyState message="No documents yet." />
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // With an icon
|
|
34
|
+
* import { FileText } from 'lucide-react';
|
|
35
|
+
* <EmptyState
|
|
36
|
+
* icon={<FileText size={32} />}
|
|
37
|
+
* message="Select a document from the sidebar to start editing."
|
|
38
|
+
* />
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // Full: icon + title + message + action
|
|
42
|
+
* <EmptyState
|
|
43
|
+
* icon={<FolderKanban size={40} />}
|
|
44
|
+
* title="No projects"
|
|
45
|
+
* message="Create your first project to get started."
|
|
46
|
+
* action={<Button onClick={handleCreate}>New project</Button>}
|
|
47
|
+
* />
|
|
48
|
+
*
|
|
49
|
+
* @param {EmptyStateProps} props - The props for the EmptyState component
|
|
50
|
+
* @returns {JSX.Element} The rendered EmptyState component
|
|
51
|
+
*/
|
|
52
|
+
export declare const EmptyState: React.FC<EmptyStateProps>;
|
|
53
|
+
//# sourceMappingURL=EmptyState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../../../src/components/atoms/EmptyState/EmptyState.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGzC;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,6EAA6E;IAC7E,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,sGAAsG;IACtG,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAgBhD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/atoms/EmptyState/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the Modal component
|
|
4
|
+
* @interface ModalProps
|
|
5
|
+
*/
|
|
6
|
+
export interface ModalProps {
|
|
7
|
+
/** Whether the modal is currently visible */
|
|
8
|
+
open: boolean;
|
|
9
|
+
/** Title shown in the modal header */
|
|
10
|
+
title: string;
|
|
11
|
+
/** Callback fired when the user requests to close the modal (backdrop click, Escape, or X button) */
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
/** Modal body content */
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
/** Width variant. `default` fits typical forms; `compact` is narrower; `wide` is for editors */
|
|
16
|
+
size?: 'default' | 'compact' | 'wide';
|
|
17
|
+
/** Optional slot rendered in the header next to the close button (e.g. action buttons) */
|
|
18
|
+
actions?: ReactNode;
|
|
19
|
+
/** When true, the body is padded; when false, the body is flush to the edges */
|
|
20
|
+
padding?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Modal Component
|
|
24
|
+
*
|
|
25
|
+
* @component
|
|
26
|
+
* @description
|
|
27
|
+
* An accessible overlay dialog with a backdrop, title header, optional
|
|
28
|
+
* header actions, and a flexible body. Renders into a React portal on
|
|
29
|
+
* `document.body`, animates in/out with Framer Motion, closes on Escape
|
|
30
|
+
* key or backdrop click, and clicks inside the dialog don't propagate
|
|
31
|
+
* to the backdrop.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Basic usage
|
|
35
|
+
* <Modal open={isOpen} title="Confirm" onClose={() => setIsOpen(false)}>
|
|
36
|
+
* <p>Are you sure?</p>
|
|
37
|
+
* </Modal>
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* // With header actions and wide size
|
|
41
|
+
* <Modal
|
|
42
|
+
* open={isOpen}
|
|
43
|
+
* title="Edit profile"
|
|
44
|
+
* size="wide"
|
|
45
|
+
* actions={<button onClick={save}>Save</button>}
|
|
46
|
+
* onClose={handleClose}
|
|
47
|
+
* >
|
|
48
|
+
* <ProfileForm />
|
|
49
|
+
* </Modal>
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // Flush body (no padding) for editors and full-bleed content
|
|
53
|
+
* <Modal open={isOpen} title="Document" padding={false} onClose={handleClose}>
|
|
54
|
+
* <DocEditor content={content} onSave={save} />
|
|
55
|
+
* </Modal>
|
|
56
|
+
*
|
|
57
|
+
* @param {ModalProps} props - The props for the Modal component
|
|
58
|
+
* @returns {React.ReactPortal | null} A portal rendering the modal, or null on the server
|
|
59
|
+
*/
|
|
60
|
+
export declare const Modal: React.FC<ModalProps>;
|
|
61
|
+
//# sourceMappingURL=Modal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../../../src/components/atoms/Modal/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAMpD;;;GAGG;AACH,MAAM,WAAW,UAAU;IAC1B,6CAA6C;IAC7C,IAAI,EAAE,OAAO,CAAC;IACd,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,qGAAqG;IACrG,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,yBAAyB;IACzB,QAAQ,EAAE,SAAS,CAAC;IACpB,gGAAgG;IAChG,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACtC,0FAA0F;IAC1F,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CAsEtC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/atoms/Modal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -2,6 +2,10 @@ export { Button } from './Button';
|
|
|
2
2
|
export type { ButtonProps } from './Button';
|
|
3
3
|
export { Card } from './Card';
|
|
4
4
|
export type { CardProps } from './Card';
|
|
5
|
+
export { EmptyState } from './EmptyState';
|
|
6
|
+
export type { EmptyStateProps } from './EmptyState';
|
|
7
|
+
export { Modal } from './Modal';
|
|
8
|
+
export type { ModalProps } from './Modal';
|
|
5
9
|
export { Checkbox } from './Checkbox';
|
|
6
10
|
export type { CheckboxProps } from './Checkbox';
|
|
7
11
|
export { DateInput } from './DateInput';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/atoms/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/atoms/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAGpE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGvE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import React, { createContext, useContext, useState, useEffect, useRef, useCallback, useMemo, memo } from 'react';
|
|
3
3
|
import { motion, AnimatePresence, LayoutGroup } from 'framer-motion';
|
|
4
|
-
import {
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
5
|
+
import { X, Check, Edit } from 'lucide-react';
|
|
5
6
|
import * as d3 from 'd3';
|
|
6
7
|
|
|
7
8
|
const ThemeContext$1 = createContext(undefined);
|
|
@@ -30,7 +31,7 @@ const ThemeProvider = ({ children, defaultTheme = 'light' }) => {
|
|
|
30
31
|
return (jsx(ThemeContext$1.Provider, { value: { theme, toggleTheme, setTheme }, children: children }));
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
var styles$
|
|
34
|
+
var styles$u = {"button":"Button-module_button__c6nkW","primary":"Button-module_primary__pMqAs","secondary":"Button-module_secondary__mBWx9","outline":"Button-module_outline__NGGGN","ghost":"Button-module_ghost__u2QBF","danger":"Button-module_danger__2ewhr","small":"Button-module_small__ZI9RX","medium":"Button-module_medium__Wnf9t","large":"Button-module_large__cQCpA","fullWidth":"Button-module_fullWidth__N8vYg","loading":"Button-module_loading__hcSI4","spinner":"Button-module_spinner__HtM96","spin":"Button-module_spin__jblrj","iconLeft":"Button-module_iconLeft__Fpz-y","iconRight":"Button-module_iconRight__kTfjS"};
|
|
34
35
|
|
|
35
36
|
const SOUND_PACKS = {
|
|
36
37
|
digital: {
|
|
@@ -595,11 +596,11 @@ function useComponentSound(config, options) {
|
|
|
595
596
|
const Button = ({ variant = 'primary', size = 'medium', fullWidth = false, loading = false, iconLeft, iconRight, children, className = '', disabled, motionProps, soundConfig, onClick, onMouseEnter, onFocus, ...rest }) => {
|
|
596
597
|
const { handlers } = useComponentSound(soundConfig);
|
|
597
598
|
const buttonClasses = [
|
|
598
|
-
styles$
|
|
599
|
-
styles$
|
|
600
|
-
styles$
|
|
601
|
-
fullWidth && styles$
|
|
602
|
-
loading && styles$
|
|
599
|
+
styles$u.button,
|
|
600
|
+
styles$u[variant],
|
|
601
|
+
styles$u[size],
|
|
602
|
+
fullWidth && styles$u.fullWidth,
|
|
603
|
+
loading && styles$u.loading,
|
|
603
604
|
className
|
|
604
605
|
].filter(Boolean).join(' ');
|
|
605
606
|
const handleClick = (e) => {
|
|
@@ -610,10 +611,10 @@ const Button = ({ variant = 'primary', size = 'medium', fullWidth = false, loadi
|
|
|
610
611
|
handlers.onMouseEnter?.();
|
|
611
612
|
onMouseEnter?.(e);
|
|
612
613
|
};
|
|
613
|
-
return (jsxs(motion.button, { className: buttonClasses, disabled: disabled || loading, whileHover: { scale: disabled || loading ? 1 : 1.02 }, whileTap: { scale: disabled || loading ? 1 : 0.98 }, transition: { type: "spring", stiffness: 400, damping: 17 }, onClick: handleClick, onMouseEnter: handleMouseEnter, onFocus: onFocus, ...motionProps, ...rest, children: [loading && jsx("span", { className: styles$
|
|
614
|
+
return (jsxs(motion.button, { className: buttonClasses, disabled: disabled || loading, whileHover: { scale: disabled || loading ? 1 : 1.02 }, whileTap: { scale: disabled || loading ? 1 : 0.98 }, transition: { type: "spring", stiffness: 400, damping: 17 }, onClick: handleClick, onMouseEnter: handleMouseEnter, onFocus: onFocus, ...motionProps, ...rest, children: [loading && jsx("span", { className: styles$u.spinner }), iconLeft && jsx("span", { className: styles$u.iconLeft, children: iconLeft }), children, iconRight && jsx("span", { className: styles$u.iconRight, children: iconRight })] }));
|
|
614
615
|
};
|
|
615
616
|
|
|
616
|
-
var styles$
|
|
617
|
+
var styles$t = {"card":"Card-module_card__r2DB2","hoverable":"Card-module_hoverable__X3OpS","elevated":"Card-module_elevated__hGV6-","outlined":"Card-module_outlined__ngRag","flat":"Card-module_flat__xy-xt","glass":"Card-module_glass__Sv-Vs","imageContainer":"Card-module_imageContainer__L4ma6","image":"Card-module_image__bQBt6","header":"Card-module_header__0dtj3","headerContent":"Card-module_headerContent__W7-jD","expandButton":"Card-module_expandButton__I7f49","expandIcon":"Card-module_expandIcon__Lu-OY","expandableContent":"Card-module_expandableContent__BFgO5","expandable":"Card-module_expandable__GMXzo","body":"Card-module_body__K7eL3","footer":"Card-module_footer__L5wO-","title":"Card-module_title__pW9g8","subtitle":"Card-module_subtitle__gejH4","clickable":"Card-module_clickable__Y6fm8","padding":"Card-module_padding__wtyDo","noPadding":"Card-module_noPadding__r5Qq0","loading":"Card-module_loading__S4Wng","loadingShimmer":"Card-module_loadingShimmer__Q1Osr","loadingPulse":"Card-module_loadingPulse__bXQmC"};
|
|
617
618
|
|
|
618
619
|
/**
|
|
619
620
|
* Card Component
|
|
@@ -678,27 +679,131 @@ const Card = ({ variant = 'elevated', hoverable = false, clickable = false, padd
|
|
|
678
679
|
onExpandChange?.(newExpanded);
|
|
679
680
|
};
|
|
680
681
|
const cardClasses = [
|
|
681
|
-
styles$
|
|
682
|
-
styles$
|
|
683
|
-
hoverable && styles$
|
|
684
|
-
clickable && styles$
|
|
685
|
-
!padding && styles$
|
|
686
|
-
expandable && styles$
|
|
682
|
+
styles$t.card,
|
|
683
|
+
styles$t[variant],
|
|
684
|
+
hoverable && styles$t.hoverable,
|
|
685
|
+
clickable && styles$t.clickable,
|
|
686
|
+
!padding && styles$t.noPadding,
|
|
687
|
+
expandable && styles$t.expandable,
|
|
687
688
|
className
|
|
688
689
|
].filter(Boolean).join(' ');
|
|
689
690
|
const renderHeader = () => {
|
|
690
691
|
if (header) {
|
|
691
|
-
return (jsxs("div", { className: styles$
|
|
692
|
+
return (jsxs("div", { className: styles$t.header, children: [jsx("div", { className: styles$t.headerContent, children: header }), expandable && (jsx("button", { className: styles$t.expandButton, onClick: handleToggleExpand, "aria-label": isExpanded ? 'Collapse card' : 'Expand card', children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: styles$t.expandIcon, style: { transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)' }, children: jsx("path", { d: "M6 9l6 6 6-6" }) }) }))] }));
|
|
692
693
|
}
|
|
693
694
|
if (title || subtitle) {
|
|
694
|
-
return (jsxs("div", { className: styles$
|
|
695
|
+
return (jsxs("div", { className: styles$t.header, children: [jsxs("div", { className: styles$t.headerContent, children: [title && jsx("h3", { className: styles$t.title, children: title }), subtitle && jsx("p", { className: styles$t.subtitle, children: subtitle })] }), expandable && (jsx("button", { className: styles$t.expandButton, onClick: handleToggleExpand, "aria-label": isExpanded ? 'Collapse card' : 'Expand card', children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: styles$t.expandIcon, style: { transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)' }, children: jsx("path", { d: "M6 9l6 6 6-6" }) }) }))] }));
|
|
695
696
|
}
|
|
696
697
|
return null;
|
|
697
698
|
};
|
|
698
|
-
const cardContent = (jsxs(Fragment, { children: [image && (jsx("div", { className: styles$
|
|
699
|
+
const cardContent = (jsxs(Fragment, { children: [image && (jsx("div", { className: styles$t.imageContainer, children: jsx("img", { src: image, alt: imageAlt, className: styles$t.image }) })), renderHeader(), jsx(AnimatePresence, { initial: false, children: (!expandable || isExpanded) && (jsxs(motion.div, { initial: expandable ? { height: 0, opacity: 0 } : undefined, animate: expandable ? { height: 'auto', opacity: 1 } : undefined, exit: expandable ? { height: 0, opacity: 0 } : undefined, transition: { duration: 0.3, ease: "easeInOut" }, className: styles$t.expandableContent, children: [children && (jsx("div", { className: padding ? styles$t.body : undefined, children: children })), footer && jsx("div", { className: styles$t.footer, children: footer })] }, "content")) })] }));
|
|
699
700
|
return (jsx(motion.div, { className: cardClasses, onClick: clickable ? onClick : undefined, whileHover: hoverable ? { y: -4 } : undefined, transition: { type: "spring", stiffness: 400, damping: 17 }, ...motionProps, ...rest, children: cardContent }));
|
|
700
701
|
};
|
|
701
702
|
|
|
703
|
+
var styles$s = {"wrapper":"EmptyState-module_wrapper__h3Y2E","compact":"EmptyState-module_compact__HdYu1","default":"EmptyState-module_default__ACAbn","large":"EmptyState-module_large__H3ELo","icon":"EmptyState-module_icon__i7-3M","title":"EmptyState-module_title__xCyfH","message":"EmptyState-module_message__Bc5xK","action":"EmptyState-module_action__UpnvZ"};
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* EmptyState Component
|
|
707
|
+
*
|
|
708
|
+
* @component
|
|
709
|
+
* @description
|
|
710
|
+
* A composable placeholder for empty lists, empty sidebars, and
|
|
711
|
+
* "nothing to show" panels. Renders an icon, optional title, message,
|
|
712
|
+
* and optional action CTA in a vertically-centered stack. Pure layout —
|
|
713
|
+
* no fetching, no state.
|
|
714
|
+
*
|
|
715
|
+
* @example
|
|
716
|
+
* // Minimal: just a message
|
|
717
|
+
* <EmptyState message="No documents yet." />
|
|
718
|
+
*
|
|
719
|
+
* @example
|
|
720
|
+
* // With an icon
|
|
721
|
+
* import { FileText } from 'lucide-react';
|
|
722
|
+
* <EmptyState
|
|
723
|
+
* icon={<FileText size={32} />}
|
|
724
|
+
* message="Select a document from the sidebar to start editing."
|
|
725
|
+
* />
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* // Full: icon + title + message + action
|
|
729
|
+
* <EmptyState
|
|
730
|
+
* icon={<FolderKanban size={40} />}
|
|
731
|
+
* title="No projects"
|
|
732
|
+
* message="Create your first project to get started."
|
|
733
|
+
* action={<Button onClick={handleCreate}>New project</Button>}
|
|
734
|
+
* />
|
|
735
|
+
*
|
|
736
|
+
* @param {EmptyStateProps} props - The props for the EmptyState component
|
|
737
|
+
* @returns {JSX.Element} The rendered EmptyState component
|
|
738
|
+
*/
|
|
739
|
+
const EmptyState = ({ icon, title, message, action, size = 'default', }) => {
|
|
740
|
+
const wrapperClass = [styles$s.wrapper, styles$s[size]].filter(Boolean).join(' ');
|
|
741
|
+
return (jsxs("div", { className: wrapperClass, children: [icon && jsx("div", { className: styles$s.icon, children: icon }), title && jsx("h3", { className: styles$s.title, children: title }), jsx("p", { className: styles$s.message, children: message }), action && jsx("div", { className: styles$s.action, children: action })] }));
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
var styles$r = {"backdrop":"Modal-module_backdrop__yOx-a","dialog":"Modal-module_dialog__yEXTq","dialogCompact":"Modal-module_dialogCompact__z1Wxp","dialogWide":"Modal-module_dialogWide__9PTXK","header":"Modal-module_header__NHHKd","title":"Modal-module_title__i3R0x","headerActions":"Modal-module_headerActions__g28UN","closeButton":"Modal-module_closeButton__siC-1","body":"Modal-module_body__U7jvM","bodyFlush":"Modal-module_bodyFlush__wtk3q"};
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Modal Component
|
|
748
|
+
*
|
|
749
|
+
* @component
|
|
750
|
+
* @description
|
|
751
|
+
* An accessible overlay dialog with a backdrop, title header, optional
|
|
752
|
+
* header actions, and a flexible body. Renders into a React portal on
|
|
753
|
+
* `document.body`, animates in/out with Framer Motion, closes on Escape
|
|
754
|
+
* key or backdrop click, and clicks inside the dialog don't propagate
|
|
755
|
+
* to the backdrop.
|
|
756
|
+
*
|
|
757
|
+
* @example
|
|
758
|
+
* // Basic usage
|
|
759
|
+
* <Modal open={isOpen} title="Confirm" onClose={() => setIsOpen(false)}>
|
|
760
|
+
* <p>Are you sure?</p>
|
|
761
|
+
* </Modal>
|
|
762
|
+
*
|
|
763
|
+
* @example
|
|
764
|
+
* // With header actions and wide size
|
|
765
|
+
* <Modal
|
|
766
|
+
* open={isOpen}
|
|
767
|
+
* title="Edit profile"
|
|
768
|
+
* size="wide"
|
|
769
|
+
* actions={<button onClick={save}>Save</button>}
|
|
770
|
+
* onClose={handleClose}
|
|
771
|
+
* >
|
|
772
|
+
* <ProfileForm />
|
|
773
|
+
* </Modal>
|
|
774
|
+
*
|
|
775
|
+
* @example
|
|
776
|
+
* // Flush body (no padding) for editors and full-bleed content
|
|
777
|
+
* <Modal open={isOpen} title="Document" padding={false} onClose={handleClose}>
|
|
778
|
+
* <DocEditor content={content} onSave={save} />
|
|
779
|
+
* </Modal>
|
|
780
|
+
*
|
|
781
|
+
* @param {ModalProps} props - The props for the Modal component
|
|
782
|
+
* @returns {React.ReactPortal | null} A portal rendering the modal, or null on the server
|
|
783
|
+
*/
|
|
784
|
+
const Modal = ({ open, title, onClose, children, size = 'default', actions, padding = true, }) => {
|
|
785
|
+
useEffect(() => {
|
|
786
|
+
if (!open)
|
|
787
|
+
return;
|
|
788
|
+
const onKey = (e) => {
|
|
789
|
+
if (e.key === 'Escape')
|
|
790
|
+
onClose();
|
|
791
|
+
};
|
|
792
|
+
document.addEventListener('keydown', onKey);
|
|
793
|
+
return () => document.removeEventListener('keydown', onKey);
|
|
794
|
+
}, [open, onClose]);
|
|
795
|
+
if (typeof document === 'undefined')
|
|
796
|
+
return null;
|
|
797
|
+
const dialogClass = [
|
|
798
|
+
styles$r.dialog,
|
|
799
|
+
size === 'compact' && styles$r.dialogCompact,
|
|
800
|
+
size === 'wide' && styles$r.dialogWide,
|
|
801
|
+
]
|
|
802
|
+
.filter(Boolean)
|
|
803
|
+
.join(' ');
|
|
804
|
+
return createPortal(jsx(AnimatePresence, { children: open && (jsx(motion.div, { className: styles$r.backdrop, initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.15 }, onClick: onClose, "aria-hidden": "true", children: jsxs(motion.div, { className: dialogClass, role: "dialog", "aria-modal": "true", "aria-label": title, initial: { opacity: 0, scale: 0.96, y: 8 }, animate: { opacity: 1, scale: 1, y: 0 }, exit: { opacity: 0, scale: 0.96, y: 8 }, transition: { duration: 0.15, ease: 'easeOut' }, onClick: (e) => e.stopPropagation(), children: [jsxs("div", { className: styles$r.header, children: [jsx("span", { className: styles$r.title, children: title }), actions && jsx("div", { className: styles$r.headerActions, children: actions }), jsx("button", { className: styles$r.closeButton, onClick: onClose, "aria-label": "Close modal", type: "button", children: jsx(X, { size: 16 }) })] }), jsx("div", { className: padding ? styles$r.body : styles$r.bodyFlush, children: children })] }) })) }), document.body);
|
|
805
|
+
};
|
|
806
|
+
|
|
702
807
|
var styles$q = {"checkboxLabel":"Checkbox-module_checkboxLabel__4tBVg","checkbox":"Checkbox-module_checkbox__BbJul","checkboxText":"Checkbox-module_checkboxText__oJsc9"};
|
|
703
808
|
|
|
704
809
|
/**
|
|
@@ -5128,5 +5233,5 @@ function formatValue(value) {
|
|
|
5128
5233
|
// Memoized Table component to prevent unnecessary re-renders
|
|
5129
5234
|
const Table = memo(TableComponent);
|
|
5130
5235
|
|
|
5131
|
-
export { ArrayInput, BooleansHeatmap, Button, Calendar, Card, Checkbox, DateInput, EditFAB, ImageSlideshow, LoadingSpinner, MoodChart, Navbar, NumberStepper, PieChart, QuantifiableHabitsChart, SearchBar, SearchableDropdown, SelectInput, SleepChart, Slider, SunburstChart, Table, Tabs, TextArea, TextInput, ThemeProvider, ThemeSwitcher, TimeInput, Toggle, ToggleButton, soundManager, useComponentSound, useSound, useTheme$1 as useTheme };
|
|
5236
|
+
export { ArrayInput, BooleansHeatmap, Button, Calendar, Card, Checkbox, DateInput, EditFAB, EmptyState, ImageSlideshow, LoadingSpinner, Modal, MoodChart, Navbar, NumberStepper, PieChart, QuantifiableHabitsChart, SearchBar, SearchableDropdown, SelectInput, SleepChart, Slider, SunburstChart, Table, Tabs, TextArea, TextInput, ThemeProvider, ThemeSwitcher, TimeInput, Toggle, ToggleButton, soundManager, useComponentSound, useSound, useTheme$1 as useTheme };
|
|
5132
5237
|
//# sourceMappingURL=index.esm.js.map
|