xedonium 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.
package/README.md CHANGED
@@ -6,8 +6,11 @@ Square corners, semantic `app-*` color tokens, light/dark via `<html data-theme>
6
6
  ## Install
7
7
 
8
8
  ```bash
9
- npm i xedonium # or: yarn add xedonium
10
- # peers: react, react-dom, tailwindcss ^3.4
9
+ npm install xedonium
10
+ # or: yarn add xedonium
11
+ # or: pnpm add xedonium
12
+
13
+ # peers: react, react-dom (18+), tailwindcss ^3.4
11
14
  ```
12
15
 
13
16
  ## Setup
@@ -46,6 +49,7 @@ import { ThemeProvider, AppBar, PageLayout, Button } from 'xedonium'
46
49
  ## What's included
47
50
 
48
51
  - Layout: `AppShell`, `AppBar`, `Navbar`, `Sidebar`, `PageLayout`, `PageHeader`, `Container`, `Flex`, `Stack`, `Grid`, `Card`, `Dashboard`, `Divider`, `Tabs`, `Breadcrumb`
52
+ - Typography: `PageTitle`, `BodyText`, `HelperText`, `Label`, `TextLink`
49
53
  - Forms: `Button`, `Field`, `Input`, `Select`, `Checkbox`, `Radio`, `RadioGroup`, `Switch`, `Slider`, `DatePicker`, `DateRangePicker`, `TimePicker`, `FileUpload`
50
54
  - Data: `Table`, `DataGrid`, `List`, `SortableList`, `VirtualList`, `Tree`, `Pagination`, `Calendar`, `Carousel`, `Timeline`, `Stepper`, `StatCard`, and charts (`LineChart`, `AreaChart`, `BarChart`, `PieChart`)
51
55
  - Feedback and overlays: `Alert`, `Toast`, `Tooltip`, `Modal`, `ConfirmDialog`, `Drawer`, `Popover`, `ActionMenu`, `CommandPalette`, `NotificationCenter`, `Progress`, `Skeleton`, `FanFavicon`, `LoadingScreen`, `RackServer`
@@ -55,20 +59,24 @@ import { ThemeProvider, AppBar, PageLayout, Button } from 'xedonium'
55
59
 
56
60
  `AppBar` has no router dependency. For react-router pass `linkComponent={Link} linkProp="to"`.
57
61
 
58
- Overlay z-indexes can be overridden with `--xd-z-modal`, `--xd-z-toast`, `--xd-z-tooltip`.
62
+ Overlay z-indexes can be overridden with `--xd-z-modal`, `--xd-z-popover`, `--xd-z-toast`, `--xd-z-tooltip`.
59
63
 
60
64
  ## Develop
61
65
 
62
66
  ```bash
63
- yarn dev # playground (every component, tabbed) at http://localhost:3100
67
+ yarn docs # docs site + playground at http://localhost:3100
64
68
  yarn build # dist/ (ESM, CJS, .d.ts, styles.css)
65
69
  ```
66
70
 
67
71
  ## Docs
68
72
 
69
- Docusaurus site in `docs/` (live examples, uses the built `dist/`). Install once with `yarn --cwd docs install`.
73
+ The docs site in `docs/` is a small Vite + React app built with the library itself (imported from `src/`, no build step needed).
74
+
75
+ - Pages: `docs/src/content/<category>.js` lists each component's page; its demos live in `docs/src/examples/<category>/<slug>-<n>.jsx` and the code shown is exactly the file that is rendered.
76
+ - Props tables: `docs/src/content/props.js`. `yarn docs:check` fails if a component's props and its table drift apart.
70
77
 
71
78
  ```bash
