@roy-ui/ui 0.0.7 → 0.0.9
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/{Button-XBBWB5ZT.css → Button-OZLAH5NO.css} +60 -13
- package/dist/Table-qVdGZkB4.d.ts +42 -0
- package/dist/TimePicker-BhRta4MK.d.ts +39 -0
- package/dist/chunk-4SGMAZBG.js +161 -0
- package/dist/chunk-4SGMAZBG.js.map +1 -0
- package/dist/chunk-5CIBIH7R.js +98 -0
- package/dist/chunk-5CIBIH7R.js.map +1 -0
- package/dist/chunk-75IGGPXL.js +518 -0
- package/dist/chunk-75IGGPXL.js.map +1 -0
- package/dist/chunk-C5X3TE5U.js +87 -0
- package/dist/chunk-C5X3TE5U.js.map +1 -0
- package/dist/chunk-HUCK7AM7.js +840 -0
- package/dist/chunk-HUCK7AM7.js.map +1 -0
- package/dist/chunk-KSHKVSNK.js +82 -0
- package/dist/chunk-KSHKVSNK.js.map +1 -0
- package/dist/chunk-M6HB6BMA.js +101 -0
- package/dist/chunk-M6HB6BMA.js.map +1 -0
- package/dist/chunk-MDPMEW4K.js +58 -0
- package/dist/chunk-MDPMEW4K.js.map +1 -0
- package/dist/chunk-PGV55XSZ.js +107 -0
- package/dist/chunk-PGV55XSZ.js.map +1 -0
- package/dist/chunk-RLBVY3DG.js +64 -0
- package/dist/chunk-RLBVY3DG.js.map +1 -0
- package/dist/chunk-SFENGB5N.js +410 -0
- package/dist/chunk-SFENGB5N.js.map +1 -0
- package/dist/chunk-XERZVDIT.js +194 -0
- package/dist/chunk-XERZVDIT.js.map +1 -0
- package/dist/components/button/index.d.ts +37 -0
- package/dist/components/button/index.js +4 -0
- package/dist/components/button/index.js.map +1 -0
- package/dist/components/data-table/index.d.ts +145 -0
- package/dist/components/data-table/index.js +9 -0
- package/dist/components/data-table/index.js.map +1 -0
- package/dist/components/date-range-picker/index.d.ts +30 -0
- package/dist/components/date-range-picker/index.js +4 -0
- package/dist/components/date-range-picker/index.js.map +1 -0
- package/dist/components/gradient-button/index.d.ts +12 -0
- package/dist/components/gradient-button/index.js +4 -0
- package/dist/components/gradient-button/index.js.map +1 -0
- package/dist/components/made-by/index.d.ts +23 -0
- package/dist/components/made-by/index.js +4 -0
- package/dist/components/made-by/index.js.map +1 -0
- package/dist/components/pagination/index.d.ts +23 -0
- package/dist/components/pagination/index.js +4 -0
- package/dist/components/pagination/index.js.map +1 -0
- package/dist/components/popover/index.d.ts +18 -0
- package/dist/components/popover/index.js +4 -0
- package/dist/components/popover/index.js.map +1 -0
- package/dist/components/table/index.d.ts +28 -0
- package/dist/components/table/index.js +4 -0
- package/dist/components/table/index.js.map +1 -0
- package/dist/components/table-search/index.d.ts +19 -0
- package/dist/components/table-search/index.js +4 -0
- package/dist/components/table-search/index.js.map +1 -0
- package/dist/components/text-morph/index.d.ts +28 -0
- package/dist/components/text-morph/index.js +4 -0
- package/dist/components/text-morph/index.js.map +1 -0
- package/dist/components/time-picker/index.d.ts +14 -0
- package/dist/components/time-picker/index.js +4 -0
- package/dist/components/time-picker/index.js.map +1 -0
- package/dist/components/tree-nav/index.d.ts +30 -0
- package/dist/components/tree-nav/index.js +4 -0
- package/dist/components/tree-nav/index.js.map +1 -0
- package/dist/dateUtils-B_m_EICl.d.ts +14 -0
- package/dist/index.d.ts +17 -422
- package/dist/index.js +12 -2519
- package/dist/index.js.map +1 -1
- package/package.json +51 -2
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
.royui-btn {
|
|
2
|
-
/* Surface — light grazes the top, the base sits in its own shade.
|
|
2
|
+
/* Surface — light grazes the top, the base sits in its own shade.
|
|
3
|
+
Pass the `color` prop and these four derive from it automatically;
|
|
4
|
+
or set any of them yourself to retint by hand. */
|
|
3
5
|
--royui-btn-top: #323232;
|
|
4
6
|
--royui-btn-bottom: #222222;
|
|
5
7
|
/* A hairline ring keeps the edge crisp on any background. */
|
|
6
8
|
--royui-btn-ring: #3a3a3a;
|
|
7
9
|
--royui-btn-fg: #ffffff;
|
|
10
|
+
/* The two depth overlays. These are hue-agnostic on purpose — a white
|
|
11
|
+
sheen on the top lip, a dark wall at the base — so they read as form
|
|
12
|
+
over any color. The `color` prop tunes their strength by luminance. */
|
|
13
|
+
--royui-btn-highlight: rgba(255, 255, 255, 0.15);
|
|
14
|
+
--royui-btn-shade: rgba(8, 8, 8, 0.55);
|
|
15
|
+
--royui-btn-focus: rgba(255, 255, 255, 0.7);
|
|
16
|
+
/* Interaction is brightness, not recolor — so it works for any base color. */
|
|
17
|
+
--royui-btn-hover-bright: 1.12;
|
|
18
|
+
--royui-btn-active-bright: 0.86;
|
|
8
19
|
--royui-btn-radius: 14px;
|
|
9
20
|
--royui-btn-pad-y: 11px;
|
|
10
21
|
--royui-btn-pad-x: 22px;
|
|
@@ -31,6 +42,7 @@
|
|
|
31
42
|
transition:
|
|
32
43
|
transform 140ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
33
44
|
box-shadow 200ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
45
|
+
filter 200ms ease,
|
|
34
46
|
background 200ms ease;
|
|
35
47
|
/* The whole illusion lives here — four layers, none of them loud:
|
|
36
48
|
1 · ring — defines the edge without a visible border
|
|
@@ -39,8 +51,8 @@
|
|
|
39
51
|
4 · drop shadow — it rests on the surface, barely */
|
|
40
52
|
box-shadow:
|
|
41
53
|
0 0 0 1px var(--royui-btn-ring),
|
|
42
|
-
inset 0 0.5px 1px
|
|
43
|
-
inset 0 -1px 1.2px 0.4px
|
|
54
|
+
inset 0 0.5px 1px var(--royui-btn-highlight),
|
|
55
|
+
inset 0 -1px 1.2px 0.4px var(--royui-btn-shade),
|
|
44
56
|
0 2px 4px -1px rgba(0, 0, 0, 0.5);
|
|
45
57
|
}
|
|
46
58
|
|
|
@@ -63,24 +75,54 @@
|
|
|
63
75
|
width: 100%;
|
|
64
76
|
}
|
|
65
77
|
|
|
66
|
-
/*
|
|
78
|
+
/* Variants — all three reuse the same depth machinery, just dialed down.
|
|
79
|
+
"secondary" is a quieter raised chip; "ghost" stays flat until hovered. */
|
|
80
|
+
.royui-btn--secondary {
|
|
81
|
+
--royui-btn-top: rgba(255, 255, 255, 0.1);
|
|
82
|
+
--royui-btn-bottom: rgba(255, 255, 255, 0.045);
|
|
83
|
+
--royui-btn-ring: rgba(255, 255, 255, 0.14);
|
|
84
|
+
--royui-btn-fg: rgba(255, 255, 255, 0.92);
|
|
85
|
+
--royui-btn-highlight: rgba(255, 255, 255, 0.12);
|
|
86
|
+
--royui-btn-shade: rgba(0, 0, 0, 0.22);
|
|
87
|
+
--royui-btn-focus: rgba(255, 255, 255, 0.6);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.royui-btn--ghost {
|
|
91
|
+
--royui-btn-fg: rgba(255, 255, 255, 0.82);
|
|
92
|
+
--royui-btn-focus: rgba(255, 255, 255, 0.6);
|
|
93
|
+
background: transparent;
|
|
94
|
+
box-shadow: none;
|
|
95
|
+
}
|
|
96
|
+
.royui-btn--ghost:hover:not(:disabled):not([aria-disabled='true']) {
|
|
97
|
+
background: rgba(255, 255, 255, 0.07);
|
|
98
|
+
filter: none;
|
|
99
|
+
box-shadow: none;
|
|
100
|
+
transform: none;
|
|
101
|
+
}
|
|
102
|
+
.royui-btn--ghost:active:not(:disabled):not([aria-disabled='true']) {
|
|
103
|
+
background: rgba(255, 255, 255, 0.11);
|
|
104
|
+
filter: none;
|
|
105
|
+
box-shadow: none;
|
|
106
|
+
transform: translateY(0.5px);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Hover — a half-pixel of lift and a touch more light. Brightness rather
|
|
110
|
+
than a hardcoded color, so it lightens whatever base color you passed. */
|
|
67
111
|
.royui-btn:hover:not(:disabled) {
|
|
68
|
-
--royui-btn-top: #383838;
|
|
69
|
-
--royui-btn-bottom: #262626;
|
|
70
112
|
transform: translateY(-0.5px);
|
|
113
|
+
filter: brightness(var(--royui-btn-hover-bright));
|
|
71
114
|
box-shadow:
|
|
72
115
|
0 0 0 1px var(--royui-btn-ring),
|
|
73
|
-
inset 0 0.5px 1px
|
|
74
|
-
inset 0 -1px 1.2px 0.4px
|
|
116
|
+
inset 0 0.5px 1px var(--royui-btn-highlight),
|
|
117
|
+
inset 0 -1px 1.2px 0.4px var(--royui-btn-shade),
|
|
75
118
|
0 4px 8px -2px rgba(0, 0, 0, 0.55);
|
|
76
119
|
}
|
|
77
120
|
|
|
78
121
|
/* Press — the top highlight collapses into an inset shadow, so the face
|
|
79
122
|
dips in instead of staying lit. That swap is what reads as "real". */
|
|
80
123
|
.royui-btn:active:not(:disabled) {
|
|
81
|
-
--royui-btn-top: #2a2a2a;
|
|
82
|
-
--royui-btn-bottom: #1e1e1e;
|
|
83
124
|
transform: translateY(0.5px);
|
|
125
|
+
filter: brightness(var(--royui-btn-active-bright));
|
|
84
126
|
transition-duration: 60ms;
|
|
85
127
|
box-shadow:
|
|
86
128
|
0 0 0 1px var(--royui-btn-ring),
|
|
@@ -90,14 +132,19 @@
|
|
|
90
132
|
}
|
|
91
133
|
|
|
92
134
|
.royui-btn:focus-visible {
|
|
93
|
-
outline: 2px solid
|
|
135
|
+
outline: 2px solid var(--royui-btn-focus);
|
|
94
136
|
outline-offset: 2px;
|
|
95
137
|
}
|
|
96
138
|
|
|
97
|
-
.royui-btn:disabled
|
|
139
|
+
.royui-btn:disabled,
|
|
140
|
+
.royui-btn[aria-disabled='true'] {
|
|
98
141
|
opacity: 0.55;
|
|
99
142
|
cursor: not-allowed;
|
|
100
143
|
}
|
|
144
|
+
/* asChild renders a non-button (e.g. <a>) that ignores the disabled attr. */
|
|
145
|
+
.royui-btn[aria-disabled='true'] {
|
|
146
|
+
pointer-events: none;
|
|
147
|
+
}
|
|
101
148
|
|
|
102
149
|
.royui-btn--loading {
|
|
103
150
|
cursor: progress;
|
|
@@ -123,7 +170,7 @@
|
|
|
123
170
|
|
|
124
171
|
@media (prefers-reduced-motion: reduce) {
|
|
125
172
|
.royui-btn {
|
|
126
|
-
transition: box-shadow 200ms ease, background 200ms ease;
|
|
173
|
+
transition: box-shadow 200ms ease, filter 200ms ease, background 200ms ease;
|
|
127
174
|
}
|
|
128
175
|
.royui-btn:hover:not(:disabled),
|
|
129
176
|
.royui-btn:active:not(:disabled) {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode, TableHTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
type TableDensity = 'compact' | 'cozy' | 'comfortable';
|
|
5
|
+
type FontSpec = string | {
|
|
6
|
+
family?: string;
|
|
7
|
+
size?: string | number;
|
|
8
|
+
weight?: number | string;
|
|
9
|
+
letterSpacing?: string;
|
|
10
|
+
featureSettings?: string;
|
|
11
|
+
};
|
|
12
|
+
interface TableProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
13
|
+
/** Rows visible before vertical scroll. Default 7. */
|
|
14
|
+
visibleRows?: number;
|
|
15
|
+
/** Approximate row height in px — drives the scroll cap. Default 44. */
|
|
16
|
+
rowHeight?: number;
|
|
17
|
+
/** Header sticks during scroll. Default true. */
|
|
18
|
+
stickyHeader?: boolean;
|
|
19
|
+
/** Padding scale. Default 'cozy'. */
|
|
20
|
+
density?: TableDensity;
|
|
21
|
+
/** Renders an inline spinner overlay on top of rows. */
|
|
22
|
+
loading?: boolean;
|
|
23
|
+
/** Replaces row area when no rows are present. */
|
|
24
|
+
empty?: ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* Force every column to fit in the container — disables horizontal scroll
|
|
27
|
+
* and lets the browser distribute width across all visible columns.
|
|
28
|
+
* Cell content wraps onto multiple lines instead of clipping.
|
|
29
|
+
*/
|
|
30
|
+
fitColumns?: boolean;
|
|
31
|
+
/** Per-zone fonts. */
|
|
32
|
+
headerFont?: FontSpec;
|
|
33
|
+
rowHeaderFont?: FontSpec;
|
|
34
|
+
cellFont?: FontSpec;
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
tableProps?: TableHTMLAttributes<HTMLTableElement>;
|
|
37
|
+
/** Show the empty slot. Set explicitly by DataTable; defaults to false. */
|
|
38
|
+
isEmpty?: boolean;
|
|
39
|
+
}
|
|
40
|
+
declare const Table: react.ForwardRefExoticComponent<TableProps & react.RefAttributes<HTMLDivElement>>;
|
|
41
|
+
|
|
42
|
+
export { type FontSpec as F, Table as T, type TableDensity as a, type TableProps as b };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type TimeValue = {
|
|
5
|
+
hours: number;
|
|
6
|
+
minutes: number;
|
|
7
|
+
};
|
|
8
|
+
interface AnalogClockProps {
|
|
9
|
+
value: TimeValue;
|
|
10
|
+
onChange: (next: TimeValue) => void;
|
|
11
|
+
hourCycle?: 12 | 24;
|
|
12
|
+
minuteStep?: number;
|
|
13
|
+
/** SVG size in px. Default 220. */
|
|
14
|
+
size?: number;
|
|
15
|
+
}
|
|
16
|
+
declare function AnalogClock({ value, onChange, hourCycle, minuteStep, size, }: AnalogClockProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
|
|
18
|
+
type TimePickerVariant = 'analog' | 'digital';
|
|
19
|
+
interface TimePickerProps {
|
|
20
|
+
value?: TimeValue | null;
|
|
21
|
+
defaultValue?: TimeValue | null;
|
|
22
|
+
onChange?: (next: TimeValue) => void;
|
|
23
|
+
/** Picker style. Default 'analog'. */
|
|
24
|
+
variant?: TimePickerVariant;
|
|
25
|
+
/** Allow the user to switch between variants. Default true. */
|
|
26
|
+
switchable?: boolean;
|
|
27
|
+
hourCycle?: 12 | 24;
|
|
28
|
+
minuteStep?: number;
|
|
29
|
+
placeholder?: string;
|
|
30
|
+
align?: 'left' | 'right';
|
|
31
|
+
className?: string;
|
|
32
|
+
style?: CSSProperties;
|
|
33
|
+
triggerLabel?: ReactNode;
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
}
|
|
36
|
+
declare function formatTime(t: TimeValue | null | undefined, hourCycle?: 12 | 24): string;
|
|
37
|
+
declare function TimePicker({ value, defaultValue, onChange, variant, switchable, hourCycle, minuteStep, placeholder, align, className, style, triggerLabel, disabled, }: TimePickerProps): react_jsx_runtime.JSX.Element;
|
|
38
|
+
|
|
39
|
+
export { AnalogClock as A, TimePicker as T, type AnalogClockProps as a, type TimePickerProps as b, type TimePickerVariant as c, type TimeValue as d, formatTime as f };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { forwardRef, isValidElement, cloneElement } from 'react';
|
|
3
|
+
import './Button-OZLAH5NO.css';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/components/button/Button.tsx
|
|
7
|
+
function parseColor(input) {
|
|
8
|
+
const s = input.trim();
|
|
9
|
+
const hex = s.replace(/^#/, "");
|
|
10
|
+
if (/^[0-9a-f]{3,4}$/i.test(hex)) {
|
|
11
|
+
return {
|
|
12
|
+
r: parseInt(hex[0] + hex[0], 16),
|
|
13
|
+
g: parseInt(hex[1] + hex[1], 16),
|
|
14
|
+
b: parseInt(hex[2] + hex[2], 16)
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (/^[0-9a-f]{6}$/i.test(hex) || /^[0-9a-f]{8}$/i.test(hex)) {
|
|
18
|
+
return {
|
|
19
|
+
r: parseInt(hex.slice(0, 2), 16),
|
|
20
|
+
g: parseInt(hex.slice(2, 4), 16),
|
|
21
|
+
b: parseInt(hex.slice(4, 6), 16)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const m = s.match(/^rgba?\(([^)]+)\)$/i);
|
|
25
|
+
if (m) {
|
|
26
|
+
const p = m[1].split(/[,\s/]+/).filter(Boolean).map(Number);
|
|
27
|
+
if (p.length >= 3 && p.slice(0, 3).every((n) => !Number.isNaN(n))) {
|
|
28
|
+
return { r: p[0], g: p[1], b: p[2] };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
var clamp = (n) => Math.max(0, Math.min(255, Math.round(n)));
|
|
34
|
+
var mix = (c, target, amt) => ({
|
|
35
|
+
r: clamp(c.r + (target - c.r) * amt),
|
|
36
|
+
g: clamp(c.g + (target - c.g) * amt),
|
|
37
|
+
b: clamp(c.b + (target - c.b) * amt)
|
|
38
|
+
});
|
|
39
|
+
var rgb = (c) => `rgb(${c.r}, ${c.g}, ${c.b})`;
|
|
40
|
+
function tintVars(color) {
|
|
41
|
+
const base = parseColor(color);
|
|
42
|
+
if (!base) {
|
|
43
|
+
return {
|
|
44
|
+
["--royui-btn-top"]: color,
|
|
45
|
+
["--royui-btn-bottom"]: color
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const lum = (0.2126 * base.r + 0.7152 * base.g + 0.0722 * base.b) / 255;
|
|
49
|
+
const light = lum > 0.62;
|
|
50
|
+
const shade = mix(base, 0, 0.6);
|
|
51
|
+
return {
|
|
52
|
+
["--royui-btn-top"]: rgb(mix(base, 255, 0.1)),
|
|
53
|
+
["--royui-btn-bottom"]: rgb(mix(base, 0, 0.1)),
|
|
54
|
+
// Light buttons need a darker edge to show on light backgrounds; dark
|
|
55
|
+
// buttons need a lighter one. Either way the ring stays a hairline.
|
|
56
|
+
["--royui-btn-ring"]: rgb(light ? mix(base, 0, 0.16) : mix(base, 255, 0.22)),
|
|
57
|
+
["--royui-btn-fg"]: light ? "#0b0b0d" : "#ffffff",
|
|
58
|
+
// Stronger top sheen on light surfaces (where a faint white is invisible),
|
|
59
|
+
// an in-hue shade at the base so it never looks like grime.
|
|
60
|
+
["--royui-btn-highlight"]: light ? "rgba(255, 255, 255, 0.5)" : "rgba(255, 255, 255, 0.15)",
|
|
61
|
+
["--royui-btn-shade"]: `rgba(${shade.r}, ${shade.g}, ${shade.b}, 0.5)`,
|
|
62
|
+
["--royui-btn-focus"]: light ? "rgba(0, 0, 0, 0.55)" : "rgba(255, 255, 255, 0.7)",
|
|
63
|
+
// Press darkens less on light buttons so the dip doesn't look like a smudge.
|
|
64
|
+
["--royui-btn-active-bright"]: light ? "0.93" : "0.86"
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function mergeRefs(...refs) {
|
|
68
|
+
return (node) => {
|
|
69
|
+
for (const ref of refs) {
|
|
70
|
+
if (typeof ref === "function") ref(node);
|
|
71
|
+
else if (ref && typeof ref === "object") {
|
|
72
|
+
ref.current = node;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
var DefaultSpinner = () => /* @__PURE__ */ jsx("span", { className: "royui-btn__spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", children: [
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
"circle",
|
|
80
|
+
{
|
|
81
|
+
cx: "12",
|
|
82
|
+
cy: "12",
|
|
83
|
+
r: "9",
|
|
84
|
+
stroke: "currentColor",
|
|
85
|
+
strokeOpacity: "0.3",
|
|
86
|
+
strokeWidth: "2.5"
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
/* @__PURE__ */ jsx(
|
|
90
|
+
"path",
|
|
91
|
+
{
|
|
92
|
+
d: "M21 12a9 9 0 0 0-9-9",
|
|
93
|
+
stroke: "currentColor",
|
|
94
|
+
strokeWidth: "2.5",
|
|
95
|
+
strokeLinecap: "round"
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
] }) });
|
|
99
|
+
var Button = forwardRef(
|
|
100
|
+
({
|
|
101
|
+
size = "md",
|
|
102
|
+
variant = "primary",
|
|
103
|
+
asChild = false,
|
|
104
|
+
color,
|
|
105
|
+
fullWidth = false,
|
|
106
|
+
loading = false,
|
|
107
|
+
loadingLabel,
|
|
108
|
+
disabled,
|
|
109
|
+
className = "",
|
|
110
|
+
style,
|
|
111
|
+
children,
|
|
112
|
+
type = "button",
|
|
113
|
+
...rest
|
|
114
|
+
}, ref) => {
|
|
115
|
+
const classes = [
|
|
116
|
+
"royui-btn",
|
|
117
|
+
`royui-btn--${size}`,
|
|
118
|
+
`royui-btn--${variant}`,
|
|
119
|
+
fullWidth ? "royui-btn--full" : "",
|
|
120
|
+
loading ? "royui-btn--loading" : "",
|
|
121
|
+
className
|
|
122
|
+
].filter(Boolean).join(" ");
|
|
123
|
+
const mergedStyle = color ? { ...tintVars(color), ...style } : style;
|
|
124
|
+
const spinner = loadingLabel ?? /* @__PURE__ */ jsx(DefaultSpinner, {});
|
|
125
|
+
const isDisabled = disabled || loading;
|
|
126
|
+
if (asChild && isValidElement(children)) {
|
|
127
|
+
const child = children;
|
|
128
|
+
const childRef = child.ref;
|
|
129
|
+
return cloneElement(
|
|
130
|
+
child,
|
|
131
|
+
{
|
|
132
|
+
...rest,
|
|
133
|
+
className: [classes, child.props.className].filter(Boolean).join(" "),
|
|
134
|
+
style: { ...mergedStyle, ...child.props.style },
|
|
135
|
+
"aria-busy": loading || void 0,
|
|
136
|
+
"aria-disabled": isDisabled || void 0,
|
|
137
|
+
ref: mergeRefs(ref, childRef)
|
|
138
|
+
},
|
|
139
|
+
loading ? spinner : child.props.children
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
return /* @__PURE__ */ jsx(
|
|
143
|
+
"button",
|
|
144
|
+
{
|
|
145
|
+
ref,
|
|
146
|
+
type,
|
|
147
|
+
disabled: isDisabled,
|
|
148
|
+
className: classes,
|
|
149
|
+
style: mergedStyle,
|
|
150
|
+
"aria-busy": loading || void 0,
|
|
151
|
+
...rest,
|
|
152
|
+
children: loading ? spinner : children
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
Button.displayName = "Button";
|
|
158
|
+
|
|
159
|
+
export { Button };
|
|
160
|
+
//# sourceMappingURL=chunk-4SGMAZBG.js.map
|
|
161
|
+
//# sourceMappingURL=chunk-4SGMAZBG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/button/Button.tsx"],"names":[],"mappings":"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","file":"chunk-4SGMAZBG.js","sourcesContent":["'use client';\n\nimport {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from 'react';\nimport './Button.css';\n\nexport type ButtonSize = 'sm' | 'md' | 'lg';\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual scale. Defaults to \"md\". */\n size?: ButtonSize;\n /** Visual weight. \"primary\" is the solid depth button; \"secondary\" is a\n * quieter raised surface; \"ghost\" is text-only until hovered. Defaults to \"primary\". */\n variant?: ButtonVariant;\n /**\n * Render the single child element instead of a <button>, merging the\n * button's classes, styles, and props onto it. Use this for a\n * button-styled link with real anchor semantics:\n * `<Button asChild><Link href=\"/x\">Go</Link></Button>`.\n */\n asChild?: boolean;\n /**\n * Base color (hex or rgb()). The whole depth treatment derives from it —\n * a lighter top and darker base for the gradient, a hairline ring that\n * adapts to the tone, and a readable label color picked by luminance.\n * Defaults to the near-black surface. Override individual CSS variables\n * (--royui-btn-top etc.) for finer control.\n */\n color?: string;\n /** Stretch the button to fill its container. Defaults to false. */\n fullWidth?: boolean;\n /** Replaces children with a spinner and disables the button. */\n loading?: boolean;\n /** Optional override for the loading visual. Defaults to a spinner. */\n loadingLabel?: ReactNode;\n children: ReactNode;\n}\n\ntype RGB = { r: number; g: number; b: number };\n\n/** Parse hex (#rgb/#rrggbb/#rrggbbaa) or rgb()/rgba(). Returns null otherwise. */\nfunction parseColor(input: string): RGB | null {\n const s = input.trim();\n const hex = s.replace(/^#/, '');\n if (/^[0-9a-f]{3,4}$/i.test(hex)) {\n return {\n r: parseInt(hex[0]! + hex[0]!, 16),\n g: parseInt(hex[1]! + hex[1]!, 16),\n b: parseInt(hex[2]! + hex[2]!, 16),\n };\n }\n if (/^[0-9a-f]{6}$/i.test(hex) || /^[0-9a-f]{8}$/i.test(hex)) {\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n }\n const m = s.match(/^rgba?\\(([^)]+)\\)$/i);\n if (m) {\n const p = m[1]!.split(/[,\\s/]+/).filter(Boolean).map(Number);\n if (p.length >= 3 && p.slice(0, 3).every((n) => !Number.isNaN(n))) {\n return { r: p[0]!, g: p[1]!, b: p[2]! };\n }\n }\n return null;\n}\n\nconst clamp = (n: number) => Math.max(0, Math.min(255, Math.round(n)));\n/** Mix a channel toward a target (255 = white, 0 = black) by amount 0..1. */\nconst mix = (c: RGB, target: number, amt: number): RGB => ({\n r: clamp(c.r + (target - c.r) * amt),\n g: clamp(c.g + (target - c.g) * amt),\n b: clamp(c.b + (target - c.b) * amt),\n});\nconst rgb = (c: RGB) => `rgb(${c.r}, ${c.g}, ${c.b})`;\n\n/** Derive the full set of depth variables from one base color. */\nfunction tintVars(color: string): CSSProperties {\n const base = parseColor(color);\n // Unparseable (named color, hsl, etc.) — let the raw value drive the\n // surface and keep the default overlays. Depth still reads via the shade.\n if (!base) {\n return {\n ['--royui-btn-top']: color,\n ['--royui-btn-bottom']: color,\n } as CSSProperties;\n }\n const lum = (0.2126 * base.r + 0.7152 * base.g + 0.0722 * base.b) / 255;\n const light = lum > 0.62;\n const shade = mix(base, 0, 0.6);\n return {\n ['--royui-btn-top']: rgb(mix(base, 255, 0.1)),\n ['--royui-btn-bottom']: rgb(mix(base, 0, 0.1)),\n // Light buttons need a darker edge to show on light backgrounds; dark\n // buttons need a lighter one. Either way the ring stays a hairline.\n ['--royui-btn-ring']: rgb(light ? mix(base, 0, 0.16) : mix(base, 255, 0.22)),\n ['--royui-btn-fg']: light ? '#0b0b0d' : '#ffffff',\n // Stronger top sheen on light surfaces (where a faint white is invisible),\n // an in-hue shade at the base so it never looks like grime.\n ['--royui-btn-highlight']: light\n ? 'rgba(255, 255, 255, 0.5)'\n : 'rgba(255, 255, 255, 0.15)',\n ['--royui-btn-shade']: `rgba(${shade.r}, ${shade.g}, ${shade.b}, 0.5)`,\n ['--royui-btn-focus']: light ? 'rgba(0, 0, 0, 0.55)' : 'rgba(255, 255, 255, 0.7)',\n // Press darkens less on light buttons so the dip doesn't look like a smudge.\n ['--royui-btn-active-bright']: light ? '0.93' : '0.86',\n } as CSSProperties;\n}\n\n/** Combine the forwarded ref with the child's own ref (asChild path). */\nfunction mergeRefs<T>(...refs: (Ref<T> | undefined)[]) {\n return (node: T) => {\n for (const ref of refs) {\n if (typeof ref === 'function') ref(node);\n else if (ref && typeof ref === 'object') {\n (ref as { current: T | null }).current = node;\n }\n }\n };\n}\n\nconst DefaultSpinner = () => (\n <span className=\"royui-btn__spinner\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"9\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.3\"\n strokeWidth=\"2.5\"\n />\n <path\n d=\"M21 12a9 9 0 0 0-9-9\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n);\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n size = 'md',\n variant = 'primary',\n asChild = false,\n color,\n fullWidth = false,\n loading = false,\n loadingLabel,\n disabled,\n className = '',\n style,\n children,\n type = 'button',\n ...rest\n },\n ref,\n ) => {\n const classes = [\n 'royui-btn',\n `royui-btn--${size}`,\n `royui-btn--${variant}`,\n fullWidth ? 'royui-btn--full' : '',\n loading ? 'royui-btn--loading' : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n // Derived vars first so an explicit `style` (or CSS-var override) still wins.\n const mergedStyle = color ? { ...tintVars(color), ...style } : style;\n const spinner = loadingLabel ?? <DefaultSpinner />;\n const isDisabled = disabled || loading;\n\n // Polymorphic path: paint the styles onto the child element (e.g. a link)\n // instead of a <button>, so native anchor semantics survive.\n if (asChild && isValidElement(children)) {\n const child = children as ReactElement<{\n className?: string;\n style?: CSSProperties;\n children?: ReactNode;\n }>;\n const childRef = (child as unknown as { ref?: Ref<unknown> }).ref;\n return cloneElement(\n child,\n {\n ...rest,\n className: [classes, child.props.className].filter(Boolean).join(' '),\n style: { ...mergedStyle, ...child.props.style },\n 'aria-busy': loading || undefined,\n 'aria-disabled': isDisabled || undefined,\n ref: mergeRefs(ref as Ref<unknown>, childRef),\n } as Record<string, unknown>,\n loading ? spinner : child.props.children,\n );\n }\n\n return (\n <button\n ref={ref}\n type={type}\n disabled={isDisabled}\n className={classes}\n style={mergedStyle}\n aria-busy={loading || undefined}\n {...rest}\n >\n {loading ? spinner : children}\n </button>\n );\n },\n);\n\nButton.displayName = 'Button';\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import './Pagination-LLKV7XXI.css';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/components/pagination/Pagination.tsx
|
|
7
|
+
function buildRange(page, pageCount, sibling) {
|
|
8
|
+
if (pageCount <= 1) return [1];
|
|
9
|
+
const first = 1;
|
|
10
|
+
const last = pageCount;
|
|
11
|
+
const left = Math.max(page - sibling, first + 1);
|
|
12
|
+
const right = Math.min(page + sibling, last - 1);
|
|
13
|
+
const cells = [first];
|
|
14
|
+
if (left > first + 1) cells.push("gap");
|
|
15
|
+
for (let i = left; i <= right; i++) cells.push(i);
|
|
16
|
+
if (right < last - 1) cells.push("gap");
|
|
17
|
+
if (last > first) cells.push(last);
|
|
18
|
+
return cells;
|
|
19
|
+
}
|
|
20
|
+
function Pagination({
|
|
21
|
+
page,
|
|
22
|
+
pageCount,
|
|
23
|
+
onPageChange,
|
|
24
|
+
siblingCount = 1,
|
|
25
|
+
showPrevNext = true,
|
|
26
|
+
prevLabel = "Prev",
|
|
27
|
+
nextLabel = "Next",
|
|
28
|
+
showSummary = false,
|
|
29
|
+
summaryRender,
|
|
30
|
+
className = "",
|
|
31
|
+
style
|
|
32
|
+
}) {
|
|
33
|
+
const cells = useMemo(
|
|
34
|
+
() => buildRange(page, pageCount, siblingCount),
|
|
35
|
+
[page, pageCount, siblingCount]
|
|
36
|
+
);
|
|
37
|
+
const canPrev = page > 1;
|
|
38
|
+
const canNext = page < pageCount;
|
|
39
|
+
const go = (n) => {
|
|
40
|
+
if (n < 1 || n > pageCount || n === page) return;
|
|
41
|
+
onPageChange(n);
|
|
42
|
+
};
|
|
43
|
+
return /* @__PURE__ */ jsxs(
|
|
44
|
+
"nav",
|
|
45
|
+
{
|
|
46
|
+
className: ["royui-pagination", className].filter(Boolean).join(" "),
|
|
47
|
+
style,
|
|
48
|
+
"aria-label": "Pagination",
|
|
49
|
+
children: [
|
|
50
|
+
showSummary && /* @__PURE__ */ jsx("span", { className: "royui-pagination__summary", children: summaryRender ? summaryRender(page, pageCount) : `Page ${page} of ${pageCount}` }),
|
|
51
|
+
/* @__PURE__ */ jsxs("div", { className: "royui-pagination__group", children: [
|
|
52
|
+
showPrevNext && /* @__PURE__ */ jsx(
|
|
53
|
+
"button",
|
|
54
|
+
{
|
|
55
|
+
type: "button",
|
|
56
|
+
className: "royui-pagination__step",
|
|
57
|
+
onClick: () => go(page - 1),
|
|
58
|
+
disabled: !canPrev,
|
|
59
|
+
"aria-label": "Previous page",
|
|
60
|
+
children: prevLabel
|
|
61
|
+
}
|
|
62
|
+
),
|
|
63
|
+
/* @__PURE__ */ jsx("ul", { className: "royui-pagination__pages", children: cells.map(
|
|
64
|
+
(cell, i) => cell === "gap" ? /* @__PURE__ */ jsx("li", { className: "royui-pagination__gap", "aria-hidden": true, children: "\xB7" }, `gap-${i}`) : /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
65
|
+
"button",
|
|
66
|
+
{
|
|
67
|
+
type: "button",
|
|
68
|
+
className: [
|
|
69
|
+
"royui-pagination__page",
|
|
70
|
+
cell === page && "royui-pagination__page--current"
|
|
71
|
+
].filter(Boolean).join(" "),
|
|
72
|
+
onClick: () => go(cell),
|
|
73
|
+
"aria-current": cell === page ? "page" : void 0,
|
|
74
|
+
"aria-label": `Page ${cell}`,
|
|
75
|
+
children: cell
|
|
76
|
+
}
|
|
77
|
+
) }, cell)
|
|
78
|
+
) }),
|
|
79
|
+
showPrevNext && /* @__PURE__ */ jsx(
|
|
80
|
+
"button",
|
|
81
|
+
{
|
|
82
|
+
type: "button",
|
|
83
|
+
className: "royui-pagination__step",
|
|
84
|
+
onClick: () => go(page + 1),
|
|
85
|
+
disabled: !canNext,
|
|
86
|
+
"aria-label": "Next page",
|
|
87
|
+
children: nextLabel
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
] })
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { Pagination };
|
|
97
|
+
//# sourceMappingURL=chunk-5CIBIH7R.js.map
|
|
98
|
+
//# sourceMappingURL=chunk-5CIBIH7R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/pagination/Pagination.tsx"],"names":[],"mappings":"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","file":"chunk-5CIBIH7R.js","sourcesContent":["'use client';\n\nimport { useMemo, type CSSProperties } from 'react';\nimport './Pagination.css';\n\nexport interface PaginationProps {\n page: number;\n pageCount: number;\n onPageChange: (page: number) => void;\n /** Pages shown adjacent to the current page. Default 1. */\n siblingCount?: number;\n /** Show Prev / Next text buttons. Default true. */\n showPrevNext?: boolean;\n /** Override the Prev / Next labels. */\n prevLabel?: string;\n nextLabel?: string;\n /** Compact summary like \"Page 3 of 12\" on the left. Default false. */\n showSummary?: boolean;\n summaryRender?: (page: number, pageCount: number) => string;\n className?: string;\n style?: CSSProperties;\n}\n\ntype Cell = number | 'gap';\n\nfunction buildRange(page: number, pageCount: number, sibling: number): Cell[] {\n if (pageCount <= 1) return [1];\n const first = 1;\n const last = pageCount;\n const left = Math.max(page - sibling, first + 1);\n const right = Math.min(page + sibling, last - 1);\n\n const cells: Cell[] = [first];\n if (left > first + 1) cells.push('gap');\n for (let i = left; i <= right; i++) cells.push(i);\n if (right < last - 1) cells.push('gap');\n if (last > first) cells.push(last);\n return cells;\n}\n\nexport function Pagination({\n page,\n pageCount,\n onPageChange,\n siblingCount = 1,\n showPrevNext = true,\n prevLabel = 'Prev',\n nextLabel = 'Next',\n showSummary = false,\n summaryRender,\n className = '',\n style,\n}: PaginationProps) {\n const cells = useMemo(\n () => buildRange(page, pageCount, siblingCount),\n [page, pageCount, siblingCount],\n );\n\n const canPrev = page > 1;\n const canNext = page < pageCount;\n\n const go = (n: number) => {\n if (n < 1 || n > pageCount || n === page) return;\n onPageChange(n);\n };\n\n return (\n <nav\n className={['royui-pagination', className].filter(Boolean).join(' ')}\n style={style}\n aria-label=\"Pagination\"\n >\n {showSummary && (\n <span className=\"royui-pagination__summary\">\n {summaryRender\n ? summaryRender(page, pageCount)\n : `Page ${page} of ${pageCount}`}\n </span>\n )}\n\n <div className=\"royui-pagination__group\">\n {showPrevNext && (\n <button\n type=\"button\"\n className=\"royui-pagination__step\"\n onClick={() => go(page - 1)}\n disabled={!canPrev}\n aria-label=\"Previous page\"\n >\n {prevLabel}\n </button>\n )}\n\n <ul className=\"royui-pagination__pages\">\n {cells.map((cell, i) =>\n cell === 'gap' ? (\n <li key={`gap-${i}`} className=\"royui-pagination__gap\" aria-hidden>\n ·\n </li>\n ) : (\n <li key={cell}>\n <button\n type=\"button\"\n className={[\n 'royui-pagination__page',\n cell === page && 'royui-pagination__page--current',\n ]\n .filter(Boolean)\n .join(' ')}\n onClick={() => go(cell)}\n aria-current={cell === page ? 'page' : undefined}\n aria-label={`Page ${cell}`}\n >\n {cell}\n </button>\n </li>\n ),\n )}\n </ul>\n\n {showPrevNext && (\n <button\n type=\"button\"\n className=\"royui-pagination__step\"\n onClick={() => go(page + 1)}\n disabled={!canNext}\n aria-label=\"Next page\"\n >\n {nextLabel}\n </button>\n )}\n </div>\n </nav>\n );\n}\n"]}
|