doom-design-system 0.1.3 → 0.1.4
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/README.md +5 -2
- package/dist/components/Accordion/Accordion.d.ts +17 -0
- package/dist/components/Accordion/Accordion.js +94 -0
- package/dist/components/Accordion/index.d.ts +1 -0
- package/dist/components/Accordion/index.js +1 -0
- package/dist/components/Alert/Alert.d.ts +11 -0
- package/dist/components/Alert/Alert.js +70 -0
- package/dist/components/Alert/index.d.ts +1 -0
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/Avatar/Avatar.d.ts +13 -0
- package/dist/components/Avatar/Avatar.js +51 -0
- package/dist/components/Avatar/index.d.ts +1 -0
- package/dist/components/Avatar/index.js +1 -0
- package/dist/components/Badge/Badge.js +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +13 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.js +46 -0
- package/dist/components/Breadcrumbs/index.d.ts +1 -0
- package/dist/components/Breadcrumbs/index.js +1 -0
- package/dist/components/Button/Button.js +39 -6
- package/dist/components/Card/Card.js +1 -1
- package/dist/components/Drawer/Drawer.d.ts +12 -0
- package/dist/components/Drawer/Drawer.js +101 -0
- package/dist/components/Drawer/index.d.ts +1 -0
- package/dist/components/Drawer/index.js +1 -0
- package/dist/components/Form/Form.d.ts +20 -7
- package/dist/components/Form/Form.js +49 -9
- package/dist/components/Input/Input.d.ts +1 -1
- package/dist/components/Input/Input.js +27 -60
- package/dist/components/Label/Label.d.ts +6 -0
- package/dist/components/Label/Label.js +38 -0
- package/dist/components/Label/index.d.ts +1 -0
- package/dist/components/Label/index.js +1 -0
- package/dist/components/Link/Link.js +1 -1
- package/dist/components/Modal/Modal.js +7 -7
- package/dist/components/Pagination/Pagination.d.ts +8 -0
- package/dist/components/Pagination/Pagination.js +94 -0
- package/dist/components/Pagination/index.d.ts +1 -0
- package/dist/components/Pagination/index.js +1 -0
- package/dist/components/Popover/Popover.d.ts +1 -1
- package/dist/components/Popover/Popover.js +47 -29
- package/dist/components/RadioGroup/RadioGroup.d.ts +19 -0
- package/dist/components/RadioGroup/RadioGroup.js +101 -0
- package/dist/components/RadioGroup/index.d.ts +1 -0
- package/dist/components/RadioGroup/index.js +1 -0
- package/dist/components/Select/Select.js +5 -17
- package/dist/components/Sheet/Sheet.d.ts +10 -0
- package/dist/components/Sheet/Sheet.js +87 -0
- package/dist/components/Sheet/index.d.ts +1 -0
- package/dist/components/Sheet/index.js +1 -0
- package/dist/components/Slider/Slider.d.ts +10 -0
- package/dist/components/Slider/Slider.js +168 -0
- package/dist/components/Slider/index.d.ts +1 -0
- package/dist/components/Slider/index.js +1 -0
- package/dist/components/Switch/Switch.d.ts +11 -0
- package/dist/components/Switch/Switch.js +77 -0
- package/dist/components/Switch/index.d.ts +1 -0
- package/dist/components/Switch/index.js +1 -0
- package/dist/components/Table/Table.js +6 -6
- package/dist/components/Tabs/Tabs.js +6 -9
- package/dist/components/Textarea/Textarea.js +3 -10
- package/dist/components/Toast/Toast.js +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts +9 -0
- package/dist/components/Tooltip/Tooltip.js +37 -0
- package/dist/components/Tooltip/index.d.ts +1 -0
- package/dist/components/Tooltip/index.js +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/styles/mixins.d.ts +3 -0
- package/dist/styles/mixins.js +25 -0
- package/dist/styles/themes/definitions.d.ts +112 -0
- package/dist/styles/themes/definitions.js +37 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
3
|
var t = {};
|
|
3
4
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
@@ -9,16 +10,55 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
10
|
}
|
|
10
11
|
return t;
|
|
11
12
|
};
|
|
12
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
+
import styled from '@emotion/styled';
|
|
15
|
+
import { css } from '@emotion/react';
|
|
16
|
+
const StyledForm = styled.form `
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
gap: 1.5rem;
|
|
20
|
+
width: 100%;
|
|
21
|
+
`;
|
|
22
|
+
const StyledField = styled.div `
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
gap: 0.5rem;
|
|
26
|
+
width: 100%;
|
|
27
|
+
|
|
28
|
+
`;
|
|
29
|
+
import { Label } from '../Label/Label';
|
|
30
|
+
export { Label };
|
|
31
|
+
const StyledMessage = styled.span `
|
|
32
|
+
font-size: 0.75rem;
|
|
33
|
+
font-weight: 500;
|
|
34
|
+
|
|
35
|
+
${props => props.variant === 'error' && css `
|
|
36
|
+
color: var(--error);
|
|
37
|
+
font-weight: 700;
|
|
38
|
+
text-transform: uppercase;
|
|
39
|
+
animation: shake 0.3s ease-in-out;
|
|
40
|
+
`}
|
|
41
|
+
|
|
42
|
+
${props => props.variant === 'description' && css `
|
|
43
|
+
color: var(--muted-foreground);
|
|
44
|
+
`}
|
|
45
|
+
|
|
46
|
+
@keyframes shake {
|
|
47
|
+
0%, 100% { transform: translateX(0); }
|
|
48
|
+
25% { transform: translateX(-4px); }
|
|
49
|
+
75% { transform: translateX(4px); }
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
13
52
|
export function Form(_a) {
|
|
14
|
-
var { children
|
|
15
|
-
return
|
|
53
|
+
var { children } = _a, props = __rest(_a, ["children"]);
|
|
54
|
+
return _jsx(StyledForm, Object.assign({}, props, { children: children }));
|
|
16
55
|
}
|
|
17
|
-
export function
|
|
18
|
-
var { children,
|
|
19
|
-
return
|
|
56
|
+
export function FormMessage(_a) {
|
|
57
|
+
var { children, variant = 'description' } = _a, props = __rest(_a, ["children", "variant"]);
|
|
58
|
+
return _jsx(StyledMessage, Object.assign({ variant: variant }, props, { children: children }));
|
|
20
59
|
}
|
|
21
|
-
export function
|
|
22
|
-
var { children,
|
|
23
|
-
return (
|
|
60
|
+
export function Field(_a) {
|
|
61
|
+
var { children, label, error, description, htmlFor, required } = _a, props = __rest(_a, ["children", "label", "error", "description", "htmlFor", "required"]);
|
|
62
|
+
return (_jsxs(StyledField, Object.assign({ error: !!error }, props, { children: [label && (_jsx(Label, { htmlFor: htmlFor, required: required, children: label })), children, description && !error && (_jsx(FormMessage, { variant: "description", children: description })), error && typeof error === 'string' && (_jsx(FormMessage, { variant: "error", children: error }))] })));
|
|
24
63
|
}
|
|
64
|
+
export const FormGroup = StyledField;
|
|
@@ -8,5 +8,5 @@ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
|
8
8
|
format?: (value: string | number | readonly string[] | undefined) => string;
|
|
9
9
|
validate?: (value: string | number | readonly string[] | undefined) => string | undefined;
|
|
10
10
|
}
|
|
11
|
-
export declare function Input({ label, error: errorProp, helperText, startAdornment, endAdornment, style, className, format, validate, onBlur, onFocus, value, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function Input({ label, error: errorProp, helperText, startAdornment, endAdornment, style, className, format, validate, onBlur, onFocus, value, id, required, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
|
|
12
12
|
export {};
|
|
@@ -13,10 +13,13 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
13
13
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { useState } from 'react';
|
|
15
15
|
import styled from '@emotion/styled';
|
|
16
|
-
import {
|
|
16
|
+
import { css } from '@emotion/react';
|
|
17
|
+
import { Label } from '../Label/Label';
|
|
18
|
+
import { baseInteractiveStyles, focusStyles, errorStyles } from '../../styles/mixins';
|
|
17
19
|
const InputContainer = styled.div `
|
|
18
20
|
display: flex;
|
|
19
21
|
flex-direction: column;
|
|
22
|
+
gap: 0.5rem;
|
|
20
23
|
width: 100%;
|
|
21
24
|
`;
|
|
22
25
|
const InputWrapper = styled.div `
|
|
@@ -33,67 +36,15 @@ const StyledInput = styled.input `
|
|
|
33
36
|
font-size: var(--text-base);
|
|
34
37
|
background: var(--card-bg);
|
|
35
38
|
color: var(--foreground);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
outline: none;
|
|
40
|
-
transition: all 0.1s ease;
|
|
41
|
-
|
|
42
|
-
&:focus {
|
|
43
|
-
box-shadow: var(--shadow-hover);
|
|
44
|
-
transform: translate(-2px, -2px);
|
|
45
|
-
border-color: ${props => props.isError ? 'var(--error)' : 'var(--primary)'};
|
|
46
|
-
}
|
|
39
|
+
|
|
40
|
+
${baseInteractiveStyles}
|
|
41
|
+
${focusStyles}
|
|
47
42
|
|
|
48
43
|
&::placeholder {
|
|
49
44
|
color: var(--muted);
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
background-color: var(--muted-foreground);
|
|
54
|
-
cursor: pointer;
|
|
55
|
-
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");
|
|
56
|
-
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");
|
|
57
|
-
mask-repeat: no-repeat;
|
|
58
|
-
-webkit-mask-repeat: no-repeat;
|
|
59
|
-
mask-position: center;
|
|
60
|
-
-webkit-mask-position: center;
|
|
61
|
-
mask-size: contain;
|
|
62
|
-
-webkit-mask-size: contain;
|
|
63
|
-
transition: background-color 0.2s;
|
|
64
|
-
width: 1em;
|
|
65
|
-
height: 1em;
|
|
66
|
-
|
|
67
|
-
&:hover {
|
|
68
|
-
background-color: var(--foreground);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
&[type="time"]::-webkit-calendar-picker-indicator {
|
|
73
|
-
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");
|
|
74
|
-
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
&::-webkit-search-cancel-button {
|
|
78
|
-
-webkit-appearance: none;
|
|
79
|
-
background-color: var(--muted-foreground);
|
|
80
|
-
cursor: pointer;
|
|
81
|
-
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");
|
|
82
|
-
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");
|
|
83
|
-
mask-repeat: no-repeat;
|
|
84
|
-
-webkit-mask-repeat: no-repeat;
|
|
85
|
-
mask-position: center;
|
|
86
|
-
-webkit-mask-position: center;
|
|
87
|
-
mask-size: contain;
|
|
88
|
-
-webkit-mask-size: contain;
|
|
89
|
-
transition: background-color 0.2s;
|
|
90
|
-
width: 1em;
|
|
91
|
-
height: 1em;
|
|
92
|
-
|
|
93
|
-
&:hover {
|
|
94
|
-
background-color: var(--foreground);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
47
|
+
${props => props.isError && errorStyles}
|
|
97
48
|
`;
|
|
98
49
|
const Adornment = styled.span `
|
|
99
50
|
position: absolute;
|
|
@@ -103,8 +54,25 @@ const Adornment = styled.span `
|
|
|
103
54
|
pointer-events: none;
|
|
104
55
|
z-index: 1;
|
|
105
56
|
`;
|
|
57
|
+
const HelperText = styled.span `
|
|
58
|
+
font-size: var(--text-xs);
|
|
59
|
+
font-weight: var(--font-medium);
|
|
60
|
+
color: ${props => props.isError ? 'var(--error)' : 'var(--muted-foreground)'};
|
|
61
|
+
|
|
62
|
+
${props => props.isError && css `
|
|
63
|
+
font-weight: var(--font-bold);
|
|
64
|
+
text-transform: uppercase;
|
|
65
|
+
animation: input-shake 0.3s ease-in-out;
|
|
66
|
+
`}
|
|
67
|
+
|
|
68
|
+
@keyframes input-shake {
|
|
69
|
+
0%, 100% { transform: translateX(0); }
|
|
70
|
+
25% { transform: translateX(-4px); }
|
|
71
|
+
75% { transform: translateX(4px); }
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
106
74
|
export function Input(_a) {
|
|
107
|
-
var { label, error: errorProp, helperText, startAdornment, endAdornment, style, className, format, validate, onBlur, onFocus, value } = _a, props = __rest(_a, ["label", "error", "helperText", "startAdornment", "endAdornment", "style", "className", "format", "validate", "onBlur", "onFocus", "value"]);
|
|
75
|
+
var { label, error: errorProp, helperText, startAdornment, endAdornment, style, className, format, validate, onBlur, onFocus, value, id, required } = _a, props = __rest(_a, ["label", "error", "helperText", "startAdornment", "endAdornment", "style", "className", "format", "validate", "onBlur", "onFocus", "value", "id", "required"]);
|
|
108
76
|
const [isFocused, setIsFocused] = useState(false);
|
|
109
77
|
const [internalError, setInternalError] = useState(undefined);
|
|
110
78
|
const error = errorProp || internalError;
|
|
@@ -121,9 +89,8 @@ export function Input(_a) {
|
|
|
121
89
|
if (onFocus)
|
|
122
90
|
onFocus(e);
|
|
123
91
|
};
|
|
124
|
-
// Use formatted value when not focused, otherwise raw value
|
|
125
92
|
const displayValue = (!isFocused && format && value !== undefined)
|
|
126
93
|
? format(value)
|
|
127
94
|
: value;
|
|
128
|
-
return (_jsxs(InputContainer, { style: style, className: className, children: [label && (_jsx(
|
|
95
|
+
return (_jsxs(InputContainer, { style: style, className: className, children: [label && (_jsx(Label, { htmlFor: id, required: required, children: label })), _jsxs(InputWrapper, { children: [startAdornment && _jsx(Adornment, { position: "start", children: startAdornment }), _jsx(StyledInput, Object.assign({ id: id, required: required, value: displayValue, hasStartAdornment: !!startAdornment, hasEndAdornment: !!endAdornment, isError: !!error, onBlur: handleBlur, onFocus: handleFocus }, props)), endAdornment && _jsx(Adornment, { position: "end", children: endAdornment })] }), helperText && !error && (_jsx(HelperText, { children: helperText })), error && (_jsx(HelperText, { isError: true, children: error }))] }));
|
|
129
96
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function Label({ children, required, ...props }: LabelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
+
import styled from '@emotion/styled';
|
|
15
|
+
import { css } from '@emotion/react';
|
|
16
|
+
const StyledLabel = styled.label `
|
|
17
|
+
font-family: var(--font-heading);
|
|
18
|
+
font-weight: var(--font-bold);
|
|
19
|
+
font-size: var(--text-sm);
|
|
20
|
+
color: var(--foreground);
|
|
21
|
+
text-transform: uppercase;
|
|
22
|
+
letter-spacing: 0.05em;
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: 0.25rem;
|
|
26
|
+
|
|
27
|
+
${props => props.required && css `
|
|
28
|
+
&::after {
|
|
29
|
+
content: '*';
|
|
30
|
+
color: var(--error);
|
|
31
|
+
margin-left: 0.25rem;
|
|
32
|
+
}
|
|
33
|
+
`}
|
|
34
|
+
`;
|
|
35
|
+
export function Label(_a) {
|
|
36
|
+
var { children, required } = _a, props = __rest(_a, ["children", "required"]);
|
|
37
|
+
return _jsx(StyledLabel, Object.assign({ required: required }, props, { children: children }));
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Label';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Label';
|
|
@@ -9,13 +9,13 @@ const ModalContext = React.createContext({ onClose: () => { } });
|
|
|
9
9
|
const Overlay = styled.div `
|
|
10
10
|
position: fixed;
|
|
11
11
|
inset: 0;
|
|
12
|
-
z-index:
|
|
12
|
+
z-index: var(--z-modal);
|
|
13
13
|
display: flex;
|
|
14
14
|
align-items: center;
|
|
15
15
|
justify-content: center;
|
|
16
|
-
padding:
|
|
16
|
+
padding: var(--spacing-md);
|
|
17
17
|
backdrop-filter: blur(4px);
|
|
18
|
-
background-color: rgba(0, 0, 0,
|
|
18
|
+
background-color: rgba(0, 0, 0, var(--overlay-opacity));
|
|
19
19
|
animation: fadeIn 0.2s ease-out;
|
|
20
20
|
|
|
21
21
|
@keyframes fadeIn {
|
|
@@ -34,21 +34,21 @@ const ContentContainer = styled.div `
|
|
|
34
34
|
}
|
|
35
35
|
`;
|
|
36
36
|
const StyledHeader = styled(Flex) `
|
|
37
|
-
padding:
|
|
37
|
+
padding: var(--spacing-lg);
|
|
38
38
|
border-bottom: var(--border-width) solid var(--card-border);
|
|
39
39
|
background: var(--background);
|
|
40
40
|
|
|
41
41
|
h2 {
|
|
42
|
-
font-size:
|
|
42
|
+
font-size: var(--text-xl);
|
|
43
43
|
font-weight: bold;
|
|
44
44
|
margin: 0;
|
|
45
45
|
}
|
|
46
46
|
`;
|
|
47
47
|
const StyledBody = styled.div `
|
|
48
|
-
padding:
|
|
48
|
+
padding: var(--spacing-lg);
|
|
49
49
|
`;
|
|
50
50
|
const StyledFooter = styled.div `
|
|
51
|
-
padding:
|
|
51
|
+
padding: var(--spacing-lg);
|
|
52
52
|
border-top: var(--border-width) solid var(--card-border);
|
|
53
53
|
background: var(--background);
|
|
54
54
|
`;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface PaginationProps {
|
|
2
|
+
currentPage: number;
|
|
3
|
+
totalPages: number;
|
|
4
|
+
onPageChange: (page: number) => void;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function Pagination({ currentPage, totalPages, onPageChange, className }: PaginationProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import styled from '@emotion/styled';
|
|
4
|
+
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
|
|
5
|
+
const PaginationNav = styled.nav `
|
|
6
|
+
display: flex;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
align-items: center;
|
|
9
|
+
gap: 0.5rem;
|
|
10
|
+
`;
|
|
11
|
+
const PageButton = styled.button `
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
width: 40px;
|
|
16
|
+
height: 40px;
|
|
17
|
+
border: var(--border-width) solid var(--card-border);
|
|
18
|
+
border-radius: var(--radius);
|
|
19
|
+
background-color: ${props => props.isActive ? 'var(--primary)' : 'var(--card-bg)'};
|
|
20
|
+
color: ${props => props.isActive ? 'var(--primary-foreground)' : 'var(--foreground)'};
|
|
21
|
+
font-family: var(--font-heading);
|
|
22
|
+
font-weight: 700;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
box-shadow: ${props => props.isActive ? 'var(--shadow-sm)' : 'none'};
|
|
25
|
+
|
|
26
|
+
&:hover:not(:disabled) {
|
|
27
|
+
transform: translate(-2px, -2px);
|
|
28
|
+
box-shadow: var(--shadow-sm);
|
|
29
|
+
background-color: var(--primary);
|
|
30
|
+
color: var(--primary-foreground);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&:active:not(:disabled) {
|
|
34
|
+
transform: translate(0, 0);
|
|
35
|
+
box-shadow: none;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&:disabled {
|
|
39
|
+
opacity: 0.5;
|
|
40
|
+
cursor: not-allowed;
|
|
41
|
+
background-color: var(--muted);
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
export function Pagination({ currentPage, totalPages, onPageChange, className }) {
|
|
45
|
+
const handlePageChange = (page) => {
|
|
46
|
+
if (page >= 1 && page <= totalPages && page !== currentPage) {
|
|
47
|
+
onPageChange(page);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const renderPageNumbers = () => {
|
|
51
|
+
const pages = [];
|
|
52
|
+
const maxVisible = 7; // Max buttons to show
|
|
53
|
+
if (totalPages <= maxVisible) {
|
|
54
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
55
|
+
pages.push(i);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Complex truncation logic
|
|
60
|
+
if (currentPage <= 4) {
|
|
61
|
+
// Near start: 1 2 3 4 5 ... N
|
|
62
|
+
for (let i = 1; i <= 5; i++)
|
|
63
|
+
pages.push(i);
|
|
64
|
+
pages.push('ellipsis');
|
|
65
|
+
pages.push(totalPages);
|
|
66
|
+
}
|
|
67
|
+
else if (currentPage >= totalPages - 3) {
|
|
68
|
+
// Near end: 1 ... N-4 N-3 N-2 N-1 N
|
|
69
|
+
pages.push(1);
|
|
70
|
+
pages.push('ellipsis');
|
|
71
|
+
for (let i = totalPages - 4; i <= totalPages; i++)
|
|
72
|
+
pages.push(i);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Middle: 1 ... C-1 C C+1 ... N
|
|
76
|
+
pages.push(1);
|
|
77
|
+
pages.push('ellipsis');
|
|
78
|
+
pages.push(currentPage - 1);
|
|
79
|
+
pages.push(currentPage);
|
|
80
|
+
pages.push(currentPage + 1);
|
|
81
|
+
pages.push('ellipsis');
|
|
82
|
+
pages.push(totalPages);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return pages.map((page, index) => {
|
|
86
|
+
if (page === 'ellipsis') {
|
|
87
|
+
return (_jsx("span", { style: { display: 'flex', alignItems: 'center' }, children: _jsx(MoreHorizontal, { size: 20 }) }, `ellipsis-${index}`));
|
|
88
|
+
}
|
|
89
|
+
const pageNum = page;
|
|
90
|
+
return (_jsx(PageButton, { isActive: currentPage === pageNum, onClick: () => handlePageChange(pageNum), "aria-current": currentPage === pageNum ? 'page' : undefined, children: pageNum }, pageNum));
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
return (_jsxs(PaginationNav, { "aria-label": "pagination", className: className, children: [_jsx(PageButton, { onClick: () => handlePageChange(currentPage - 1), disabled: currentPage === 1, "aria-label": "Go to previous page", children: _jsx(ChevronLeft, { size: 20, strokeWidth: 2.5 }) }), renderPageNumbers(), _jsx(PageButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages, "aria-label": "Go to next page", children: _jsx(ChevronRight, { size: 20, strokeWidth: 2.5 }) })] }));
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Pagination } from './Pagination';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Pagination } from './Pagination';
|
|
@@ -4,7 +4,7 @@ interface PopoverProps {
|
|
|
4
4
|
content: React.ReactNode;
|
|
5
5
|
isOpen: boolean;
|
|
6
6
|
onClose: () => void;
|
|
7
|
-
placement?: 'bottom-start' | 'bottom-end' | 'bottom-center';
|
|
7
|
+
placement?: 'bottom-start' | 'bottom-end' | 'bottom-center' | 'top-start' | 'top-end' | 'top-center';
|
|
8
8
|
offset?: number;
|
|
9
9
|
}
|
|
10
10
|
export declare function Popover({ trigger, content, isOpen, onClose, placement, offset }: PopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx,
|
|
3
|
-
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef, useEffect, useCallback, useLayoutEffect } from 'react';
|
|
4
4
|
import { createPortal } from 'react-dom';
|
|
5
|
+
import { keyframes } from '@emotion/react';
|
|
6
|
+
const popoverScale = keyframes `
|
|
7
|
+
from { opacity: 0; transform: scale(0.95); }
|
|
8
|
+
to { opacity: 1; transform: scale(1); }
|
|
9
|
+
`;
|
|
5
10
|
export function Popover({ trigger, content, isOpen, onClose, placement = 'bottom-start', offset = 8 }) {
|
|
6
11
|
const triggerRef = useRef(null);
|
|
7
12
|
const contentRef = useRef(null);
|
|
@@ -14,42 +19,60 @@ export function Popover({ trigger, content, isOpen, onClose, placement = 'bottom
|
|
|
14
19
|
const contentRect = contentRef.current.getBoundingClientRect();
|
|
15
20
|
const viewportWidth = window.innerWidth;
|
|
16
21
|
const viewportHeight = window.innerHeight;
|
|
17
|
-
let top =
|
|
18
|
-
let left =
|
|
19
|
-
let origin = 'top
|
|
20
|
-
|
|
21
|
-
if (
|
|
22
|
+
let top = 0;
|
|
23
|
+
let left = 0;
|
|
24
|
+
let origin = 'top center';
|
|
25
|
+
const isTop = placement.startsWith('top');
|
|
26
|
+
if (isTop) {
|
|
22
27
|
top = triggerRect.top - contentRect.height - offset;
|
|
23
28
|
origin = 'bottom';
|
|
29
|
+
if (top < 0) {
|
|
30
|
+
top = triggerRect.bottom + offset;
|
|
31
|
+
origin = 'top';
|
|
32
|
+
}
|
|
24
33
|
}
|
|
25
34
|
else {
|
|
35
|
+
top = triggerRect.bottom + offset;
|
|
26
36
|
origin = 'top';
|
|
37
|
+
if (top + contentRect.height > viewportHeight) {
|
|
38
|
+
top = triggerRect.top - contentRect.height - offset;
|
|
39
|
+
origin = 'bottom';
|
|
40
|
+
}
|
|
27
41
|
}
|
|
28
|
-
|
|
29
|
-
if (
|
|
42
|
+
const align = placement.split('-')[1];
|
|
43
|
+
if (align === 'start') {
|
|
30
44
|
left = triggerRect.left;
|
|
45
|
+
origin += ' left';
|
|
31
46
|
}
|
|
32
|
-
else if (
|
|
47
|
+
else if (align === 'end') {
|
|
33
48
|
left = triggerRect.right - contentRect.width;
|
|
49
|
+
origin += ' right';
|
|
34
50
|
}
|
|
35
|
-
else
|
|
51
|
+
else {
|
|
36
52
|
left = triggerRect.left + (triggerRect.width / 2) - (contentRect.width / 2);
|
|
53
|
+
origin += ' center';
|
|
54
|
+
}
|
|
55
|
+
// Edge Config
|
|
56
|
+
const padding = 16;
|
|
57
|
+
// Horizontal Clamping
|
|
58
|
+
if (left + contentRect.width > viewportWidth - padding) {
|
|
59
|
+
left = viewportWidth - contentRect.width - padding;
|
|
37
60
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
left = viewportWidth - contentRect.width - 16; // 16px padding from right edge
|
|
41
|
-
if (origin.includes('left'))
|
|
42
|
-
origin = origin.replace('left', 'right');
|
|
61
|
+
if (left < padding) {
|
|
62
|
+
left = padding;
|
|
43
63
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
// Vertical Clamping (Fail-safe)
|
|
65
|
+
if (top < padding) {
|
|
66
|
+
top = padding;
|
|
67
|
+
}
|
|
68
|
+
if (top + contentRect.height > viewportHeight - padding) {
|
|
69
|
+
top = viewportHeight - contentRect.height - padding;
|
|
48
70
|
}
|
|
49
71
|
setPosition({ top, left });
|
|
50
72
|
setTransformOrigin(origin);
|
|
51
73
|
}, [isOpen, placement, offset]);
|
|
52
|
-
|
|
74
|
+
// Use useLayoutEffect for layout measurements to prevent flash
|
|
75
|
+
useLayoutEffect(() => {
|
|
53
76
|
if (isOpen) {
|
|
54
77
|
updatePosition();
|
|
55
78
|
window.addEventListener('resize', updatePosition);
|
|
@@ -75,17 +98,12 @@ export function Popover({ trigger, content, isOpen, onClose, placement = 'bottom
|
|
|
75
98
|
document.addEventListener('mousedown', handleClickOutside);
|
|
76
99
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
77
100
|
}, [isOpen, onClose]);
|
|
78
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, style: { display: 'inline-block' }, children: trigger }), isOpen && typeof document !== 'undefined' && createPortal(
|
|
101
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, style: { display: 'inline-block' }, children: trigger }), isOpen && typeof document !== 'undefined' && createPortal(_jsx("div", { ref: contentRef, style: {
|
|
79
102
|
position: 'fixed',
|
|
80
103
|
top: position.top,
|
|
81
104
|
left: position.left,
|
|
82
105
|
zIndex: 9999, // High z-index to ensure it's on top
|
|
83
106
|
transformOrigin: transformOrigin,
|
|
84
|
-
animation:
|
|
85
|
-
}, children:
|
|
86
|
-
@keyframes popoverScale {
|
|
87
|
-
from { opacity: 0; transform: scale(0.95); }
|
|
88
|
-
to { opacity: 1; transform: scale(1); }
|
|
89
|
-
}
|
|
90
|
-
` })] }), document.body)] }));
|
|
107
|
+
animation: `${popoverScale} 0.1s ease-out`,
|
|
108
|
+
}, children: content }), document.body)] }));
|
|
91
109
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface RadioGroupProps {
|
|
3
|
+
name?: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
defaultValue?: string;
|
|
6
|
+
onValueChange?: (value: string) => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function RadioGroup({ name, value: controlledValue, defaultValue, onValueChange, disabled, children, className }: RadioGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
interface RadioGroupItemProps {
|
|
13
|
+
value: string;
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function RadioGroupItem({ value, children, disabled, className }: RadioGroupItemProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export {};
|