@lepid-labs/ui-react 1.0.0 → 1.0.2
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/AppHeader.d.ts +36 -0
- package/dist/AppHeader.js +32 -0
- package/dist/AppShell.d.ts +41 -0
- package/dist/AppShell.js +64 -0
- package/dist/ButtonGroup.d.ts +13 -0
- package/dist/ButtonGroup.js +14 -0
- package/dist/CodeBlock.d.ts +11 -0
- package/dist/CodeBlock.js +30 -0
- package/dist/HoldButton.d.ts +23 -0
- package/dist/HoldButton.js +112 -0
- package/dist/IconButton.d.ts +18 -0
- package/dist/IconButton.js +9 -0
- package/dist/LogBlock.d.ts +22 -0
- package/dist/LogBlock.js +30 -0
- package/dist/Page.d.ts +51 -0
- package/dist/Page.js +30 -0
- package/dist/SideNav.d.ts +27 -0
- package/dist/SideNav.js +21 -0
- package/dist/StatusCard.d.ts +42 -0
- package/dist/StatusCard.js +35 -0
- package/dist/Stepper.d.ts +19 -0
- package/dist/Stepper.js +12 -0
- package/dist/Table.d.ts +17 -0
- package/dist/Table.js +29 -0
- package/dist/Tabs.js +4 -1
- package/dist/button-group.d.ts +7 -0
- package/dist/button-group.js +11 -0
- package/dist/copy-state.d.ts +14 -0
- package/dist/copy-state.js +31 -0
- package/dist/feedback.d.ts +5 -1
- package/dist/feedback.js +2 -2
- package/dist/hold.d.ts +31 -0
- package/dist/hold.js +82 -0
- package/dist/icon-button.d.ts +23 -0
- package/dist/icon-button.js +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +23 -0
- package/dist/log-state.d.ts +20 -0
- package/dist/log-state.js +21 -0
- package/dist/poly.d.ts +6 -0
- package/dist/poly.js +1 -0
- package/dist/shell-state.d.ts +22 -0
- package/dist/shell-state.js +25 -0
- package/dist/slide-dir.d.ts +5 -0
- package/dist/slide-dir.js +12 -0
- package/dist/status-card.d.ts +15 -0
- package/dist/status-card.js +27 -0
- package/dist/stepper-state.d.ts +12 -0
- package/dist/stepper-state.js +24 -0
- package/dist/table-state.d.ts +28 -0
- package/dist/table-state.js +29 -0
- package/dist/useSlideDir.d.ts +7 -0
- package/dist/useSlideDir.js +26 -0
- package/package.json +3 -2
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type StatusTone = "info" | "success" | "warning" | "danger";
|
|
2
|
+
/** `true` means "warning" — the default call-to-action ring. */
|
|
3
|
+
export declare function attentionTone(attention: boolean | StatusTone | undefined): StatusTone | undefined;
|
|
4
|
+
export interface StatusCardAttrs {
|
|
5
|
+
className: string;
|
|
6
|
+
"data-ld-attention"?: StatusTone;
|
|
7
|
+
}
|
|
8
|
+
/** Root class list and data attributes for a given tone/attention state. */
|
|
9
|
+
export declare function statusCardAttrs(tone: StatusTone | undefined, attention: boolean | StatusTone | undefined, className?: string): StatusCardAttrs;
|
|
10
|
+
/** Restart the change flash on `el`: drop the attribute, reflow, set it again. */
|
|
11
|
+
export declare function replayFlash(el: {
|
|
12
|
+
removeAttribute(name: string): void;
|
|
13
|
+
setAttribute(name: string, value: string): void;
|
|
14
|
+
readonly offsetWidth: number;
|
|
15
|
+
}): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Pure attribute logic behind StatusCard, kept DOM-free so it can be tested
|
|
2
|
+
// under node:test without a renderer (so it imports nothing — Node runs the
|
|
3
|
+
// .ts source and cannot resolve the .js specifiers the build uses).
|
|
4
|
+
/** `true` means "warning" — the default call-to-action ring. */
|
|
5
|
+
export function attentionTone(attention) {
|
|
6
|
+
if (attention === true)
|
|
7
|
+
return "warning";
|
|
8
|
+
if (!attention)
|
|
9
|
+
return undefined;
|
|
10
|
+
return attention;
|
|
11
|
+
}
|
|
12
|
+
/** Root class list and data attributes for a given tone/attention state. */
|
|
13
|
+
export function statusCardAttrs(tone, attention, className) {
|
|
14
|
+
const attrs = {
|
|
15
|
+
className: ["ld-status-card", tone && `ld-status-card--${tone}`, className].filter(Boolean).join(" "),
|
|
16
|
+
};
|
|
17
|
+
const ring = attentionTone(attention);
|
|
18
|
+
if (ring)
|
|
19
|
+
attrs["data-ld-attention"] = ring;
|
|
20
|
+
return attrs;
|
|
21
|
+
}
|
|
22
|
+
/** Restart the change flash on `el`: drop the attribute, reflow, set it again. */
|
|
23
|
+
export function replayFlash(el) {
|
|
24
|
+
el.removeAttribute("data-ld-changed");
|
|
25
|
+
void el.offsetWidth;
|
|
26
|
+
el.setAttribute("data-ld-changed", "");
|
|
27
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type StepState = "complete" | "current" | "upcoming";
|
|
2
|
+
/** Where step `index` sits relative to `current`: before it is complete, at it
|
|
3
|
+
* is current, after it is upcoming. A `current` past the last step therefore
|
|
4
|
+
* reads as "all complete"; a negative one as "all upcoming". */
|
|
5
|
+
export declare function stepState(index: number, current: number): StepState;
|
|
6
|
+
export interface StepAttrs {
|
|
7
|
+
className: string;
|
|
8
|
+
"aria-current"?: "step";
|
|
9
|
+
}
|
|
10
|
+
/** Class list and aria attributes for step `index`. The theme CSS derives
|
|
11
|
+
* the rail fill from the state modifiers, so nothing else is written. */
|
|
12
|
+
export declare function stepAttrs(index: number, current: number, className?: string): StepAttrs;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Pure state logic behind Stepper, kept DOM-free so it can be tested under
|
|
2
|
+
// node:test without a renderer (so it imports nothing — Node runs the .ts
|
|
3
|
+
// source and cannot resolve the .js specifiers the build uses).
|
|
4
|
+
/** Where step `index` sits relative to `current`: before it is complete, at it
|
|
5
|
+
* is current, after it is upcoming. A `current` past the last step therefore
|
|
6
|
+
* reads as "all complete"; a negative one as "all upcoming". */
|
|
7
|
+
export function stepState(index, current) {
|
|
8
|
+
if (index < current)
|
|
9
|
+
return "complete";
|
|
10
|
+
if (index === current)
|
|
11
|
+
return "current";
|
|
12
|
+
return "upcoming";
|
|
13
|
+
}
|
|
14
|
+
/** Class list and aria attributes for step `index`. The theme CSS derives
|
|
15
|
+
* the rail fill from the state modifiers, so nothing else is written. */
|
|
16
|
+
export function stepAttrs(index, current, className) {
|
|
17
|
+
const state = stepState(index, current);
|
|
18
|
+
const attrs = {
|
|
19
|
+
className: ["ld-stepper__step", `ld-stepper__step--${state}`, className].filter(Boolean).join(" "),
|
|
20
|
+
};
|
|
21
|
+
if (state === "current")
|
|
22
|
+
attrs["aria-current"] = "step";
|
|
23
|
+
return attrs;
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Descendants that own their own click/keys; a row never double-fires for them. */
|
|
2
|
+
export declare const ROW_NESTED_CONTROLS = "a[href], button, input, select, textarea, summary, label, [role=\"button\"], [role=\"link\"], [contenteditable=\"true\"]";
|
|
3
|
+
export interface TableOptions {
|
|
4
|
+
/** Rows are clickable: pointer cursor, focus ring, selected state. */
|
|
5
|
+
interactive?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Class list for the `<table>`. */
|
|
9
|
+
export declare function tableAttrs({ interactive, className }: TableOptions): {
|
|
10
|
+
className: string;
|
|
11
|
+
};
|
|
12
|
+
export interface TableRowOptions {
|
|
13
|
+
/** The row has an activation handler, so it joins the tab order. */
|
|
14
|
+
activatable?: boolean;
|
|
15
|
+
/** Selected state; omitted leaves aria-selected off entirely. */
|
|
16
|
+
selected?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface TableRowAttrs {
|
|
19
|
+
tabIndex?: 0;
|
|
20
|
+
"aria-selected"?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Focus and selection ARIA for a body row. */
|
|
23
|
+
export declare function tableRowAttrs({ activatable, selected }: TableRowOptions): TableRowAttrs;
|
|
24
|
+
/** Enter or Space on the focused row itself (not a control inside it) activates it. */
|
|
25
|
+
export declare function isRowActivationKey(key: string, fromRow: boolean): boolean;
|
|
26
|
+
/** A click activates the row unless it landed on a nested control (`hit` is the
|
|
27
|
+
* closest ROW_NESTED_CONTROLS match inside the row) or finished a text selection. */
|
|
28
|
+
export declare function isRowActivationClick(hitNestedControl: boolean, selectedText: string): boolean;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Pure attribute and activation logic behind Table / TableRow, kept DOM-free
|
|
2
|
+
// so it can be tested under node:test without a renderer (so it imports
|
|
3
|
+
// nothing — Node runs the .ts source and cannot resolve .js specifiers).
|
|
4
|
+
/** Descendants that own their own click/keys; a row never double-fires for them. */
|
|
5
|
+
export const ROW_NESTED_CONTROLS = 'a[href], button, input, select, textarea, summary, label, [role="button"], [role="link"], [contenteditable="true"]';
|
|
6
|
+
/** Class list for the `<table>`. */
|
|
7
|
+
export function tableAttrs({ interactive, className }) {
|
|
8
|
+
return {
|
|
9
|
+
className: ["ld-table", interactive && "ld-table--interactive", className].filter(Boolean).join(" "),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** Focus and selection ARIA for a body row. */
|
|
13
|
+
export function tableRowAttrs({ activatable, selected }) {
|
|
14
|
+
const attrs = {};
|
|
15
|
+
if (activatable)
|
|
16
|
+
attrs.tabIndex = 0;
|
|
17
|
+
if (selected !== undefined)
|
|
18
|
+
attrs["aria-selected"] = selected;
|
|
19
|
+
return attrs;
|
|
20
|
+
}
|
|
21
|
+
/** Enter or Space on the focused row itself (not a control inside it) activates it. */
|
|
22
|
+
export function isRowActivationKey(key, fromRow) {
|
|
23
|
+
return fromRow && (key === "Enter" || key === " ");
|
|
24
|
+
}
|
|
25
|
+
/** A click activates the row unless it landed on a nested control (`hit` is the
|
|
26
|
+
* closest ROW_NESTED_CONTROLS match inside the row) or finished a text selection. */
|
|
27
|
+
export function isRowActivationClick(hitNestedControl, selectedText) {
|
|
28
|
+
return !hitNestedControl && selectedText === "";
|
|
29
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RefObject } from "react";
|
|
2
|
+
/** Ref for an indicator track (`.ld-tabs`, `.ld-btn-group`). After every render
|
|
3
|
+
* it finds the child matching `activeSelector` and, when that moved, stamps
|
|
4
|
+
* `data-ld-dir="forward" | "back"` on the track — the theme reads it to pick
|
|
5
|
+
* which edge of the sliding indicator leads. Read from the DOM, so it works
|
|
6
|
+
* when the active state lives in the children (`aria-pressed` on `Button`s). */
|
|
7
|
+
export declare function useSlideDir<T extends HTMLElement>(activeSelector: string): RefObject<T | null>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect, useRef } from "react";
|
|
2
|
+
import { slideDir } from "./slide-dir.js";
|
|
3
|
+
// Layout effect on the client so data-ld-dir lands in the same frame as the
|
|
4
|
+
// selection change (a transition reads its timing when it starts); plain
|
|
5
|
+
// effect on the server, where React 18 warns about layout effects.
|
|
6
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
7
|
+
/** Ref for an indicator track (`.ld-tabs`, `.ld-btn-group`). After every render
|
|
8
|
+
* it finds the child matching `activeSelector` and, when that moved, stamps
|
|
9
|
+
* `data-ld-dir="forward" | "back"` on the track — the theme reads it to pick
|
|
10
|
+
* which edge of the sliding indicator leads. Read from the DOM, so it works
|
|
11
|
+
* when the active state lives in the children (`aria-pressed` on `Button`s). */
|
|
12
|
+
export function useSlideDir(activeSelector) {
|
|
13
|
+
const ref = useRef(null);
|
|
14
|
+
const prev = useRef(-1);
|
|
15
|
+
useIsomorphicLayoutEffect(() => {
|
|
16
|
+
const el = ref.current;
|
|
17
|
+
if (!el)
|
|
18
|
+
return;
|
|
19
|
+
const next = Array.from(el.children).findIndex((c) => c.matches(activeSelector));
|
|
20
|
+
const dir = slideDir(prev.current, next);
|
|
21
|
+
if (dir)
|
|
22
|
+
el.dataset.ldDir = dir;
|
|
23
|
+
prev.current = next;
|
|
24
|
+
});
|
|
25
|
+
return ref;
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lepid-labs/ui-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Shared React components styled by @lepid-labs/styles themes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsc -p tsconfig.json",
|
|
26
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
26
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
27
|
+
"test": "node --test"
|
|
27
28
|
},
|
|
28
29
|
"peerDependencies": {
|
|
29
30
|
"react": ">=18"
|