@judarn/ui 0.0.0-stage → 0.7.1
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/LICENSE +21 -0
- package/README.md +47 -2
- package/dist/Badge/Badge.d.ts +26 -0
- package/dist/Button/Button.d.ts +19 -0
- package/dist/Card/Card.d.ts +22 -0
- package/dist/DataMatrix/DataMatrix.d.ts +26 -0
- package/dist/DataTable/DataTable.d.ts +21 -0
- package/dist/Footer/Footer.d.ts +21 -0
- package/dist/LogoLockup/LogoLockup.d.ts +20 -0
- package/dist/Navbar/Navbar.d.ts +21 -0
- package/dist/TextField/TextField.d.ts +31 -0
- package/dist/index.cjs +676 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.mjs +650 -0
- package/dist/sdui/index.cjs +572 -0
- package/dist/sdui/index.d.ts +1 -0
- package/dist/sdui/index.mjs +540 -0
- package/dist/sdui/schema.json +729 -0
- package/dist/sdui/serializer.d.ts +54 -0
- package/package.json +82 -4
- package/src/tailwind.d.ts +11 -0
- package/src/tailwind.js +61 -0
- package/styles/colors_and_type.css +543 -0
- package/styles/components.css +243 -0
- package/styles/styles.css +52 -0
- package/styles/tailwind-theme.css +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ruben Luthman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,48 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @judarn/ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React components and CSS tokens for the Judarn design system, with colors in OKLCh and a fixed 8 px spacing grid.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install --save-exact @judarn/ui
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```jsx
|
|
10
|
+
import "@judarn/ui/styles";
|
|
11
|
+
import { Button, Card } from "@judarn/ui";
|
|
12
|
+
|
|
13
|
+
export function Status() {
|
|
14
|
+
return (
|
|
15
|
+
<Card eyebrow="System status" title="Operational">
|
|
16
|
+
<Button variant="primary">View metrics</Button>
|
|
17
|
+
</Card>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`react` 18 or later is the only peer dependency. The package ships compiled ESM and CommonJS. Other entry points: `@judarn/ui/colors` (CSS custom properties only), `@judarn/ui/theme` and `@judarn/ui/tailwind` (Tailwind v4), and `@judarn/ui/sdui` (server-driven UI).
|
|
23
|
+
|
|
24
|
+
## Accent colors
|
|
25
|
+
|
|
26
|
+
A project that sets its own `--jd-accent` also sets `--jd-accent-ink` to `#000000` or `#ffffff`, whichever stays readable on that fill. Accent buttons and badges read the resolved `--accent-ink`. The `--jd-accent*` hooks have no default, so a value set on `:root` carries into nested scopes.
|
|
27
|
+
|
|
28
|
+
## Guarantees and the checks behind them
|
|
29
|
+
|
|
30
|
+
| Guarantee | Check |
|
|
31
|
+
| :--- | :--- |
|
|
32
|
+
| `ink100` meets 7:1 on every surface and appearance; `ink60` and `signalError` meet 4.5:1, and 7:1 in high-contrast appearances | `scripts/verify-contrast.js` (run by `npm test`) |
|
|
33
|
+
| Components render the markup their contracts describe | `scripts/verify-unit.js` |
|
|
34
|
+
| A page with `data-theme="dark"` gets the dark accent ink | `scripts/verify-visual.js` |
|
|
35
|
+
| Server-driven payloads accept only allowlisted props and reject `style`, `className`, and `dangerouslySetInnerHTML` | `scripts/verify-sdui.js` |
|
|
36
|
+
|
|
37
|
+
White ink on mid-tone fills can fall below 4.5:1 by design, and paragraph line spacing does not meet WCAG SC 1.4.8. The repository README explains both.
|
|
38
|
+
|
|
39
|
+
## Development
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm ci
|
|
43
|
+
npm test
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## License
|
|
47
|
+
|
|
48
|
+
MIT © 2026 Ruben Luthman. The package includes the LICENSE file.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
4
|
+
children?: React.ReactNode;
|
|
5
|
+
/** @default "outline" */
|
|
6
|
+
variant?: "outline" | "solid" | "accent" | "accent-outline";
|
|
7
|
+
/** Optional custom accent color hex or rgb string. Automatically resolves accessible contrasting text ink. */
|
|
8
|
+
accentColor?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface TagProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the foreground ink ("#000000" or "#ffffff") for a fill from its relative luminance and the 0.50 perceptual crossover (ADR-0006).
|
|
17
|
+
* Accepts #hex, rgb() and oklch(); throws a TypeError for any other format.
|
|
18
|
+
*/
|
|
19
|
+
export function getContrastingInk(hexOrRgb: string): string;
|
|
20
|
+
|
|
21
|
+
/** Status chip set as written, with optional luminance-aware contrasting ink. */
|
|
22
|
+
export function Badge(props: BadgeProps): React.JSX.Element;
|
|
23
|
+
/** Sentence-case keyword chip. */
|
|
24
|
+
export function Tag(props: TagProps): React.JSX.Element;
|
|
25
|
+
export default Badge;
|
|
26
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
|
|
4
|
+
children?: React.ReactNode;
|
|
5
|
+
/** Visual style. @default "primary" */
|
|
6
|
+
variant?: "primary" | "outline" | "secondary" | "ghost" | "accent";
|
|
7
|
+
/** @default "md" */
|
|
8
|
+
size?: "sm" | "md" | "lg";
|
|
9
|
+
/** Stretch to full container width. @default false */
|
|
10
|
+
block?: boolean;
|
|
11
|
+
/** @default false */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
type?: "button" | "submit" | "reset";
|
|
14
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Judarn button – flat fill, border, and hover inversion. A consumer `className` extends the base classes. */
|
|
18
|
+
export function Button(props: ButtonProps): React.JSX.Element;
|
|
19
|
+
export default Button;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
4
|
+
/** Small accent label, set as a `t-label` (uppercase unless `eyebrowCasing` is "asWritten"). */
|
|
5
|
+
eyebrow?: string;
|
|
6
|
+
/** "asWritten" for an eyebrow holding a unit, a digit, or a mixed-case term (ADR-0009). @default "uppercase" */
|
|
7
|
+
eyebrowCasing?: "uppercase" | "asWritten";
|
|
8
|
+
title?: React.ReactNode;
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
/** Media block (image/figure) rendered at top. */
|
|
11
|
+
media?: React.ReactNode;
|
|
12
|
+
/** Action row (buttons) rendered at bottom. */
|
|
13
|
+
actions?: React.ReactNode;
|
|
14
|
+
/** Remove elevation + padding. @default false */
|
|
15
|
+
flat?: boolean;
|
|
16
|
+
/** Apply compact padding (space2 / 16px) for sidebars and dense panes. @default false */
|
|
17
|
+
compact?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Content card block with substrate background contrast (surfaceElevated) and the host card radius. */
|
|
21
|
+
export function Card(props: CardProps): React.JSX.Element;
|
|
22
|
+
export default Card;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface MatrixColumn {
|
|
4
|
+
key: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Right-align with tabular figures. @default false */
|
|
7
|
+
numeric?: boolean;
|
|
8
|
+
/** Fixed width in pixels (number) or CSS length (string). */
|
|
9
|
+
width?: number | string;
|
|
10
|
+
/** "asWritten" for a header holding a unit symbol or mixed-case term, such as kg or e1RM (ADR-0009). @default "uppercase" */
|
|
11
|
+
casing?: "uppercase" | "asWritten";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DataMatrixProps extends React.TableHTMLAttributes<HTMLTableElement> {
|
|
15
|
+
/** Column keys (strings) or {key,label,numeric,width} objects. */
|
|
16
|
+
columns?: Array<string | MatrixColumn>;
|
|
17
|
+
/** Row objects keyed by column key. */
|
|
18
|
+
rows?: Array<Record<string, React.ReactNode>>;
|
|
19
|
+
/** Spoken table label for assistive tech. @default "Data Matrix" */
|
|
20
|
+
label?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Data Matrix with 1px hairline rules between cells and no perimeter border, tabular figures, and accessible landmarks. */
|
|
24
|
+
export function DataMatrix(props: DataMatrixProps): React.JSX.Element;
|
|
25
|
+
export default DataMatrix;
|
|
26
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface DataColumn {
|
|
4
|
+
key: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Right-align with tabular figures. @default false */
|
|
7
|
+
numeric?: boolean;
|
|
8
|
+
/** "asWritten" for a header holding a unit symbol or mixed-case term, such as kg or e1RM (ADR-0009). @default "uppercase" */
|
|
9
|
+
casing?: "uppercase" | "asWritten";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DataTableProps extends React.TableHTMLAttributes<HTMLTableElement> {
|
|
13
|
+
/** Column keys (strings) or {key,label,numeric} objects. */
|
|
14
|
+
columns?: Array<string | DataColumn>;
|
|
15
|
+
/** Row objects keyed by column key. */
|
|
16
|
+
rows?: Array<Record<string, React.ReactNode>>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Bordered data table – uppercase headers unless a column sets casing "asWritten", hairline row rules. */
|
|
20
|
+
export function DataTable(props: DataTableProps): React.JSX.Element;
|
|
21
|
+
export default DataTable;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface FooterColumn {
|
|
4
|
+
head: string;
|
|
5
|
+
links?: Array<string | { label: string; href?: string }>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface FooterProps extends React.HTMLAttributes<HTMLElement> {
|
|
9
|
+
/** Brand wordmark. @default "JUDARN" */
|
|
10
|
+
brand?: string;
|
|
11
|
+
/** Short line under the brand. */
|
|
12
|
+
tagline?: string;
|
|
13
|
+
/** Link columns. */
|
|
14
|
+
columns?: FooterColumn[];
|
|
15
|
+
/** "asWritten" for column heads holding mixed-case terms (ADR-0009). Heads render as `h2`. @default "uppercase" */
|
|
16
|
+
headCasing?: "uppercase" | "asWritten";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Three-column footer with 2px top rule. */
|
|
20
|
+
export function Footer(props: FooterProps): React.JSX.Element;
|
|
21
|
+
export default Footer;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface LogoLockupProps {
|
|
4
|
+
/** Wordmark text (heavy sans). @default "JUDARN" */
|
|
5
|
+
name?: string;
|
|
6
|
+
/** Optional descriptor under/after the name. */
|
|
7
|
+
tagline?: string;
|
|
8
|
+
/** Your geometric mark (SVG element). Omit for a construction placeholder. */
|
|
9
|
+
mark?: React.ReactNode;
|
|
10
|
+
/** Lockup arrangement. @default "horizontal" */
|
|
11
|
+
variant?: "horizontal" | "vertical" | "icon" | "reversed";
|
|
12
|
+
/** Pixel size of the placeholder mark. */
|
|
13
|
+
markSize?: number;
|
|
14
|
+
/** "asWritten" keeps the tagline as written (ADR-0009). @default "uppercase" */
|
|
15
|
+
taglineCasing?: "uppercase" | "asWritten";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Logo frame – geometric mark + wordmark, four variants. */
|
|
19
|
+
export function LogoLockup(props: LogoLockupProps): React.JSX.Element;
|
|
20
|
+
export default LogoLockup;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface NavLink {
|
|
4
|
+
label: string;
|
|
5
|
+
href?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface NavbarProps extends React.HTMLAttributes<HTMLElement> {
|
|
9
|
+
/** Brand wordmark text. @default "JUDARN" */
|
|
10
|
+
brand?: string;
|
|
11
|
+
/** Link labels or {label, href} objects. */
|
|
12
|
+
links?: Array<string | NavLink>;
|
|
13
|
+
/** Label of the active link (gets accent underline). */
|
|
14
|
+
current?: string;
|
|
15
|
+
/** Right-aligned actions (e.g. a Button). */
|
|
16
|
+
actions?: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Top navigation bar – 2px baseline rule, links set as written. */
|
|
20
|
+
export function Navbar(props: NavbarProps): React.JSX.Element;
|
|
21
|
+
export default Navbar;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
type FieldControlProps = Omit<
|
|
4
|
+
React.InputHTMLAttributes<HTMLInputElement> &
|
|
5
|
+
React.TextareaHTMLAttributes<HTMLTextAreaElement> &
|
|
6
|
+
React.SelectHTMLAttributes<HTMLSelectElement>,
|
|
7
|
+
"id"
|
|
8
|
+
>;
|
|
9
|
+
|
|
10
|
+
export interface TextFieldProps extends FieldControlProps {
|
|
11
|
+
/** Label above the control, uppercase unless labelCasing is "asWritten". */
|
|
12
|
+
label?: string;
|
|
13
|
+
/** "asWritten" for a label longer than two words or holding a digit, unit, or mixed-case term (ADR-0009). @default "uppercase" */
|
|
14
|
+
labelCasing?: "uppercase" | "asWritten";
|
|
15
|
+
/** Helper text below the control, linked with `aria-describedby`. */
|
|
16
|
+
hint?: string;
|
|
17
|
+
/** Error message below the control, linked with `aria-describedby`. Also marks the control invalid. */
|
|
18
|
+
error?: string;
|
|
19
|
+
/** Render an input, textarea, or select. @default "input" */
|
|
20
|
+
as?: "input" | "textarea" | "select";
|
|
21
|
+
/** Overrides the generated `React.useId()` id. */
|
|
22
|
+
id?: string;
|
|
23
|
+
/** Marks the control invalid (`aria-invalid`, signal-error border). @default false */
|
|
24
|
+
invalid?: boolean;
|
|
25
|
+
/** @default false */
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Labelled field – input / textarea / select with Judarn styling. */
|
|
30
|
+
export function TextField(props: TextFieldProps): React.JSX.Element;
|
|
31
|
+
export default TextField;
|