@lo-ink/ui 0.2.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"AppIcon.d.ts","sourceRoot":"","sources":["../src/AppIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG1E,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,eAAe,CAAC;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;CACvE;AAED,wBAAgB,OAAO,CAAC,EACtB,GAAG,EACH,GAAQ,EACR,IAAe,EACf,QAAQ,EACR,UAAU,EACV,SAAS,EACT,GAAG,KAAK,EACT,EAAE,YAAY,+BAad"}
1
+ {"version":3,"file":"AppIcon.d.ts","sourceRoot":"","sources":["../src/AppIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG1E,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,eAAe,CAAC;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;CACvE;AAED,wBAAgB,OAAO,CAAC,EACtB,GAAG,EACH,GAAQ,EACR,IAAe,EACf,QAAQ,EACR,UAAU,EACV,SAAS,EACT,GAAG,KAAK,EACT,EAAE,YAAY,+BAcd"}
package/dist/AppIcon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { classes } from "./utils.js";
3
3
  export function AppIcon({ src, alt = "", size = "medium", children, imageProps, className, ...props }) {
4
- return (_jsx("span", { ...props, className: classes("lo-ui-app-icon", `lo-ui-app-icon--${size}`, className), children: src ? _jsx("img", { ...imageProps, src: src, alt: alt }) : children }));
4
+ return (_jsx("span", { ...props, role: props.role ?? (!src && props["aria-label"] ? "img" : undefined), className: classes("lo-ui-app-icon", `lo-ui-app-icon--${size}`, className), children: src ? _jsx("img", { ...imageProps, src: src, alt: alt }) : children }));
5
5
  }
@@ -0,0 +1,4 @@
1
+ import { type DialogHTMLAttributes } from "react";
2
+ /** Native modal semantics; the caller controls showModal(), close() and cancellation. */
3
+ export declare const Dialog: import("react").ForwardRefExoticComponent<DialogHTMLAttributes<HTMLDialogElement> & import("react").RefAttributes<HTMLDialogElement>>;
4
+ //# sourceMappingURL=Dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../src/Dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAG9D,yFAAyF;AACzF,eAAO,MAAM,MAAM,uIAWjB,CAAC"}
package/dist/Dialog.js ADDED
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { classes } from "./utils.js";
4
+ /** Native modal semantics; the caller controls showModal(), close() and cancellation. */
5
+ export const Dialog = forwardRef(function Dialog({ className, ...props }, ref) {
6
+ return (_jsx("dialog", { ...props, ref: ref, className: classes("lo-ui-dialog", className) }));
7
+ });
@@ -0,0 +1,3 @@
1
+ import type { ProgressHTMLAttributes } from "react";
2
+ export declare function Progress({ className, ...props }: ProgressHTMLAttributes<HTMLProgressElement>): import("react").JSX.Element;
3
+ //# sourceMappingURL=Progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Progress.d.ts","sourceRoot":"","sources":["../src/Progress.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAC;AAGpD,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,sBAAsB,CAAC,mBAAmB,CAAC,+BAI7C"}
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { classes } from "./utils.js";
3
+ export function Progress({ className, ...props }) {
4
+ return (_jsx("progress", { ...props, className: classes("lo-ui-progress", className) }));
5
+ }
@@ -0,0 +1,7 @@
1
+ import type { HTMLAttributes } from "react";
2
+ import type { SpacingToken } from "@lo-ink/design-tokens";
3
+ export interface SurfaceProps extends HTMLAttributes<HTMLElement> {
4
+ padding?: SpacingToken;
5
+ }
6
+ export declare function Surface({ padding, className, style, ...props }: SurfaceProps): import("react").JSX.Element;
7
+ //# sourceMappingURL=Surface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Surface.d.ts","sourceRoot":"","sources":["../src/Surface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAG1D,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC/D,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AACD,wBAAgB,OAAO,CAAC,EACtB,OAAW,EACX,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,YAAY,+BAad"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { classes } from "./utils.js";
3
+ export function Surface({ padding = 4, className, style, ...props }) {
4
+ return (_jsx("section", { ...props, className: classes("lo-ui-surface", className), style: {
5
+ "--lo-surface-padding": `var(--lo-space-${padding})`,
6
+ ...style,
7
+ } }));
8
+ }
@@ -0,0 +1,8 @@
1
+ import { type ReactNode, type TextareaHTMLAttributes } from "react";
2
+ export interface TextAreaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
3
+ label: ReactNode;
4
+ description?: ReactNode;
5
+ error?: ReactNode;
6
+ }
7
+ export declare const TextArea: import("react").ForwardRefExoticComponent<TextAreaProps & import("react").RefAttributes<HTMLTextAreaElement>>;
8
+ //# sourceMappingURL=TextArea.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextArea.d.ts","sourceRoot":"","sources":["../src/TextArea.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC5B,MAAM,OAAO,CAAC;AAGf,MAAM,WAAW,aAAc,SAAQ,sBAAsB,CAAC,mBAAmB,CAAC;IAChF,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AACD,eAAO,MAAM,QAAQ,+GA8CpB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useId, } from "react";
3
+ import { classes } from "./utils.js";
4
+ export const TextArea = forwardRef(function TextArea({ label, description, error, id: providedId, className, "aria-describedby": describedBy, ...props }, ref) {
5
+ const generatedId = useId();
6
+ const id = providedId ?? generatedId;
7
+ const descriptionId = description ? `${id}-description` : undefined;
8
+ const errorId = error ? `${id}-error` : undefined;
9
+ return (_jsxs("div", { className: classes("lo-ui-field", className), children: [_jsx("label", { className: "lo-ui-field__label", htmlFor: id, children: label }), _jsx("textarea", { ...props, ref: ref, id: id, "aria-invalid": error ? true : props["aria-invalid"], "aria-describedby": [describedBy, descriptionId, errorId].filter(Boolean).join(" ") ||
10
+ undefined, className: "lo-ui-field__input lo-ui-textarea" }), description && (_jsx("div", { className: "lo-ui-field__description", id: descriptionId, children: description })), error && (_jsx("div", { className: "lo-ui-field__error", id: errorId, children: error }))] }));
11
+ });
@@ -4,6 +4,7 @@ export interface TextFieldProps extends Omit<InputHTMLAttributes<HTMLInputElemen
4
4
  description?: ReactNode;