72
- yarn docs # builds the lib, then serves at http://localhost:3000
73
- yarn docs:build # static site in docs/build
79
+ yarn docs:build # static site in docs/dist (+ 404.html for GitHub Pages deep links)
80
+ yarn docs:preview # serve the production build
81
+ yarn docs:check # verify props tables and example files
74
82
  ```
@@ -1,13 +1,16 @@
1
1
  export default ActionMenu;
2
2
  /**
3
3
  * Dropdown of page actions. Closes on outside click and Escape (focus returns to the trigger).
4
+ * The menu is portalled to <body>, so scroll containers and overflow: hidden ancestors can't clip it.
4
5
  * items: [{ key, label, description?, badge?, tone?, disabled?, hasDialog?, onClick }]
5
6
  * `trigger` is the button content; `variant` styles the trigger (e.g. 'warning' to flag pending work).
7
+ * `placement` is where the menu opens (default "bottom-start"; e.g. "bottom-end", "top-start"). It flips above or to the other edge when there is no room, and re-adjusts on scroll and resize.
6
8
  */
7
- declare function ActionMenu({ label, trigger, variant, items, className }: {
9
+ declare function ActionMenu({ label, trigger, variant, items, placement, className }: {
8
10
  label: any;
9
11
  trigger: any;
10
12
  variant?: string;
11
13
  items: any;
14
+ placement?: string;
12
15
  className?: string;
13
16
  }): import("react").JSX.Element;
@@ -2,6 +2,7 @@ export default AppShell;
2
2
  /**
3
3
  * Application frame: header on top, `sidebar` on the left, scrolling `children` as the main area.
4
4
  * Below the `md` breakpoint the sidebar moves into a Drawer opened from a menu button in the header.
5
+ * The drawer closes by itself when the window grows to the `md` breakpoint, where the sidebar is shown inline.
5
6
  * `sidebar` may be a node, or a function `(close) => node` if it should close the drawer on selection.
6
7
  */
7
8
  declare function AppShell({ header, sidebar, sidebarTitle, children, className }: {
@@ -0,0 +1,8 @@
1
+ export default BodyText;
2
+ /** Body copy: `text-sm` in the primary text color. `as` changes the element (default p). */
3
+ declare function BodyText({ as: Tag, className, children, ...rest }: {
4
+ [x: string]: any;
5
+ as?: string;
6
+ className?: string;
7
+ children: any;
8
+ }): import("react").JSX.Element;
@@ -1,5 +1,8 @@
1
1
  export default Checkbox;
2
- /** Checkbox with inline label. `onChange` receives the new boolean. `indeterminate` shows the mixed state. */
2
+ /**
3
+ * Square checkbox with inline label. `onChange` receives the new boolean. `indeterminate` shows the mixed state.
4
+ * The native input stays in the DOM (visually hidden) so forms, labels and keyboard behave normally.
5
+ */
3
6
  declare function Checkbox({ label, checked, onChange, indeterminate, disabled, className, ...rest }: {
4
7
  [x: string]: any;
5
8
  label: any;
@@ -1,11 +1,15 @@
1
1
  export default Drawer;
2
- /** Side panel dialog: backdrop, focus trap, Escape / backdrop to close. side: right | left. */
3
- declare function Drawer({ open, onClose, title, side, width, footer, children }: {
2
+ /**
3
+ * Side panel dialog: backdrop, focus trap, Escape / backdrop to close. side: right | left.
4
+ * `padded={false}` removes the body padding and lets the content fill (and scroll) itself, e.g. a Sidebar.
5
+ */
6
+ declare function Drawer({ open, onClose, title, side, width, padded, footer, children }: {
4
7
  open: any;
5
8
  onClose: any;
6
9
  title: any;
7
10
  side?: string;
8
11
  width?: string;
12
+ padded?: boolean;
9
13
  footer: any;
10
14
  children: any;
11
15
  }): any;
@@ -0,0 +1,21 @@
1
+ export default FloatingPanel;
2
+ /**
3
+ * A panel positioned next to `anchorRef`'s element, rendered into <body> with fixed positioning so no
4
+ * ancestor (overflow: hidden, transforms, dialogs) can clip it. It flips to the opposite side when there is
5
+ * no room, stays inside the viewport and follows the anchor on scroll and resize.
6
+ *
7
+ * placement: top | bottom | left | right | auto, optionally with -start / -end (e.g. "bottom-end").
8
+ * `matchWidth` makes the panel at least as wide as the anchor. Pass `panelRef` to read the element.
9
+ */
10
+ declare function FloatingPanel({ open, anchorRef, placement, gap, matchWidth, panelRef, className, style, children, ...rest }: {
11
+ [x: string]: any;
12
+ open: any;
13
+ anchorRef: any;
14
+ placement?: string;
15
+ gap?: number;
16
+ matchWidth?: boolean;
17
+ panelRef: any;
18
+ className?: string;
19
+ style: any;
20
+ children: any;
21
+ }): any;
@@ -0,0 +1,8 @@
1
+ export default HelperText;
2
+ /** Secondary text for hints and captions: `text-xs` in the muted color. `as` changes the element (default p). */
3
+ declare function HelperText({ as: Tag, className, children, ...rest }: {
4
+ [x: string]: any;
5
+ as?: string;
6
+ className?: string;
7
+ children: any;
8
+ }): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ export default Label;
2
+ /**
3
+ * Small uppercase label. Renders a real <label> when `htmlFor` is given (use it for form controls), otherwise a
4
+ * <span>; `as` overrides the element.
5
+ */
6
+ declare function Label({ as, htmlFor, className, children, ...rest }: {
7
+ [x: string]: any;
8
+ as: any;
9
+ htmlFor: any;
10
+ className?: string;
11
+ children: any;
12
+ }): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ export default PageTitle;
2
+ /** Page heading: bold, tight tracking, 2xl on phones and 3xl from `sm`. `as` changes the element (default h1). */
3
+ declare function PageTitle({ as: Tag, className, children, ...rest }: {
4
+ [x: string]: any;
5
+ as?: string;
6
+ className?: string;
7
+ children: any;
8
+ }): import("react").JSX.Element;
@@ -1,13 +1,17 @@
1
1
  export default Popover;
2
2
  /**
3
3
  * Button that toggles a floating panel with arbitrary content. Closes on outside click and Escape
4
- * (focus returns to the trigger). align: start | end. Use ActionMenu for a plain list of actions.
4
+ * (focus returns to the trigger). The panel is portalled to <body>, so it is never clipped by an
5
+ * ancestor, and it flips when there is no room.
6
+ * placement: top | bottom | left | right | auto, optionally with -start / -end. `align` (start | end) is the
7
+ * shorthand for bottom-start / bottom-end. Use ActionMenu for a plain list of actions.
5
8
  */
6
- declare function Popover({ trigger, label, variant, align, className, children }: {
9
+ declare function Popover({ trigger, label, variant, align, placement, className, children }: {
7
10
  trigger: any;
8
11
  label: any;
9
12
  variant?: string;
10
13
  align?: string;
14
+ placement: any;
11
15
  className?: string;
12
16
  children: any;
13
17
  }): import("react").JSX.Element;
@@ -1,6 +1,10 @@
1
1
  export default Select;
2
- /** Labelled native select. options: [{ value, label, disabled? }]. `onChange` receives the value string. */
3
- declare function Select({ label, value, onChange, options, placeholder, error, className, ...rest }: {
2
+ /**
3
+ * Labelled select with a themed listbox (portalled, so it is never clipped). Keyboard: Up / Down / Home / End move,
4
+ * Enter or Space picks, Escape closes, typing jumps to a matching option.
5
+ * options: [{ value, label, disabled? }]. `onChange` receives the value string. `name` adds a hidden input for forms.
6
+ */
7
+ declare function Select({ label, value, onChange, options, placeholder, error, disabled, name, className, ...rest }: {
4
8
  [x: string]: any;
5
9
  label: any;
6
10
  value: any;
@@ -8,5 +12,7 @@ declare function Select({ label, value, onChange, options, placeholder, error, c
8
12
  options: any;
9
13
  placeholder: any;
10
14
  error: any;
15
+ disabled?: boolean;
16
+ name: any;
11
17
  className?: string;
12
18
  }): import("react").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  export default Slider;
2
- /** Range input. `onChange` receives a number. */
2
+ /** Range input with a square thumb and a filled track (styled in styles.css). `onChange` receives a number. */
3
3
  declare function Slider({ label, value, onChange, min, max, step, showValue, className, ...rest }: {
4
4
  [x: string]: any;
5
5
  label: any;
@@ -0,0 +1,13 @@
1
+ export default TextLink;
2
+ /**
3
+ * Underlined inline link with a hover color. `linkComponent` / `linkProp` swap in a router link, as in AppBar
4
+ * (e.g. `linkComponent={Link} linkProp="to"`).
5
+ */
6
+ declare function TextLink({ href, linkComponent: Link, linkProp, className, children, ...rest }: {
7
+ [x: string]: any;
8
+ href: any;
9
+ linkComponent?: string;
10
+ linkProp?: string;
11
+ className?: string;
12
+ children: any;
13
+ }): import("react").JSX.Element;
@@ -1,6 +1,10 @@
1
1
  export default TimePicker;
2
- /** Labelled time field using the native time control. `value` / `onChange` use "HH:MM" strings. `step` is in seconds. */
3
- declare function TimePicker({ label, value, onChange, step, min, max, error, ...rest }: {
2
+ /**
3
+ * Time field with a themed hour / minute picker (no native control). `value` / `onChange` use 24-hour "HH:MM" strings.
4
+ * `step` is the minute granularity in seconds (default 900 = 15 min). `min` / `max` ("HH:MM") disable times outside
5
+ * them. `hour12` shows the hours on a 12-hour clock with AM / PM (the value stays 24-hour).
6
+ */
7
+ declare function TimePicker({ label, value, onChange, step, min, max, hour12, placeholder, error, disabled, className, ...rest }: {
4
8
  [x: string]: any;
5
9
  label: any;
6
10
  value: any;
@@ -8,5 +12,9 @@ declare function TimePicker({ label, value, onChange, step, min, max, error, ...
8
12
  step?: number;
9
13
  min: any;
10
14
  max: any;
15
+ hour12?: boolean;
16
+ placeholder?: string;
11
17
  error: any;
18
+ disabled?: boolean;
19
+ className?: string;
12
20
  }): import("react").JSX.Element;
@@ -1,6 +1,7 @@
1
1
  export default Tooltip;
2
- declare function Tooltip({ text, children, className }: {
2
+ declare function Tooltip({ text, children, placement, className }: {
3
3
  text: any;
4
4
  children: any;
5
+ placement?: string;
5
6
  className?: string;
6
7
  }): any;
@@ -1,2 +1,2 @@
1
1
  export default useDismissable;
2
- declare function useDismissable(open: any, rootRef: any, onDismiss: any): void;
2
+ declare function useDismissable(open: any, insideRefs: any, onDismiss: any): void;
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export { default as AppShell } from "./components/AppShell";
5
5
  export { default as AreaChart } from "./components/AreaChart";
6
6
  export { default as Avatar } from "./components/Avatar";
7
7
  export { default as BarChart } from "./components/BarChart";
8
+ export { default as BodyText } from "./components/BodyText";
8
9
  export { default as Breadcrumb } from "./components/Breadcrumb";
9
10
  export { default as Button } from "./components/Button";
10
11
  export { default as Calendar } from "./components/Calendar";
@@ -26,8 +27,10 @@ export { default as FileUpload } from "./components/FileUpload";
26
27
  export { default as Flex } from "./components/Flex";
27
28
  export { default as FocusTrap } from "./components/FocusTrap";
28
29
  export { default as Grid } from "./components/Grid";
30
+ export { default as HelperText } from "./components/HelperText";
29
31
  export { default as Image } from "./components/Image";
30
32
  export { default as Input } from "./components/Input";
33
+ export { default as Label } from "./components/Label";
31
34
  export { default as LineChart } from "./components/LineChart";
32
35
  export { default as List } from "./components/List";
33
36
  export { default as LoadingScreen } from "./components/LoadingScreen";
@@ -36,6 +39,7 @@ export { default as Navbar } from "./components/Navbar";
36
39
  export { default as NotificationCenter } from "./components/NotificationCenter";
37
40
  export { default as PageHeader } from "./components/PageHeader";
38
41
  export { default as PageLayout } from "./components/PageLayout";
42
+ export { default as PageTitle } from "./components/PageTitle";
39
43
  export { default as Pagination } from "./components/Pagination";
40
44
  export { default as PieChart } from "./components/PieChart";
41
45
  export { default as Popover } from "./components/Popover";
@@ -55,6 +59,7 @@ export { default as Stepper } from "./components/Stepper";
55
59
  export { default as Switch } from "./components/Switch";
56
60
  export { default as Table } from "./components/Table";
57
61
  export { default as Tabs } from "./components/Tabs";
62
+ export { default as TextLink } from "./components/TextLink";
58
63
  export { default as ThemeToggle } from "./components/ThemeToggle";
59
64
  export { default as Timeline } from "./components/Timeline";
60
65
  export { default as TimePicker } from "./components/TimePicker";
package/dist/styles.css CHANGED
@@ -77,3 +77,91 @@ body {
77
77
  scroll-behavior: auto !important;
78
78
  }
79
79
  }
80
+
81
+ /* Square scrollbars in both themes (WebKit/Blink); Firefox gets thin themed bars via scrollbar-color */
82
+ ::-webkit-scrollbar {
83
+ width: 12px;
84
+ height: 12px;
85
+ }
86
+
87
+ ::-webkit-scrollbar-track,
88
+ ::-webkit-scrollbar-corner {
89
+ background: rgb(var(--color-app-bg));
90
+ border-radius: 0;
91
+ }
92
+
93
+ ::-webkit-scrollbar-thumb {
94
+ background: rgb(var(--color-app-border));
95
+ border: 3px solid rgb(var(--color-app-bg));
96
+ border-radius: 0;
97
+ }
98
+
99
+ ::-webkit-scrollbar-thumb:hover {
100
+ background: rgb(var(--color-app-muted));
101
+ }
102
+
103
+ @supports not selector(::-webkit-scrollbar) {
104
+ * {
105
+ scrollbar-width: thin;
106
+ scrollbar-color: rgb(var(--color-app-border)) rgb(var(--color-app-bg));
107
+ }
108
+ }
109
+
110
+ /* Slider: square thumb, filled track. --xd-fill (set by <Slider>) is the filled percentage. */
111
+ .xd-slider {
112
+ -webkit-appearance: none;
113
+ appearance: none;
114
+ height: 18px;
115
+ margin: 0;
116
+ background: transparent;
117
+ cursor: pointer;
118
+ }
119
+
120
+ .xd-slider:disabled {
121
+ cursor: not-allowed;
122
+ opacity: 0.5;
123
+ }
124
+
125
+ .xd-slider::-webkit-slider-runnable-track {
126
+ height: 4px;
127
+ border-radius: 0;
128
+ background: linear-gradient(
129
+ to right,
130
+ rgb(var(--color-app-strong)) var(--xd-fill, 0%),
131
+ rgb(var(--color-app-border)) var(--xd-fill, 0%)
132
+ );
133
+ }
134
+
135
+ .xd-slider::-webkit-slider-thumb {
136
+ -webkit-appearance: none;
137
+ appearance: none;
138
+ width: 14px;
139
+ height: 14px;
140
+ margin-top: -5px;
141
+ border: 2px solid rgb(var(--color-app-bg));
142
+ border-radius: 0;
143
+ background: rgb(var(--color-app-strong));
144
+ box-shadow: 0 0 0 1px rgb(var(--color-app-strong));
145
+ }
146
+
147
+ .xd-slider::-moz-range-track {
148
+ height: 4px;
149
+ border-radius: 0;
150
+ background: rgb(var(--color-app-border));
151
+ }
152
+
153
+ .xd-slider::-moz-range-progress {
154
+ height: 4px;
155
+ border-radius: 0;
156
+ background: rgb(var(--color-app-strong));
157
+ }
158
+
159
+ .xd-slider::-moz-range-thumb {
160
+ box-sizing: border-box;
161
+ width: 14px;
162
+ height: 14px;
163
+ border: 2px solid rgb(var(--color-app-bg));
164
+ border-radius: 0;
165
+ background: rgb(var(--color-app-strong));
166
+ box-shadow: 0 0 0 1px rgb(var(--color-app-strong));
167
+ }
@@ -0,0 +1,14 @@
1
+ export function parsePlacement(placement?: string): {
2
+ side: string;
3
+ align: string;
4
+ };
5
+ export function computePosition(anchor: any, panel: any, { placement, gap, viewport }?: {
6
+ placement?: string;
7
+ gap?: number;
8
+ }): {
9
+ top: number;
10
+ left: number;
11
+ side: string;
12
+ align: string;
13
+ };
14
+ export function isClipped(element: any): boolean;