panelui-web 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,7 +25,10 @@ const kpiVariants = tv({
25
25
  },
26
26
  variants: {
27
27
  surface: {
28
- true: { root: 'rounded-3xl border bg-card p-5 text-card-foreground' },
28
+ true: {
29
+ root: 'rounded-3xl border bg-card p-5 text-card-foreground',
30
+ group: 'rounded-3xl border bg-card p-5 text-card-foreground',
31
+ },
29
32
  },
30
33
  color: {
31
34
  primary: { chart: '[--pu-color:var(--primary)]', progress: '[--pu-color:var(--primary)]' },
@@ -221,8 +224,8 @@ function KpiSeparator({ className, ...props }) {
221
224
  }
222
225
  KpiSeparator.displayName = 'Kpi.Separator';
223
226
  /** Several metrics as one panel, with a rule between each and the next. */
224
- function KpiGroup({ orientation = 'horizontal', className, ...props }) {
225
- return _jsx("div", { className: kpiVariants({ orientation }).group({ className }), ...props });
227
+ function KpiGroup({ orientation = 'horizontal', surface = false, className, ...props }) {
228
+ return _jsx("div", { className: kpiVariants({ orientation, surface }).group({ className }), ...props });
226
229
  }
227
230
  KpiGroup.displayName = 'Kpi.Group';
228
231
  export const Kpi = Object.assign(KpiRoot, {
@@ -114,6 +114,13 @@ declare function LaneBoardMeta({ className, ...props }: LaneBoardMetaProps): imp
114
114
  declare namespace LaneBoardMeta {
115
115
  var displayName: string;
116
116
  }
117
+ export interface LaneBoardAvatarProps extends ComponentProps<'span'> {
118
+ }
119
+ /** Who a card belongs to, as initials in a small circle. */
120
+ declare function LaneBoardAvatar({ className, ...props }: LaneBoardAvatarProps): import("react").JSX.Element;
121
+ declare namespace LaneBoardAvatar {
122
+ var displayName: string;
123
+ }
117
124
  export declare const LaneBoard: typeof LaneBoardRoot & {
118
125
  Title: typeof LaneBoardTitle;
119
126
  Code: typeof LaneBoardCode;
@@ -121,5 +128,6 @@ export declare const LaneBoard: typeof LaneBoardRoot & {
121
128
  Steps: typeof LaneBoardSteps;
122
129
  Tag: typeof LaneBoardTag;
123
130
  Meta: typeof LaneBoardMeta;
131
+ Avatar: typeof LaneBoardAvatar;
124
132
  };
125
- export { LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta };
133
+ export { LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta, LaneBoardAvatar, };
@@ -89,6 +89,7 @@ const laneBoardVariants = tv({
89
89
  step: 'h-1 w-4 rounded-full',
90
90
  tag: 'inline-flex items-center rounded-full border border-[color-mix(in_oklab,var(--pu-color)_35%,var(--card))] bg-[color-mix(in_oklab,var(--pu-color)_14%,transparent)] px-2 py-0.5 text-xs font-medium text-[var(--pu-color)]',
91
91
  meta: 'font-mono text-sm tabular-nums text-foreground',
92
+ avatar: 'flex size-6 shrink-0 items-center justify-center rounded-full bg-muted text-[0.625rem] font-semibold text-muted-foreground',
92
93
  },
93
94
  variants: {
94
95
  color: {
@@ -678,6 +679,11 @@ function LaneBoardMeta({ className, ...props }) {
678
679
  return _jsx("span", { className: laneBoardVariants().meta({ className }), ...props });
679
680
  }
680
681
  LaneBoardMeta.displayName = 'LaneBoard.Meta';
682
+ /** Who a card belongs to, as initials in a small circle. */
683
+ function LaneBoardAvatar({ className, ...props }) {
684
+ return _jsx("span", { "data-slot": "lane-board-avatar", className: laneBoardVariants().avatar({ className }), ...props });
685
+ }
686
+ LaneBoardAvatar.displayName = 'LaneBoard.Avatar';
681
687
  export const LaneBoard = Object.assign(LaneBoardRoot, {
682
688
  Title: LaneBoardTitle,
683
689
  Code: LaneBoardCode,
@@ -685,7 +691,8 @@ export const LaneBoard = Object.assign(LaneBoardRoot, {
685
691
  Steps: LaneBoardSteps,
686
692
  Tag: LaneBoardTag,
687
693
  Meta: LaneBoardMeta,
694
+ Avatar: LaneBoardAvatar,
688
695
  });
689
696
  /* By name as well, for a Server Component, which cannot dot into a client
690
697
  module. */
691
- export { LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta };
698
+ export { LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta, LaneBoardAvatar, };
@@ -124,9 +124,32 @@ declare function PlanetControls({ step, className, children, ...props }: PlanetC
124
124
  declare namespace PlanetControls {
125
125
  var displayName: string;
126
126
  }
127
+ export interface PlanetListProps extends ComponentProps<'ul'> {
128
+ }
129
+ /**
130
+ * The places on the globe as a list, in two columns, for picking one by name.
131
+ * Put it beside or under the globe and turn the globe to whatever is picked.
132
+ */
133
+ declare function PlanetList({ className, ...props }: PlanetListProps): import("react").JSX.Element;
134
+ declare namespace PlanetList {
135
+ var displayName: string;
136
+ }
137
+ export interface PlanetListItemProps extends Omit<ComponentProps<'button'>, 'color'> {
138
+ /** The colour of the dot before the name. Match it to the place's marker. */
139
+ color?: PlanetMarkerColor;
140
+ /** Draws the row as the one that has been picked. */
141
+ selected?: boolean;
142
+ }
143
+ /** One place in `Planet.List`: a dot in its marker's colour, and its name. A button. */
144
+ declare function PlanetListItem({ color, selected, className, children, ...props }: PlanetListItemProps): import("react").JSX.Element;
145
+ declare namespace PlanetListItem {
146
+ var displayName: string;
147
+ }
127
148
  export declare const Planet: import("react").ForwardRefExoticComponent<Omit<PlanetProps, "ref"> & import("react").RefAttributes<PlanetHandle>> & {
128
149
  Globe: typeof PlanetGlobe;
129
150
  Marker: typeof PlanetMarker;
130
151
  Controls: typeof PlanetControls;
152
+ List: typeof PlanetList;
153
+ ListItem: typeof PlanetListItem;
131
154
  };
132
- export { PlanetGlobe, PlanetMarker, PlanetControls };
155
+ export { PlanetGlobe, PlanetMarker, PlanetControls, PlanetList, PlanetListItem };
@@ -80,6 +80,11 @@ const planetVariants = tv({
80
80
  controls: 'inline-flex items-stretch divide-x divide-border overflow-hidden rounded-xl border bg-card text-card-foreground shadow-sm',
81
81
  control: 'inline-flex size-9 cursor-pointer items-center justify-center text-muted-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground active:bg-muted',
82
82
  caption: 'flex items-center px-3 text-sm font-medium',
83
+ // The places on the globe again, as a list beside it, ruled off from what is above.
84
+ list: 'grid grid-cols-2 gap-1 border-t pt-3',
85
+ listItem: 'flex w-full cursor-pointer items-center gap-2 rounded-lg px-2 py-1.5 text-start text-sm text-muted-foreground outline-none transition-colors hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring aria-pressed:bg-muted aria-pressed:text-foreground',
86
+ listDot: 'size-2 shrink-0 rounded-full bg-[var(--pu-color)]',
87
+ listName: 'truncate',
83
88
  },
84
89
  variants: {
85
90
  /** The colour of the light at the globe's edge. */
@@ -99,11 +104,11 @@ const planetVariants = tv({
99
104
  },
100
105
  },
101
106
  color: {
102
- primary: { marker: '[--pu-color:var(--primary)]' },
103
- info: { marker: '[--pu-color:var(--info)]' },
104
- success: { marker: '[--pu-color:var(--success)]' },
105
- warning: { marker: '[--pu-color:var(--warning)]' },
106
- destructive: { marker: '[--pu-color:var(--destructive)]' },
107
+ primary: { marker: '[--pu-color:var(--primary)]', listDot: '[--pu-color:var(--primary)]' },
108
+ info: { marker: '[--pu-color:var(--info)]', listDot: '[--pu-color:var(--info)]' },
109
+ success: { marker: '[--pu-color:var(--success)]', listDot: '[--pu-color:var(--success)]' },
110
+ warning: { marker: '[--pu-color:var(--warning)]', listDot: '[--pu-color:var(--warning)]' },
111
+ destructive: { marker: '[--pu-color:var(--destructive)]', listDot: '[--pu-color:var(--destructive)]' },
107
112
  },
108
113
  },
109
114
  defaultVariants: { color: 'primary', glow: 'primary' },
@@ -638,10 +643,26 @@ function PlanetControls({ step = 60, className, children, ...props }) {
638
643
  return (_jsxs("div", { role: "group", "aria-label": "Turn the globe", className: slots.controls({ className }), ...props, children: [_jsx("button", { type: "button", "aria-label": "Turn west", className: slots.control(), onClick: () => planet.rotateBy(-step), children: _jsx(Arrow, { flipped: true }) }), children !== undefined && children !== null ? (_jsx("span", { className: slots.caption(), children: children })) : null, _jsx("button", { type: "button", "aria-label": "Turn east", className: slots.control(), onClick: () => planet.rotateBy(step), children: _jsx(Arrow, {}) })] }));
639
644
  }
640
645
  PlanetControls.displayName = 'Planet.Controls';
646
+ /**
647
+ * The places on the globe as a list, in two columns, for picking one by name.
648
+ * Put it beside or under the globe and turn the globe to whatever is picked.
649
+ */
650
+ function PlanetList({ className, ...props }) {
651
+ return _jsx("ul", { "data-slot": "planet-list", className: planetVariants().list({ className }), ...props });
652
+ }
653
+ PlanetList.displayName = 'Planet.List';
654
+ /** One place in `Planet.List`: a dot in its marker's colour, and its name. A button. */
655
+ function PlanetListItem({ color = 'primary', selected = false, className, children, ...props }) {
656
+ const slots = planetVariants({ color });
657
+ return (_jsx("li", { "data-slot": "planet-list-item", children: _jsxs("button", { type: "button", "aria-pressed": selected, className: slots.listItem({ className }), ...props, children: [_jsx("span", { "aria-hidden": "true", className: slots.listDot() }), _jsx("span", { className: slots.listName(), children: children })] }) }));
658
+ }
659
+ PlanetListItem.displayName = 'Planet.ListItem';
641
660
  export const Planet = Object.assign(PlanetRoot, {
642
661
  Globe: PlanetGlobe,
643
662
  Marker: PlanetMarker,
644
663
  Controls: PlanetControls,
664
+ List: PlanetList,
665
+ ListItem: PlanetListItem,
645
666
  });
646
667
  /*
647
668
  * The parts again, by name. `Planet.Globe` is a property of a component, and a
@@ -650,4 +671,4 @@ export const Planet = Object.assign(PlanetRoot, {
650
671
  * Server Component writes `<PlanetGlobe>`; anywhere else the dotted form is
651
672
  * the same thing.
652
673
  */
653
- export { PlanetGlobe, PlanetMarker, PlanetControls };
674
+ export { PlanetGlobe, PlanetMarker, PlanetControls, PlanetList, PlanetListItem };
@@ -3,7 +3,9 @@
3
3
  * ruler of ticks that rises under the value.
4
4
  *
5
5
  * ```tsx
6
+ * <RangeMeter.Label>Response time</RangeMeter.Label>
6
7
  * <RangeMeter min={80} max={600} value={time} onValueChange={setTime} marker={300} />
8
+ * <RangeMeter.Scale start="80 ms" end="600 ms" />
7
9
  * ```
8
10
  *
9
11
  * ## The ruler swells where the reading is
@@ -64,7 +66,33 @@ export interface RangeMeterProps extends Omit<ComponentProps<'div'>, 'onChange'
64
66
  /** Drawn in the tag before the number: an icon. */
65
67
  children?: ReactNode;
66
68
  }
67
- export declare function RangeMeter({ min, max, value, onValueChange, step, marker, ticks, color, formatValue, label, valueText, className, children, ...props }: RangeMeterProps): import("react").JSX.Element;
68
- export declare namespace RangeMeter {
69
+ declare function RangeMeterRoot({ min, max, value, onValueChange, step, marker, ticks, color, formatValue, label, valueText, className, children, ...props }: RangeMeterProps): import("react").JSX.Element;
70
+ declare namespace RangeMeterRoot {
69
71
  var displayName: string;
70
72
  }
73
+ export interface RangeMeterLabelProps extends ComponentProps<'p'> {
74
+ }
75
+ /**
76
+ * The meter's name, written over it. The meter's own `label` is what a screen
77
+ * reader says; this is what everyone else reads.
78
+ */
79
+ declare function RangeMeterLabel({ className, ...props }: RangeMeterLabelProps): import("react").JSX.Element;
80
+ declare namespace RangeMeterLabel {
81
+ var displayName: string;
82
+ }
83
+ export interface RangeMeterScaleProps extends Omit<ComponentProps<'div'>, 'children'> {
84
+ /** The word or figure at the low end. */
85
+ start: ReactNode;
86
+ /** The word or figure at the high end. */
87
+ end: ReactNode;
88
+ }
89
+ /** What the two ends of the ruler stand for, written under it at either side. */
90
+ declare function RangeMeterScale({ start, end, className, ...props }: RangeMeterScaleProps): import("react").JSX.Element;
91
+ declare namespace RangeMeterScale {
92
+ var displayName: string;
93
+ }
94
+ export declare const RangeMeter: typeof RangeMeterRoot & {
95
+ Label: typeof RangeMeterLabel;
96
+ Scale: typeof RangeMeterScale;
97
+ };
98
+ export { RangeMeterLabel, RangeMeterScale };
@@ -5,7 +5,9 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
5
5
  * ruler of ticks that rises under the value.
6
6
  *
7
7
  * ```tsx
8
+ * <RangeMeter.Label>Response time</RangeMeter.Label>
8
9
  * <RangeMeter min={80} max={600} value={time} onValueChange={setTime} marker={300} />
10
+ * <RangeMeter.Scale start="80 ms" end="600 ms" />
9
11
  * ```
10
12
  *
11
13
  * ## The ruler swells where the reading is
@@ -44,6 +46,9 @@ const rangeMeterVariants = tv({
44
46
  ruler: 'relative flex h-10 items-end justify-between',
45
47
  tick: 'w-[3px] rounded-full transition-[height,background-color,opacity,box-shadow] duration-200 ease-out motion-reduce:transition-none',
46
48
  marker: 'pointer-events-none absolute -bottom-2.5 size-1.5 -translate-x-1/2 rotate-45 rounded-[1px] bg-foreground rtl:translate-x-1/2',
49
+ // Siblings of the meter, written beside it rather than inside it.
50
+ label: 'text-sm font-medium',
51
+ scale: 'flex justify-between text-xs text-muted-foreground',
47
52
  tag: 'pointer-events-none absolute top-0 flex h-7 items-center gap-1 whitespace-nowrap rounded-full bg-[var(--pu-color)] px-2.5 text-xs font-semibold tabular-nums text-[var(--pu-on-color)] shadow-[0_6px_18px_-4px_color-mix(in_oklab,var(--pu-color)_70%,transparent)] transition-[background-color,box-shadow,scale] duration-200 motion-reduce:transition-none [&_svg]:size-3.5 [&_svg]:shrink-0',
48
53
  },
49
54
  variants: {
@@ -85,7 +90,7 @@ const clamp = (value, low, high) => Math.min(high, Math.max(low, value));
85
90
  const SPREAD = 2.6;
86
91
  /** A resting tick's height, as a share of the ruler's. */
87
92
  const REST = 0.34;
88
- export function RangeMeter({ min = 0, max = 100, value, onValueChange, step = 1, marker, ticks = 41, color = 'primary', formatValue, label = 'Reading', valueText, className, children, ...props }) {
93
+ function RangeMeterRoot({ min = 0, max = 100, value, onValueChange, step = 1, marker, ticks = 41, color = 'primary', formatValue, label = 'Reading', valueText, className, children, ...props }) {
89
94
  const interactive = onValueChange !== undefined;
90
95
  const slots = rangeMeterVariants({ color, interactive, marked: marker !== undefined });
91
96
  const ruler = useRef(null);
@@ -167,4 +172,24 @@ export function RangeMeter({ min = 0, max = 100, value, onValueChange, step = 1,
167
172
  } }, index));
168
173
  }), marker !== undefined ? (_jsx("span", { className: slots.marker(), style: { insetInlineStart: `${(clamp((marker - min) / span, 0, 1) * 100).toFixed(2)}%` } })) : null] })] }));
169
174
  }
170
- RangeMeter.displayName = 'RangeMeter';
175
+ RangeMeterRoot.displayName = 'RangeMeter';
176
+ /**
177
+ * The meter's name, written over it. The meter's own `label` is what a screen
178
+ * reader says; this is what everyone else reads.
179
+ */
180
+ function RangeMeterLabel({ className, ...props }) {
181
+ return _jsx("p", { "data-slot": "range-meter-label", className: rangeMeterVariants().label({ className }), ...props });
182
+ }
183
+ RangeMeterLabel.displayName = 'RangeMeter.Label';
184
+ /** What the two ends of the ruler stand for, written under it at either side. */
185
+ function RangeMeterScale({ start, end, className, ...props }) {
186
+ return (_jsxs("div", { "data-slot": "range-meter-scale", className: rangeMeterVariants().scale({ className }), ...props, children: [_jsx("span", { children: start }), _jsx("span", { children: end })] }));
187
+ }
188
+ RangeMeterScale.displayName = 'RangeMeter.Scale';
189
+ export const RangeMeter = Object.assign(RangeMeterRoot, {
190
+ Label: RangeMeterLabel,
191
+ Scale: RangeMeterScale,
192
+ });
193
+ /* By name as well, for a Server Component, which cannot dot into a client
194
+ module. */
195
+ export { RangeMeterLabel, RangeMeterScale };
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Stat — one figure written large, with what it is and what it means.
3
+ *
4
+ * ```tsx
5
+ * <Stat>
6
+ * <Stat.Content>
7
+ * <Stat.Label>Response time</Stat.Label>
8
+ * <Stat.Value>
9
+ * 240<Stat.Unit>ms</Stat.Unit>
10
+ * </Stat.Value>
11
+ * </Stat.Content>
12
+ * <Stat.Badge>60 ms inside budget</Stat.Badge>
13
+ * </Stat>
14
+ * ```
15
+ *
16
+ * ## The figure over the chart
17
+ *
18
+ * It is the reading at the top of a panel whose body is a meter, a bar chart
19
+ * or a grid of days: the label says what is measured, the value is the
20
+ * reading, and the badge on the trailing side says how that reading stands.
21
+ * Change the value as the chart beside it changes and the two read as one.
22
+ *
23
+ * ## The row sets the baseline
24
+ *
25
+ * Inside `Stat`, the value is set solid, with no leading, so its foot sits on
26
+ * the same line as the badge's at the bottom of the row. Outside it, as a
27
+ * label and a value stacked on their own, the value keeps its line height and
28
+ * sits in running text like any other line.
29
+ *
30
+ * ## The unit follows the value's size
31
+ *
32
+ * `Stat.Unit` is written inside `Stat.Value` and takes its size and its gap
33
+ * from it, so a unit never has to be sized by hand to match its number.
34
+ *
35
+ * ## It renders on the server
36
+ *
37
+ * No state and no handlers. Everything that depends on where a part sits is
38
+ * done in CSS from data attributes, so a Server Component can render it.
39
+ */
40
+ import type { ComponentProps } from 'react';
41
+ export interface StatProps extends ComponentProps<'div'> {
42
+ }
43
+ /** A row: the label and value on the leading side, a badge on the trailing one. */
44
+ declare function StatRoot({ className, ...props }: StatProps): import("react").JSX.Element;
45
+ declare namespace StatRoot {
46
+ var displayName: string;
47
+ }
48
+ export interface StatContentProps extends ComponentProps<'div'> {
49
+ }
50
+ /** The label and the value, stacked. Used on its own when there is no badge. */
51
+ declare function StatContent({ className, ...props }: StatContentProps): import("react").JSX.Element;
52
+ declare namespace StatContent {
53
+ var displayName: string;
54
+ }
55
+ export interface StatLabelProps extends ComponentProps<'p'> {
56
+ /**
57
+ * `medium` sets the label in a heavier weight, for a figure that stands on
58
+ * its own rather than at the top of a panel that is already titled.
59
+ * Default `normal`.
60
+ */
61
+ weight?: 'normal' | 'medium';
62
+ }
63
+ /** What is measured, in a quiet line over the value. */
64
+ declare function StatLabel({ weight, className, ...props }: StatLabelProps): import("react").JSX.Element;
65
+ declare namespace StatLabel {
66
+ var displayName: string;
67
+ }
68
+ export interface StatDescriptionProps extends ComponentProps<'p'> {
69
+ }
70
+ /** What the reading means, in words: "Answering slowly". Written under the label. */
71
+ declare function StatDescription({ className, ...props }: StatDescriptionProps): import("react").JSX.Element;
72
+ declare namespace StatDescription {
73
+ var displayName: string;
74
+ }
75
+ export interface StatValueProps extends ComponentProps<'p'> {
76
+ /** `sm` is 2xl, `md` 3xl and `lg` 4xl. Default `lg`. */
77
+ size?: 'sm' | 'md' | 'lg';
78
+ }
79
+ /** The figure. Put a `Stat.Unit` inside it, after the number. */
80
+ declare function StatValue({ size, className, ...props }: StatValueProps): import("react").JSX.Element;
81
+ declare namespace StatValue {
82
+ var displayName: string;
83
+ }
84
+ export interface StatUnitProps extends ComponentProps<'span'> {
85
+ }
86
+ /** The unit after the number, smaller and quieter, sized from the value it is in. */
87
+ declare function StatUnit({ className, ...props }: StatUnitProps): import("react").JSX.Element;
88
+ declare namespace StatUnit {
89
+ var displayName: string;
90
+ }
91
+ export interface StatBadgeProps extends ComponentProps<'span'> {
92
+ }
93
+ /** How the reading stands, in a pill on the row's trailing side. */
94
+ declare function StatBadge({ className, ...props }: StatBadgeProps): import("react").JSX.Element;
95
+ declare namespace StatBadge {
96
+ var displayName: string;
97
+ }
98
+ export declare const Stat: typeof StatRoot & {
99
+ Content: typeof StatContent;
100
+ Label: typeof StatLabel;
101
+ Description: typeof StatDescription;
102
+ Value: typeof StatValue;
103
+ Unit: typeof StatUnit;
104
+ Badge: typeof StatBadge;
105
+ };
106
+ export { StatContent, StatLabel, StatDescription, StatValue, StatUnit, StatBadge };
@@ -0,0 +1,72 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { tv } from 'tailwind-variants';
3
+ const statVariants = tv({
4
+ slots: {
5
+ root: 'flex items-end justify-between gap-4',
6
+ content: 'flex flex-col gap-1',
7
+ label: 'text-sm text-muted-foreground',
8
+ description: 'text-sm font-medium',
9
+ // Solid inside a row, so its foot lines up with the badge's.
10
+ value: 'group/stat-value font-bold tracking-tight in-data-[slot=stat]:leading-none',
11
+ unit: [
12
+ 'ms-1 text-sm font-medium text-muted-foreground',
13
+ 'group-data-[size=lg]/stat-value:ms-1.5 group-data-[size=lg]/stat-value:text-base',
14
+ ],
15
+ badge: 'rounded-full bg-muted px-2.5 py-1 text-xs font-medium text-muted-foreground',
16
+ },
17
+ variants: {
18
+ size: {
19
+ sm: { value: 'text-2xl' },
20
+ md: { value: 'text-3xl' },
21
+ lg: { value: 'text-4xl' },
22
+ },
23
+ weight: {
24
+ normal: {},
25
+ medium: { label: 'font-medium' },
26
+ },
27
+ },
28
+ });
29
+ /** A row: the label and value on the leading side, a badge on the trailing one. */
30
+ function StatRoot({ className, ...props }) {
31
+ return _jsx("div", { "data-slot": "stat", className: statVariants().root({ className }), ...props });
32
+ }
33
+ StatRoot.displayName = 'Stat';
34
+ /** The label and the value, stacked. Used on its own when there is no badge. */
35
+ function StatContent({ className, ...props }) {
36
+ return _jsx("div", { "data-slot": "stat-content", className: statVariants().content({ className }), ...props });
37
+ }
38
+ StatContent.displayName = 'Stat.Content';
39
+ /** What is measured, in a quiet line over the value. */
40
+ function StatLabel({ weight = 'normal', className, ...props }) {
41
+ return _jsx("p", { "data-slot": "stat-label", className: statVariants({ weight }).label({ className }), ...props });
42
+ }
43
+ StatLabel.displayName = 'Stat.Label';
44
+ /** What the reading means, in words: "Answering slowly". Written under the label. */
45
+ function StatDescription({ className, ...props }) {
46
+ return (_jsx("p", { "data-slot": "stat-description", className: statVariants().description({ className }), ...props }));
47
+ }
48
+ StatDescription.displayName = 'Stat.Description';
49
+ /** The figure. Put a `Stat.Unit` inside it, after the number. */
50
+ function StatValue({ size = 'lg', className, ...props }) {
51
+ return (_jsx("p", { "data-slot": "stat-value", "data-size": size, className: statVariants({ size }).value({ className }), ...props }));
52
+ }
53
+ StatValue.displayName = 'Stat.Value';
54
+ /** The unit after the number, smaller and quieter, sized from the value it is in. */
55
+ function StatUnit({ className, ...props }) {
56
+ return _jsx("span", { "data-slot": "stat-unit", className: statVariants().unit({ className }), ...props });
57
+ }
58
+ StatUnit.displayName = 'Stat.Unit';
59
+ /** How the reading stands, in a pill on the row's trailing side. */
60
+ function StatBadge({ className, ...props }) {
61
+ return _jsx("span", { "data-slot": "stat-badge", className: statVariants().badge({ className }), ...props });
62
+ }
63
+ StatBadge.displayName = 'Stat.Badge';
64
+ export const Stat = Object.assign(StatRoot, {
65
+ Content: StatContent,
66
+ Label: StatLabel,
67
+ Description: StatDescription,
68
+ Value: StatValue,
69
+ Unit: StatUnit,
70
+ Badge: StatBadge,
71
+ });
72
+ export { StatContent, StatLabel, StatDescription, StatValue, StatUnit, StatBadge };
@@ -5,7 +5,10 @@
5
5
  * ```tsx
6
6
  * <TiltCard>
7
7
  * <TiltCard.Layer depth={24}>…a figure…</TiltCard.Layer>
8
- * <TiltCard.Layer depth={8}>…its caption…</TiltCard.Layer>
8
+ * <TiltCard.Layer depth={8}>
9
+ * <TiltCard.Title>Versions</TiltCard.Title>
10
+ * <TiltCard.Description>Every save is kept.</TiltCard.Description>
11
+ * </TiltCard.Layer>
9
12
  * </TiltCard>
10
13
  * ```
11
14
  *
@@ -54,7 +57,25 @@ declare function TiltCardLayer({ depth, className, style, ...props }: TiltCardLa
54
57
  declare namespace TiltCardLayer {
55
58
  var displayName: string;
56
59
  }
60
+ export interface TiltCardTitleProps extends ComponentProps<'h3'> {
61
+ /** The heading level, to fit the page around the card. Default `h3`. */
62
+ as?: 'h2' | 'h3' | 'h4' | 'p';
63
+ }
64
+ /** What the card is about. */
65
+ declare function TiltCardTitle({ as: Tag, className, ...props }: TiltCardTitleProps): import("react").JSX.Element;
66
+ declare namespace TiltCardTitle {
67
+ var displayName: string;
68
+ }
69
+ export interface TiltCardDescriptionProps extends ComponentProps<'p'> {
70
+ }
71
+ /** A line or two of body text, under the title. */
72
+ declare function TiltCardDescription({ className, ...props }: TiltCardDescriptionProps): import("react").JSX.Element;
73
+ declare namespace TiltCardDescription {
74
+ var displayName: string;
75
+ }
57
76
  export declare const TiltCard: typeof TiltCardRoot & {
58
77
  Layer: typeof TiltCardLayer;
78
+ Title: typeof TiltCardTitle;
79
+ Description: typeof TiltCardDescription;
59
80
  };
60
- export { TiltCardLayer };
81
+ export { TiltCardLayer, TiltCardTitle, TiltCardDescription };
@@ -7,7 +7,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  * ```tsx
8
8
  * <TiltCard>
9
9
  * <TiltCard.Layer depth={24}>…a figure…</TiltCard.Layer>
10
- * <TiltCard.Layer depth={8}>…its caption…</TiltCard.Layer>
10
+ * <TiltCard.Layer depth={8}>
11
+ * <TiltCard.Title>Versions</TiltCard.Title>
12
+ * <TiltCard.Description>Every save is kept.</TiltCard.Description>
13
+ * </TiltCard.Layer>
11
14
  * </TiltCard>
12
15
  * ```
13
16
  *
@@ -44,6 +47,8 @@ const tiltCardVariants = tv({
44
47
  card: 'relative overflow-hidden rounded-3xl border bg-card text-card-foreground shadow-sm transition-[transform,box-shadow,border-color] duration-500 ease-out [transform-style:preserve-3d] [transform:rotateX(var(--pu-rx,0deg))_rotateY(var(--pu-ry,0deg))] group-data-[tilting]/tilt:shadow-xl group-data-[tilting]/tilt:duration-100 motion-reduce:transition-none motion-reduce:[transform:none]',
45
48
  // The light is the card's colour, soft and wide, centred on the pointer.
46
49
  glare: 'pointer-events-none absolute inset-0 rounded-[inherit] bg-[radial-gradient(18rem_circle_at_var(--pu-gx,50%)_var(--pu-gy,50%),color-mix(in_oklab,var(--pu-color)_16%,transparent),transparent_70%)] opacity-0 transition-opacity duration-300 group-data-[tilting]/tilt:opacity-100',
50
+ title: 'text-base font-semibold',
51
+ description: 'text-sm text-muted-foreground',
47
52
  layer: 'transition-transform duration-500 ease-out [transform:translate3d(calc(var(--pu-px,0)*var(--pu-depth)*1px),calc(var(--pu-py,0)*var(--pu-depth)*1px),calc(var(--pu-depth)*1px))] group-data-[tilting]/tilt:duration-100 motion-reduce:[transform:none]',
48
53
  },
49
54
  variants: {
@@ -106,9 +111,21 @@ function TiltCardLayer({ depth = 16, className, style, ...props }) {
106
111
  return (_jsx("div", { className: tiltCardVariants().layer({ className }), style: { ['--pu-depth']: depth, ...style }, ...props }));
107
112
  }
108
113
  TiltCardLayer.displayName = 'TiltCard.Layer';
114
+ /** What the card is about. */
115
+ function TiltCardTitle({ as: Tag = 'h3', className, ...props }) {
116
+ return _jsx(Tag, { "data-slot": "tilt-card-title", className: tiltCardVariants().title({ className }), ...props });
117
+ }
118
+ TiltCardTitle.displayName = 'TiltCard.Title';
119
+ /** A line or two of body text, under the title. */
120
+ function TiltCardDescription({ className, ...props }) {
121
+ return (_jsx("p", { "data-slot": "tilt-card-description", className: tiltCardVariants().description({ className }), ...props }));
122
+ }
123
+ TiltCardDescription.displayName = 'TiltCard.Description';
109
124
  export const TiltCard = Object.assign(TiltCardRoot, {
110
125
  Layer: TiltCardLayer,
126
+ Title: TiltCardTitle,
127
+ Description: TiltCardDescription,
111
128
  });
112
129
  /* By name as well, for a Server Component, which cannot dot into a client
113
130
  module. */
114
- export { TiltCardLayer };
131
+ export { TiltCardLayer, TiltCardTitle, TiltCardDescription };
package/dist/index.d.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  export { cn } from './lib/cn.js';
2
2
  export { RollingNumber, type RollingNumberProps } from './components/rolling-number/index.js';
3
- export { Planet, PlanetGlobe, PlanetMarker, PlanetControls, type PlanetProps, type PlanetHandle, type PlanetRotation, type PlanetGlobeProps, type PlanetMarkerProps, type PlanetMarkerColor, type PlanetControlsProps, } from './components/planet/index.js';
4
- export { Feedback, FeedbackTrigger, FeedbackContent, FeedbackPanel, FeedbackTitle, FeedbackClose, FeedbackField, FeedbackFooter, FeedbackCancel, FeedbackSubmit, type FeedbackProps, type FeedbackTriggerProps, type FeedbackContentProps, type FeedbackPanelProps, type FeedbackTitleProps, type FeedbackCloseProps, type FeedbackFieldProps, type FeedbackFooterProps, type FeedbackActionProps, type FeedbackSubmitProps, } from './components/feedback/index.js';
3
+ export { Planet, PlanetGlobe, PlanetMarker, PlanetControls, PlanetList, PlanetListItem, type PlanetProps, type PlanetHandle, type PlanetRotation, type PlanetGlobeProps, type PlanetMarkerProps, type PlanetMarkerColor, type PlanetControlsProps, type PlanetListProps, type PlanetListItemProps, } from './components/planet/index.js';
4
+ export { Feedback, FeedbackTrigger, FeedbackContent, FeedbackPanel, FeedbackTitle, FeedbackClose, FeedbackField, FeedbackDescription, FeedbackMessage, FeedbackRating, FeedbackFooter, FeedbackCancel, FeedbackSubmit, type FeedbackProps, type FeedbackTriggerProps, type FeedbackContentProps, type FeedbackPanelProps, type FeedbackTitleProps, type FeedbackCloseProps, type FeedbackFieldProps, type FeedbackDescriptionProps, type FeedbackMessageProps, type FeedbackRatingProps, type FeedbackFooterProps, type FeedbackActionProps, type FeedbackSubmitProps, } from './components/feedback/index.js';
5
5
  export { Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter, type CardProps, type CardHeaderProps, type CardTitleProps, type CardDescriptionProps, type CardActionProps, type CardContentProps, type CardFooterProps, } from './components/card/index.js';
6
6
  export { Frame, FrameHeader, FrameTitle, FrameDescription, FrameAction, FramePanel, FrameRow, FrameMedia, FrameContent, FrameActions, FrameSection, FrameFooter, type FrameProps, type FrameVariant, type FrameHeaderProps, type FrameTitleProps, type FrameDescriptionProps, type FrameActionProps, type FramePanelProps, type FrameRowProps, type FrameMediaProps, type FrameContentProps, type FrameActionsProps, type FrameSectionProps, type FrameFooterProps, } from './components/frame/index.js';
7
7
  export { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter, SheetClose, SheetStage, type SheetProps, type SheetSide, type SheetTriggerProps, type SheetContentProps, type SheetHeaderProps, type SheetTitleProps, type SheetDescriptionProps, type SheetBodyProps, type SheetFooterProps, type SheetCloseProps, type SheetStageProps, } from './components/sheet/index.js';
8
- export { DayGrid, DayGridLegend, type DayGridProps, type DayGridLegendProps, type DayGridColor, type DayCell, type DayLevel, } from './components/day-grid/index.js';
9
- export { RangeMeter, type RangeMeterProps, type RangeMeterColor, } from './components/range-meter/index.js';
8
+ export { DayGrid, DayGridLegend, DayGridWeekdays, DayGridCaption, DayGridTitle, DayGridDescription, type DayGridProps, type DayGridLegendProps, type DayGridWeekdaysProps, type DayGridCaptionProps, type DayGridTitleProps, type DayGridDescriptionProps, type DayGridColor, type DayCell, type DayLevel, } from './components/day-grid/index.js';
9
+ export { RangeMeter, RangeMeterLabel, RangeMeterScale, type RangeMeterProps, type RangeMeterLabelProps, type RangeMeterScaleProps, type RangeMeterColor, } from './components/range-meter/index.js';
10
10
  export { BarPicker, type BarPickerProps, type BarPickerBar, type BarPickerColor, } from './components/bar-picker/index.js';
11
11
  export { Kpi, KpiHeader, KpiIcon, KpiTitle, KpiActions, KpiContent, KpiStat, KpiValue, KpiTrend, KpiChart, KpiProgress, KpiFooter, KpiSeparator, KpiGroup, type KpiProps, type KpiHeaderProps, type KpiIconProps, type KpiTitleProps, type KpiActionsProps, type KpiContentProps, type KpiStatProps, type KpiValueProps, type KpiTrendProps, type KpiChartProps, type KpiProgressProps, type KpiFooterProps, type KpiSeparatorProps, type KpiGroupProps, type KpiColor, type KpiGoodDirection, type KpiTone, } from './components/kpi/index.js';
12
- export { LaneBoard, LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta, type LaneBoardProps, type LaneBoardTitleProps, type LaneBoardCodeProps, type LaneBoardRowProps, type LaneBoardStepsProps, type LaneBoardTagProps, type LaneBoardMetaProps, type LaneBoardCard, type LaneBoardLane, type LaneBoardMove, type LaneBoardColor, } from './components/lane-board/index.js';
13
- export { Flow, FlowBackground, FlowNode, FlowHandle, FlowEdge, FlowGroup, FlowControls, FlowMiniMap, type FlowProps, type FlowBackgroundProps, type FlowNodeProps, type FlowHandleProps, type FlowEdgeProps, type FlowGroupProps, type FlowControlsProps, type FlowMiniMapProps, type FlowViewport, type FlowNodePosition, type FlowEndpoint, type FlowEndpointReference, type FlowConnection, type FlowEdgeVariant, type FlowColor, type FlowSide, } from './components/flow/index.js';
14
- export { TiltCard, TiltCardLayer, type TiltCardProps, type TiltCardLayerProps, type TiltCardColor, } from './components/tilt-card/index.js';
15
- export { CommandDock, CommandDockTrigger, CommandDockPanel, CommandDockInput, CommandDockResults, CommandDockRow, CommandDockStatus, type CommandDockProps, type CommandDockTriggerProps, type CommandDockPanelProps, type CommandDockInputProps, type CommandDockResultsProps, type CommandDockRowProps, type CommandDockStatusProps, } from './components/command-dock/index.js';
12
+ export { LaneBoard, LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta, LaneBoardAvatar, type LaneBoardProps, type LaneBoardTitleProps, type LaneBoardCodeProps, type LaneBoardRowProps, type LaneBoardStepsProps, type LaneBoardTagProps, type LaneBoardMetaProps, type LaneBoardAvatarProps, type LaneBoardCard, type LaneBoardLane, type LaneBoardMove, type LaneBoardColor, } from './components/lane-board/index.js';
13
+ export { Flow, FlowBackground, FlowNode, FlowHandle, FlowEdge, FlowGroup, FlowGroupItem, FlowNodeHeader, FlowNodeContent, FlowNodeTitle, FlowNodeDescription, FlowNodeBadge, FlowControls, FlowMiniMap, type FlowProps, type FlowBackgroundProps, type FlowNodeProps, type FlowHandleProps, type FlowEdgeProps, type FlowGroupProps, type FlowGroupItemProps, type FlowNodeHeaderProps, type FlowNodeContentProps, type FlowNodeTitleProps, type FlowNodeDescriptionProps, type FlowNodeBadgeProps, type FlowControlsProps, type FlowMiniMapProps, type FlowViewport, type FlowNodePosition, type FlowEndpoint, type FlowEndpointReference, type FlowConnection, type FlowEdgeVariant, type FlowColor, type FlowSide, } from './components/flow/index.js';
14
+ export { TiltCard, TiltCardLayer, TiltCardTitle, TiltCardDescription, type TiltCardProps, type TiltCardLayerProps, type TiltCardTitleProps, type TiltCardDescriptionProps, type TiltCardColor, } from './components/tilt-card/index.js';
15
+ export { Stat, StatContent, StatLabel, StatDescription, StatValue, StatUnit, StatBadge, type StatProps, type StatContentProps, type StatLabelProps, type StatDescriptionProps, type StatValueProps, type StatUnitProps, type StatBadgeProps, } from './components/stat/index.js';
16
+ export { CommandDock, CommandDockTrigger, CommandDockPanel, CommandDockInput, CommandDockResults, CommandDockRow, CommandDockRowTitle, CommandDockRowMeta, CommandDockStatus, type CommandDockProps, type CommandDockTriggerProps, type CommandDockPanelProps, type CommandDockInputProps, type CommandDockResultsProps, type CommandDockRowProps, type CommandDockRowTitleProps, type CommandDockRowMetaProps, type CommandDockStatusProps, } from './components/command-dock/index.js';
package/dist/index.js CHANGED
@@ -1,15 +1,16 @@
1
1
  export { cn } from './lib/cn.js';
2
2
  export { RollingNumber } from './components/rolling-number/index.js';
3
- export { Planet, PlanetGlobe, PlanetMarker, PlanetControls, } from './components/planet/index.js';
4
- export { Feedback, FeedbackTrigger, FeedbackContent, FeedbackPanel, FeedbackTitle, FeedbackClose, FeedbackField, FeedbackFooter, FeedbackCancel, FeedbackSubmit, } from './components/feedback/index.js';
3
+ export { Planet, PlanetGlobe, PlanetMarker, PlanetControls, PlanetList, PlanetListItem, } from './components/planet/index.js';
4
+ export { Feedback, FeedbackTrigger, FeedbackContent, FeedbackPanel, FeedbackTitle, FeedbackClose, FeedbackField, FeedbackDescription, FeedbackMessage, FeedbackRating, FeedbackFooter, FeedbackCancel, FeedbackSubmit, } from './components/feedback/index.js';
5
5
  export { Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter, } from './components/card/index.js';
6
6
  export { Frame, FrameHeader, FrameTitle, FrameDescription, FrameAction, FramePanel, FrameRow, FrameMedia, FrameContent, FrameActions, FrameSection, FrameFooter, } from './components/frame/index.js';
7
7
  export { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter, SheetClose, SheetStage, } from './components/sheet/index.js';
8
- export { DayGrid, DayGridLegend, } from './components/day-grid/index.js';
9
- export { RangeMeter, } from './components/range-meter/index.js';
8
+ export { DayGrid, DayGridLegend, DayGridWeekdays, DayGridCaption, DayGridTitle, DayGridDescription, } from './components/day-grid/index.js';
9
+ export { RangeMeter, RangeMeterLabel, RangeMeterScale, } from './components/range-meter/index.js';
10
10
  export { BarPicker, } from './components/bar-picker/index.js';
11
11
  export { Kpi, KpiHeader, KpiIcon, KpiTitle, KpiActions, KpiContent, KpiStat, KpiValue, KpiTrend, KpiChart, KpiProgress, KpiFooter, KpiSeparator, KpiGroup, } from './components/kpi/index.js';
12
- export { LaneBoard, LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta, } from './components/lane-board/index.js';
13
- export { Flow, FlowBackground, FlowNode, FlowHandle, FlowEdge, FlowGroup, FlowControls, FlowMiniMap, } from './components/flow/index.js';
14
- export { TiltCard, TiltCardLayer, } from './components/tilt-card/index.js';
15
- export { CommandDock, CommandDockTrigger, CommandDockPanel, CommandDockInput, CommandDockResults, CommandDockRow, CommandDockStatus, } from './components/command-dock/index.js';
12
+ export { LaneBoard, LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta, LaneBoardAvatar, } from './components/lane-board/index.js';
13
+ export { Flow, FlowBackground, FlowNode, FlowHandle, FlowEdge, FlowGroup, FlowGroupItem, FlowNodeHeader, FlowNodeContent, FlowNodeTitle, FlowNodeDescription, FlowNodeBadge, FlowControls, FlowMiniMap, } from './components/flow/index.js';
14
+ export { TiltCard, TiltCardLayer, TiltCardTitle, TiltCardDescription, } from './components/tilt-card/index.js';
15
+ export { Stat, StatContent, StatLabel, StatDescription, StatValue, StatUnit, StatBadge, } from './components/stat/index.js';
16
+ export { CommandDock, CommandDockTrigger, CommandDockPanel, CommandDockInput, CommandDockResults, CommandDockRow, CommandDockRowTitle, CommandDockRowMeta, CommandDockStatus, } from './components/command-dock/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panelui-web",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "PanelUI for the web: animated, data-rich React components styled with Tailwind CSS on shadcn tokens.",
5
5
  "type": "module",
6
6
  "sideEffects": false,