5
5
  error?: ReactNode;
6
6
  inputClassName?: string;
7
+ labelHidden?: boolean;
7
8
  }
8
9
  export declare const TextField: import("react").ForwardRefExoticComponent<TextFieldProps & import("react").RefAttributes<HTMLInputElement>>;
9
10
  //# sourceMappingURL=TextField.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextField.d.ts","sourceRoot":"","sources":["../src/TextField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,CACP;IACC,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,SAAS,6GAgDrB,CAAC"}
1
+ {"version":3,"file":"TextField.d.ts","sourceRoot":"","sources":["../src/TextField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,CACP;IACC,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,SAAS,6GAuDrB,CAAC"}
package/dist/TextField.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef, useId, } from "react";
3
3
  import { classes } from "./utils.js";
4
- export const TextField = forwardRef(function TextField({ label, description, error, id: providedId, className, inputClassName, "aria-describedby": ariaDescribedBy, ...props }, ref) {
4
+ export const TextField = forwardRef(function TextField({ label, description, error, id: providedId, className, inputClassName, labelHidden = false, "aria-describedby": ariaDescribedBy, ...props }, ref) {
5
5
  const generatedId = useId();
6
6
  const id = providedId ?? generatedId;
7
7
  const descriptionId = description ? `${id}-description` : undefined;
@@ -9,5 +9,5 @@ export const TextField = forwardRef(function TextField({ label, description, err
9
9
  const describedBy = [ariaDescribedBy, descriptionId, errorId]
10
10
  .filter(Boolean)
11
11
  .join(" ");
12
- return (_jsxs("div", { className: classes("lo-ui-field", className), children: [_jsx("label", { className: "lo-ui-field__label", htmlFor: id, children: label }), _jsx("input", { ...props, ref: ref, id: id, "aria-invalid": error ? true : props["aria-invalid"], "aria-describedby": describedBy || undefined, className: classes("lo-ui-field__input", inputClassName) }), description && (_jsx("div", { className: "lo-ui-field__description", id: descriptionId, children: description })), error && (_jsx("div", { className: "lo-ui-field__error", id: errorId, children: error }))] }));
12
+ return (_jsxs("div", { className: classes("lo-ui-field", labelHidden && "lo-ui-field--label-hidden", className), children: [_jsx("label", { className: "lo-ui-field__label", htmlFor: id, children: label }), _jsx("input", { ...props, ref: ref, id: id, "aria-invalid": error ? true : props["aria-invalid"], "aria-describedby": describedBy || undefined, className: classes("lo-ui-field__input", inputClassName) }), description && (_jsx("div", { className: "lo-ui-field__description", id: descriptionId, children: description })), error && (_jsx("div", { className: "lo-ui-field__error", id: errorId, children: error }))] }));
13
13
  });
@@ -1,11 +1,14 @@
1
- import type { HTMLAttributes } from "react";
2
- export interface TextProps extends HTMLAttributes<HTMLParagraphElement> {
3
- tone?: "primary" | "secondary" | "danger";
4
- size?: "caption" | "label" | "body";
1
+ import { type HTMLAttributes } from "react";
2
+ export interface TextProps extends HTMLAttributes<HTMLElement> {
3
+ as?: "p" | "span" | "strong" | "code" | "pre";
4
+ tone?: "primary" | "secondary" | "danger" | "success";
5
+ weight?: "regular" | "medium" | "bold";
6
+ family?: "ui" | "display" | "mono";
7
+ size?: "caption" | "label" | "body" | "title" | "display";
5
8
  }
6
- export declare function Text({ tone, size, className, ...props }: TextProps): import("react").JSX.Element;
9
+ export declare function Text({ as: Tag, tone, weight, family, size, className, ...props }: TextProps): import("react").JSX.Element;
7
10
  export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
8
11
  level?: 1 | 2 | 3 | 4 | 5 | 6;
9
12
  }
10
- export declare function Heading({ level, className, ...props }: HeadingProps): import("react").JSX.Element;
13
+ export declare const Heading: import("react").ForwardRefExoticComponent<HeadingProps & import("react").RefAttributes<HTMLHeadingElement>>;
11
14
  //# sourceMappingURL=Typography.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Typography.d.ts","sourceRoot":"","sources":["../src/Typography.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,WAAW,SAAU,SAAQ,cAAc,CAAC,oBAAoB,CAAC;IACrE,IAAI,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC1C,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;CACrC;AAED,wBAAgB,IAAI,CAAC,EACnB,IAAgB,EAChB,IAAa,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE,SAAS,+BAYX;AAED,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,kBAAkB,CAAC;IACtE,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC/B;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAS,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,+BAGvE"}
1
+ {"version":3,"file":"Typography.d.ts","sourceRoot":"","sources":["../src/Typography.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAGxD,MAAM,WAAW,SAAU,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC5D,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;IAC9C,IAAI,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtD,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IACvC,MAAM,CAAC,EAAE,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC;IACnC,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CAC3D;AAED,wBAAgB,IAAI,CAAC,EACnB,EAAE,EAAE,GAAS,EACb,IAAgB,EAChB,MAAM,EACN,MAAM,EACN,IAAa,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE,SAAS,+BAcX;AAED,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,kBAAkB,CAAC;IACtE,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC/B;AAED,eAAO,MAAM,OAAO,6GAWnB,CAAC"}
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
2
3
  import { classes } from "./utils.js";
3
- export function Text({ tone = "primary", size = "body", className, ...props }) {
4
- return (_jsx("p", { ...props, className: classes("lo-ui-text", `lo-ui-text--${tone}`, `lo-ui-text--${size}`, className) }));
4
+ export function Text({ as: Tag = "p", tone = "primary", weight, family, size = "body", className, ...props }) {
5
+ return (_jsx(Tag, { ...props, className: classes("lo-ui-text", `lo-ui-text--${tone}`, `lo-ui-text--${size}`, weight && `lo-ui-text--weight-${weight}`, family && `lo-ui-text--family-${family}`, className) }));
5
6
  }
6
- export function Heading({ level = 1, className, ...props }) {
7
+ export const Heading = forwardRef(function Heading({ level = 1, className, ...props }, ref) {
7
8
  const Tag = `h${level}`;
8
- return _jsx(Tag, { ...props, className: classes("lo-ui-heading", className) });
9
- }
9
+ return (_jsx(Tag, { ...props, ref: ref, className: classes("lo-ui-heading", className) }));
10
+ });
package/dist/index.d.ts CHANGED
@@ -6,4 +6,8 @@ export { Cell, List, type CellProps, type ListProps } from "./List.js";
6
6
  export { Checkbox, Switch, type SelectionControlProps, } from "./SelectionControl.js";
7
7
  export { TextField, type TextFieldProps } from "./TextField.js";
8
8
  export { Heading, Text, type HeadingProps, type TextProps, } from "./Typography.js";
9
+ export { TextArea, type TextAreaProps } from "./TextArea.js";
10
+ export { Surface, type SurfaceProps } from "./Surface.js";
11
+ export { Dialog } from "./Dialog.js";
12
+ export { Progress } from "./Progress.js";
9
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,QAAQ,EACR,MAAM,EACN,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,OAAO,EACP,IAAI,EACJ,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,QAAQ,EACR,MAAM,EACN,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,OAAO,EACP,IAAI,EACJ,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -6,3 +6,7 @@ export { Cell, List } from "./List.js";
6
6
  export { Checkbox, Switch, } from "./SelectionControl.js";
7
7
  export { TextField } from "./TextField.js";
8
8
  export { Heading, Text, } from "./Typography.js";
9
+ export { TextArea } from "./TextArea.js";
10
+ export { Surface } from "./Surface.js";
11
+ export { Dialog } from "./Dialog.js";
12
+ export { Progress } from "./Progress.js";
package/dist/styles.css CHANGED
@@ -13,12 +13,16 @@
13
13
  box-sizing: border-box;
14
14
  }
15
15
 
16
- :where(.lo-ui-root button, .lo-ui-root input) {
16
+ :where(.lo-ui-root button, .lo-ui-root input, .lo-ui-root textarea) {
17
17
  font: inherit;
18
18
  -webkit-tap-highlight-color: transparent;
19
19
  }
20
20
 
21
- :where(.lo-ui-root button, .lo-ui-root input):focus-visible {
21
+ :where(
22
+ .lo-ui-root button,
23
+ .lo-ui-root input,
24
+ .lo-ui-root textarea
25
+ ):focus-visible {
22
26
  outline: 3px solid var(--lo-color-focus);
23
27
  outline-offset: 2px;
24
28
  }
@@ -221,7 +225,8 @@
221
225
  justify-content: center;
222
226
  }
223
227
 
224
- .lo-ui-selection--control-only .lo-ui-selection__copy {
228
+ .lo-ui-selection--control-only .lo-ui-selection__copy,
229
+ .lo-ui-field--label-hidden .lo-ui-field__label {
225
230
  position: absolute;
226
231
  width: 1px;
227
232
  height: 1px;
@@ -443,18 +448,23 @@
443
448
  border-radius: 11px;
444
449
  color: var(--lo-color-accent-contrast);
445
450
  background: var(--lo-color-accent-fill);
451
+ font-size: 18px;
452
+ font-weight: var(--lo-font-weight-medium);
453
+ line-height: 1;
446
454
  }
447
455
 
448
456
  .lo-ui-app-icon--small {
449
457
  width: 32px;
450
458
  height: 32px;
451
459
  border-radius: 8px;
460
+ font-size: 14px;
452
461
  }
453
462
 
454
463
  .lo-ui-app-icon--large {
455
464
  width: 64px;
456
465
  height: 64px;
457
466
  border-radius: 16px;
467
+ font-size: 26px;
458
468
  }
459
469
 
460
470
  .lo-ui-app-icon > img {
@@ -470,28 +480,25 @@
470
480
  }
471
481
 
472
482
  .lo-ui-empty-state {
473
- min-height: 240px;
474
- padding: var(--lo-space-8) var(--lo-space-6);
483
+ padding: 30px 15px;
475
484
  display: flex;
476
485
  flex-direction: column;
477
486
  align-items: center;
478
487
  justify-content: center;
479
- gap: var(--lo-space-2);
488
+ gap: 10px;
480
489
  text-align: center;
481
- border: 1px dashed var(--lo-color-border);
482
- border-radius: var(--lo-radius-lg);
490
+ border: 1px solid color-mix(in srgb, var(--lo-color-accent) 4%, transparent);
491
+ border-radius: calc(var(--lo-radius-lg) + 2px);
483
492
  background: var(--lo-color-surface);
484
493
  }
485
494
 
486
495
  .lo-ui-empty-state__icon {
487
496
  width: 52px;
488
497
  height: 52px;
489
- margin-bottom: var(--lo-space-2);
498
+ margin-bottom: 5px;
490
499
  display: grid;
491
500
  place-items: center;
492
- border-radius: var(--lo-radius-md);
493
- color: var(--lo-color-accent);
494
- background: var(--lo-color-accent-soft);
501
+ color: var(--lo-color-accent-text);
495
502
  }
496
503
 
497
504
  .lo-ui-empty-state__icon > svg {
@@ -507,19 +514,20 @@
507
514
  }
508
515
 
509
516
  .lo-ui-empty-state__title {
517
+ font-family: var(--lo-font-family);
510
518
  color: var(--lo-color-text);
511
- font-size: var(--lo-font-size-body);
519
+ font-size: 26px;
512
520
  line-height: var(--lo-line-height-tight);
513
521
  }
514
522
 
515
523
  .lo-ui-empty-state__description {
516
524
  max-width: 36ch;
517
525
  color: var(--lo-color-text-secondary);
518
- font-size: var(--lo-font-size-label);
526
+ font-size: var(--lo-font-size-body);
519
527
  }
520
528
 
521
529
  .lo-ui-empty-state__action {
522
- margin-top: var(--lo-space-3);
530
+ margin-top: 5px;
523
531
  }
524
532
 
525
533
  .lo-ui-stack,
@@ -538,6 +546,7 @@
538
546
  }
539
547
 
540
548
  .lo-ui-heading {
549
+ font-family: var(--lo-font-family);
541
550
  color: var(--lo-color-text);
542
551
  font-weight: var(--lo-font-weight-bold);
543
552
  font-size: var(--lo-font-size-title);
@@ -580,3 +589,129 @@
580
589
  animation: none;
581
590
  }
582
591
  }
592
+
593
+ .lo-ui-surface {
594
+ min-width: 0;
595
+ padding: var(--lo-surface-padding);
596
+ border: 1px solid var(--lo-color-border);
597
+ border-radius: var(--lo-radius-lg);
598
+ background: var(--lo-color-surface);
599
+ color: var(--lo-color-text);
600
+ }
601
+ .lo-ui-dialog {
602
+ box-sizing: border-box;
603
+ width: min(560px, calc(100% - 32px));
604
+ max-height: calc(100dvh - 32px);
605
+ overflow-y: auto;
606
+ padding: var(--lo-space-5);
607
+ border: 1px solid var(--lo-color-border);
608
+ border-radius: var(--lo-radius-lg);
609
+ color: var(--lo-color-text);
610
+ background: var(--lo-color-surface);
611
+ }
612
+ .lo-ui-dialog::backdrop {
613
+ background: #12162466;
614
+ }
615
+ .lo-ui-textarea {
616
+ resize: vertical;
617
+ line-height: var(--lo-line-height-body);
618
+ }
619
+ .lo-ui-field__input[type="file"] {
620
+ padding: var(--lo-space-2);
621
+ }
622
+ .lo-ui-field__input::file-selector-button {
623
+ font: inherit;
624
+ color: var(--lo-color-accent-text);
625
+ background: var(--lo-color-accent-soft);
626
+ border: 0;
627
+ border-radius: var(--lo-radius-full);
628
+ padding: var(--lo-space-2) var(--lo-space-3);
629
+ margin-right: var(--lo-space-2);
630
+ cursor: pointer;
631
+ }
632
+ .lo-ui-progress {
633
+ display: block;
634
+ appearance: none;
635
+ border: 0;
636
+ width: 100%;
637
+ height: 10px;
638
+ border-radius: var(--lo-radius-full);
639
+ overflow: hidden;
640
+ background: var(--lo-color-border);
641
+ color: var(--lo-color-accent);
642
+ }
643
+ .lo-ui-progress::-webkit-progress-bar {
644
+ background: var(--lo-color-border);
645
+ }
646
+ .lo-ui-progress::-webkit-progress-value {
647
+ background: var(--lo-color-accent);
648
+ border-radius: var(--lo-radius-full);
649
+ }
650
+ .lo-ui-progress::-moz-progress-bar {
651
+ background: var(--lo-color-accent);
652
+ border-radius: var(--lo-radius-full);
653
+ }
654
+
655
+ :where(.lo-ui-root code, .lo-ui-root pre) {
656
+ font-family: var(--lo-font-family-mono);
657
+ }
658
+
659
+ .lo-ui-app-icon:has(> img) {
660
+ background: transparent;
661
+ }
662
+ .lo-ui-progress:indeterminate {
663
+ background-image: linear-gradient(
664
+ 90deg,
665
+ var(--lo-color-border) 0% 30%,
666
+ var(--lo-color-accent) 30% 50%,
667
+ var(--lo-color-border) 50% 100%
668
+ );
669
+ background-size: 200% 100%;
670
+ animation: lo-ui-progress-pending 1.4s linear infinite;
671
+ }
672
+ .lo-ui-progress:indeterminate::-webkit-progress-bar {
673
+ background: transparent;
674
+ }
675
+ @keyframes lo-ui-progress-pending {
676
+ from {
677
+ background-position: 100% 0;
678
+ }
679
+ to {
680
+ background-position: 0% 0;
681
+ }
682
+ }
683
+ @media (prefers-reduced-motion: reduce) {
684
+ .lo-ui-progress:indeterminate {
685
+ animation: none;
686
+ background-position: 50% 0;
687
+ }
688
+ }
689
+
690
+ .lo-ui-text--title {
691
+ font-size: 26px;
692
+ }
693
+ .lo-ui-text--display {
694
+ font-size: 40px;
695
+ line-height: var(--lo-line-height-tight);
696
+ }
697
+ .lo-ui-text--success {
698
+ color: var(--lo-color-success);
699
+ }
700
+ .lo-ui-text--weight-regular {
701
+ font-weight: var(--lo-font-weight-regular);
702
+ }
703
+ .lo-ui-text--weight-medium {
704
+ font-weight: var(--lo-font-weight-medium);
705
+ }
706
+ .lo-ui-text--weight-bold {
707
+ font-weight: var(--lo-font-weight-bold);
708
+ }
709
+ .lo-ui-text--family-ui {
710
+ font-family: var(--lo-font-family);
711
+ }
712
+ .lo-ui-text--family-display {
713
+ font-family: var(--lo-font-family-display);
714
+ }
715
+ .lo-ui-text--family-mono {
716
+ font-family: var(--lo-font-family-mono);
717
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lo-ink/ui",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Accessible React components for LO miniapps",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,10 +30,10 @@
30
30
  },
31
31
  "scripts": {
32
32
  "prepack": "npm run build",
33
- "build": "tsc -p tsconfig.json && node scripts/copy-assets.mjs"
33
+ "build": "node ../../scripts/build-package.mjs"
34
34
  },
35
35
  "dependencies": {
36
- "@lo-ink/design-tokens": "0.2.0"
36
+ "@lo-ink/design-tokens": "0.3.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react": ">=18 <20",
package/src/AppIcon.tsx CHANGED
@@ -21,6 +21,7 @@ export function AppIcon({
21
21
  return (
22
22
  <span
23
23
  {...props}
24
+ role={props.role ?? (!src && props["aria-label"] ? "img" : undefined)}
24
25
  className={classes(
25
26
  "lo-ui-app-icon",
26
27
  `lo-ui-app-icon--${size}`,
package/src/Dialog.tsx ADDED
@@ -0,0 +1,16 @@
1
+ import { forwardRef, type DialogHTMLAttributes } from "react";
2
+ import { classes } from "./utils.js";
3
+
4
+ /** Native modal semantics; the caller controls showModal(), close() and cancellation. */
5
+ export const Dialog = forwardRef<
6
+ HTMLDialogElement,
7
+ DialogHTMLAttributes<HTMLDialogElement>
8
+ >(function Dialog({ className, ...props }, ref) {
9
+ return (
10
+ <dialog
11
+ {...props}
12
+ ref={ref}
13
+ className={classes("lo-ui-dialog", className)}
14
+ />
15
+ );
16
+ });
@@ -0,0 +1,11 @@
1
+ import type { ProgressHTMLAttributes } from "react";
2
+ import { classes } from "./utils.js";
3
+
4
+ export function Progress({
5
+ className,
6
+ ...props
7
+ }: ProgressHTMLAttributes<HTMLProgressElement>) {
8
+ return (
9
+ <progress {...props} className={classes("lo-ui-progress", className)} />
10
+ );
11
+ }
@@ -0,0 +1,26 @@
1
+ import type { CSSProperties, HTMLAttributes } from "react";
2
+ import type { SpacingToken } from "@lo-ink/design-tokens";
3
+ import { classes } from "./utils.js";
4
+
5
+ export interface SurfaceProps extends HTMLAttributes<HTMLElement> {
6
+ padding?: SpacingToken;
7
+ }
8
+ export function Surface({
9
+ padding = 4,
10
+ className,
11
+ style,
12
+ ...props
13
+ }: SurfaceProps) {
14
+ return (
15
+ <section
16
+ {...props}
17
+ className={classes("lo-ui-surface", className)}
18
+ style={
19
+ {
20
+ "--lo-surface-padding": `var(--lo-space-${padding})`,
21
+ ...style,
22
+ } as CSSProperties
23
+ }
24
+ />
25
+ );
26
+ }
@@ -0,0 +1,60 @@
1
+ import {
2
+ forwardRef,
3
+ useId,
4
+ type ReactNode,
5
+ type TextareaHTMLAttributes,
6
+ } from "react";
7
+ import { classes } from "./utils.js";
8
+
9
+ export interface TextAreaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
10
+ label: ReactNode;
11
+ description?: ReactNode;
12
+ error?: ReactNode;
13
+ }
14
+ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
15
+ function TextArea(
16
+ {
17
+ label,
18
+ description,
19
+ error,
20
+ id: providedId,
21
+ className,
22
+ "aria-describedby": describedBy,
23
+ ...props
24
+ },
25
+ ref,
26
+ ) {
27
+ const generatedId = useId();
28
+ const id = providedId ?? generatedId;
29
+ const descriptionId = description ? `${id}-description` : undefined;
30
+ const errorId = error ? `${id}-error` : undefined;
31
+ return (
32
+ <div className={classes("lo-ui-field", className)}>
33
+ <label className="lo-ui-field__label" htmlFor={id}>
34
+ {label}
35
+ </label>
36
+ <textarea
37
+ {...props}
38
+ ref={ref}
39
+ id={id}
40
+ aria-invalid={error ? true : props["aria-invalid"]}
41
+ aria-describedby={
42
+ [describedBy, descriptionId, errorId].filter(Boolean).join(" ") ||
43
+ undefined
44
+ }
45
+ className="lo-ui-field__input lo-ui-textarea"
46
+ />
47
+ {description && (
48
+ <div className="lo-ui-field__description" id={descriptionId}>
49
+ {description}
50
+ </div>
51
+ )}
52
+ {error && (
53
+ <div className="lo-ui-field__error" id={errorId}>
54
+ {error}
55
+ </div>
56
+ )}
57
+ </div>
58
+ );
59
+ },
60
+ );
package/src/TextField.tsx CHANGED
@@ -14,6 +14,7 @@ export interface TextFieldProps extends Omit<
14
14
  description?: ReactNode;
15
15
  error?: ReactNode;
16
16
  inputClassName?: string;
17
+ labelHidden?: boolean;
17
18
  }
18
19
 
19
20
  export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
@@ -25,6 +26,7 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
25
26
  id: providedId,
26
27
  className,
27
28
  inputClassName,
29
+ labelHidden = false,
28
30
  "aria-describedby": ariaDescribedBy,
29
31
  ...props
30
32
  },
@@ -39,7 +41,13 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
39
41
  .join(" ");
40
42
 
41
43
  return (
42
- <div className={classes("lo-ui-field", className)}>
44
+ <div
45
+ className={classes(
46
+ "lo-ui-field",
47
+ labelHidden && "lo-ui-field--label-hidden",
48
+ className,
49
+ )}
50
+ >
43
51
  <label className="lo-ui-field__label" htmlFor={id}>
44
52
  {label}
45
53
  </label>
@@ -1,24 +1,32 @@
1
- import type { HTMLAttributes } from "react";
1
+ import { forwardRef, type HTMLAttributes } from "react";
2
2
  import { classes } from "./utils.js";
3
3
 
4
- export interface TextProps extends HTMLAttributes<HTMLParagraphElement> {
5
- tone?: "primary" | "secondary" | "danger";
6
- size?: "caption" | "label" | "body";
4
+ export interface TextProps extends HTMLAttributes<HTMLElement> {
5
+ as?: "p" | "span" | "strong" | "code" | "pre";
6
+ tone?: "primary" | "secondary" | "danger" | "success";
7
+ weight?: "regular" | "medium" | "bold";
8
+ family?: "ui" | "display" | "mono";
9
+ size?: "caption" | "label" | "body" | "title" | "display";
7
10
  }
8
11
 
9
12
  export function Text({
13
+ as: Tag = "p",
10
14
  tone = "primary",
15
+ weight,
16
+ family,
11
17
  size = "body",
12
18
  className,
13
19
  ...props
14
20
  }: TextProps) {
15
21
  return (
16
- <p
22
+ <Tag
17
23
  {...props}
18
24
  className={classes(
19
25
  "lo-ui-text",
20
26
  `lo-ui-text--${tone}`,
21
27
  `lo-ui-text--${size}`,
28
+ weight && `lo-ui-text--weight-${weight}`,
29
+ family && `lo-ui-text--family-${family}`,
22
30
  className,
23
31
  )}
24
32
  />
@@ -29,7 +37,15 @@ export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
29
37
  level?: 1 | 2 | 3 | 4 | 5 | 6;
30
38
  }
31
39
 
32
- export function Heading({ level = 1, className, ...props }: HeadingProps) {
33
- const Tag = `h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
34
- return <Tag {...props} className={classes("lo-ui-heading", className)} />;
35
- }
40
+ export const Heading = forwardRef<HTMLHeadingElement, HeadingProps>(
41
+ function Heading({ level = 1, className, ...props }, ref) {
42
+ const Tag = `h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
43
+ return (
44
+ <Tag
45
+ {...props}
46
+ ref={ref}
47
+ className={classes("lo-ui-heading", className)}
48
+ />
49
+ );
50
+ },
51
+ );
package/src/index.ts CHANGED
@@ -15,3 +15,7 @@ export {
15
15
  type HeadingProps,
16
16
  type TextProps,
17
17
  } from "./Typography.js";
18
+ export { TextArea, type TextAreaProps } from "./TextArea.js";
19
+ export { Surface, type SurfaceProps } from "./Surface.js";
20
+ export { Dialog } from "./Dialog.js";
21
+ export { Progress } from "./Progress.js";
package/src/styles.css CHANGED
@@ -13,12 +13,16 @@
13
13
  box-sizing: border-box;
14
14
  }
15
15
 
16
- :where(.lo-ui-root button, .lo-ui-root input) {
16
+ :where(.lo-ui-root button, .lo-ui-root input, .lo-ui-root textarea) {
17
17
  font: inherit;
18
18
  -webkit-tap-highlight-color: transparent;
19
19
  }
20
20
 
21
- :where(.lo-ui-root button, .lo-ui-root input):focus-visible {
21
+ :where(
22
+ .lo-ui-root button,
23
+ .lo-ui-root input,
24
+ .lo-ui-root textarea
25
+ ):focus-visible {
22
26
  outline: 3px solid var(--lo-color-focus);
23
27
  outline-offset: 2px;
24
28
  }
@@ -221,7 +225,8 @@
221
225
  justify-content: center;
222
226
  }
223
227
 
224
- .lo-ui-selection--control-only .lo-ui-selection__copy {
228
+ .lo-ui-selection--control-only .lo-ui-selection__copy,
229
+ .lo-ui-field--label-hidden .lo-ui-field__label {
225
230
  position: absolute;
226
231
  width: 1px;
227
232
  height: 1px;
@@ -443,18 +448,23 @@
443
448
  border-radius: 11px;
444
449
  color: var(--lo-color-accent-contrast);
445
450
  background: var(--lo-color-accent-fill);
451
+ font-size: 18px;
452
+ font-weight: var(--lo-font-weight-medium);
453
+ line-height: 1;
446
454
  }
447
455
 
448
456
  .lo-ui-app-icon--small {
449
457
  width: 32px;
450
458
  height: 32px;
451
459
  border-radius: 8px;
460
+ font-size: 14px;
452
461
  }
453
462
 
454
463
  .lo-ui-app-icon--large {
455
464
  width: 64px;
456
465
  height: 64px;
457
466
  border-radius: 16px;
467
+ font-size: 26px;
458
468
  }
459
469
 
460
470
  .lo-ui-app-icon > img {
@@ -470,28 +480,25 @@
470
480
  }
471
481
 
472
482
  .lo-ui-empty-state {
473
- min-height: 240px;
474
- padding: var(--lo-space-8) var(--lo-space-6);
483
+ padding: 30px 15px;
475
484
  display: flex;
476
485
  flex-direction: column;
477
486
  align-items: center;
478
487
  justify-content: center;
479
- gap: var(--lo-space-2);
488
+ gap: 10px;
480
489
  text-align: center;
481
- border: 1px dashed var(--lo-color-border);
482
- border-radius: var(--lo-radius-lg);
490
+ border: 1px solid color-mix(in srgb, var(--lo-color-accent) 4%, transparent);
491
+ border-radius: calc(var(--lo-radius-lg) + 2px);
483
492
  background: var(--lo-color-surface);
484
493
  }
485
494
 
486
495
  .lo-ui-empty-state__icon {
487
496
  width: 52px;
488
497
  height: 52px;
489
- margin-bottom: var(--lo-space-2);
498
+ margin-bottom: 5px;
490
499
  display: grid;
491
500
  place-items: center;
492
- border-radius: var(--lo-radius-md);
493
- color: var(--lo-color-accent);
494
- background: var(--lo-color-accent-soft);
501
+ color: var(--lo-color-accent-text);
495
502
  }
496
503
 
497
504
  .lo-ui-empty-state__icon > svg {
@@ -507,19 +514,20 @@
507
514
  }
508
515
 
509
516
  .lo-ui-empty-state__title {
517
+ font-family: var(--lo-font-family);
510
518
  color: var(--lo-color-text);
511
- font-size: var(--lo-font-size-body);
519
+ font-size: 26px;
512
520
  line-height: var(--lo-line-height-tight);
513
521
  }
514
522
 
515
523
  .lo-ui-empty-state__description {
516
524
  max-width: 36ch;
517
525
  color: var(--lo-color-text-secondary);
518
- font-size: var(--lo-font-size-label);
526
+ font-size: var(--lo-font-size-body);
519
527
  }
520
528
 
521
529
  .lo-ui-empty-state__action {
522
- margin-top: var(--lo-space-3);
530
+ margin-top: 5px;
523
531
  }
524
532
 
525
533
  .lo-ui-stack,
@@ -538,6 +546,7 @@
538
546
  }
539
547
 
540
548
  .lo-ui-heading {
549
+ font-family: var(--lo-font-family);
541
550
  color: var(--lo-color-text);
542
551
  font-weight: var(--lo-font-weight-bold);
543
552
  font-size: var(--lo-font-size-title);
@@ -580,3 +589,129 @@
580
589
  animation: none;
581
590
  }
582
591
  }
592
+
593
+ .lo-ui-surface {
594
+ min-width: 0;
595
+ padding: var(--lo-surface-padding);
596
+ border: 1px solid var(--lo-color-border);
597
+ border-radius: var(--lo-radius-lg);
598
+ background: var(--lo-color-surface);
599
+ color: var(--lo-color-text);
600
+ }
601
+ .lo-ui-dialog {
602
+ box-sizing: border-box;
603
+ width: min(560px, calc(100% - 32px));
604
+ max-height: calc(100dvh - 32px);
605
+ overflow-y: auto;
606
+ padding: var(--lo-space-5);
607
+ border: 1px solid var(--lo-color-border);
608
+ border-radius: var(--lo-radius-lg);
609
+ color: var(--lo-color-text);
610
+ background: var(--lo-color-surface);
611
+ }
612
+ .lo-ui-dialog::backdrop {
613
+ background: #12162466;
614
+ }
615
+ .lo-ui-textarea {
616
+ resize: vertical;
617
+ line-height: var(--lo-line-height-body);
618
+ }
619
+ .lo-ui-field__input[type="file"] {
620
+ padding: var(--lo-space-2);
621
+ }
622
+ .lo-ui-field__input::file-selector-button {
623
+ font: inherit;
624
+ color: var(--lo-color-accent-text);
625
+ background: var(--lo-color-accent-soft);
626
+ border: 0;
627
+ border-radius: var(--lo-radius-full);
628
+ padding: var(--lo-space-2) var(--lo-space-3);
629
+ margin-right: var(--lo-space-2);
630
+ cursor: pointer;
631
+ }
632
+ .lo-ui-progress {
633
+ display: block;
634
+ appearance: none;
635
+ border: 0;
636
+ width: 100%;
637
+ height: 10px;
638
+ border-radius: var(--lo-radius-full);
639
+ overflow: hidden;
640
+ background: var(--lo-color-border);
641
+ color: var(--lo-color-accent);
642
+ }
643
+ .lo-ui-progress::-webkit-progress-bar {
644
+ background: var(--lo-color-border);
645
+ }
646
+ .lo-ui-progress::-webkit-progress-value {
647
+ background: var(--lo-color-accent);
648
+ border-radius: var(--lo-radius-full);
649
+ }
650
+ .lo-ui-progress::-moz-progress-bar {
651
+ background: var(--lo-color-accent);
652
+ border-radius: var(--lo-radius-full);
653
+ }
654
+
655
+ :where(.lo-ui-root code, .lo-ui-root pre) {
656
+ font-family: var(--lo-font-family-mono);
657
+ }
658
+
659
+ .lo-ui-app-icon:has(> img) {
660
+ background: transparent;
661
+ }
662
+ .lo-ui-progress:indeterminate {
663
+ background-image: linear-gradient(
664
+ 90deg,
665
+ var(--lo-color-border) 0% 30%,
666
+ var(--lo-color-accent) 30% 50%,
667
+ var(--lo-color-border) 50% 100%
668
+ );
669
+ background-size: 200% 100%;
670
+ animation: lo-ui-progress-pending 1.4s linear infinite;
671
+ }
672
+ .lo-ui-progress:indeterminate::-webkit-progress-bar {
673
+ background: transparent;
674
+ }
675
+ @keyframes lo-ui-progress-pending {
676
+ from {
677
+ background-position: 100% 0;
678
+ }
679
+ to {
680
+ background-position: 0% 0;
681
+ }
682
+ }
683
+ @media (prefers-reduced-motion: reduce) {
684
+ .lo-ui-progress:indeterminate {
685
+ animation: none;
686
+ background-position: 50% 0;
687
+ }
688
+ }
689
+
690
+ .lo-ui-text--title {
691
+ font-size: 26px;
692
+ }
693
+ .lo-ui-text--display {
694
+ font-size: 40px;
695
+ line-height: var(--lo-line-height-tight);
696
+ }
697
+ .lo-ui-text--success {
698
+ color: var(--lo-color-success);
699
+ }
700
+ .lo-ui-text--weight-regular {
701
+ font-weight: var(--lo-font-weight-regular);
702
+ }
703
+ .lo-ui-text--weight-medium {
704
+ font-weight: var(--lo-font-weight-medium);
705
+ }
706
+ .lo-ui-text--weight-bold {
707
+ font-weight: var(--lo-font-weight-bold);
708
+ }
709
+ .lo-ui-text--family-ui {
710
+ font-family: var(--lo-font-family);
711
+ }
712
+ .lo-ui-text--family-display {
713
+ font-family: var(--lo-font-family-display);
714
+ }
715
+ .lo-ui-text--family-mono {
716
+ font-family: var(--lo-font-family-mono);
717
+ }