@lo-ink/ui 0.1.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lo-ink/ui",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Accessible React components for LO miniapps",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "build": "tsc -p tsconfig.json && node scripts/copy-assets.mjs"
34
34
  },
35
35
  "dependencies": {
36
- "@lo-ink/design-tokens": "0.1.1"
36
+ "@lo-ink/design-tokens": "0.3.0"
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
+ });
@@ -6,6 +6,7 @@ export interface EmptyStateProps extends Omit<
6
6
  "title"
7
7
  > {
8
8
  title: ReactNode;
9
+ headingLevel?: 2 | 3 | 4 | 5 | 6;
9
10
  description?: ReactNode;
10
11
  icon?: ReactNode;
11
12
  action?: ReactNode;
@@ -13,12 +14,14 @@ export interface EmptyStateProps extends Omit<
13
14
 
14
15
  export function EmptyState({
15
16
  title,
17
+ headingLevel = 2,
16
18
  description,
17
19
  icon,
18
20
  action,
19
21
  className,
20
22
  ...props
21
23
  }: EmptyStateProps) {
24
+ const Tag = `h${headingLevel}` as "h2" | "h3" | "h4" | "h5" | "h6";
22
25
  return (
23
26
  <div {...props} className={classes("lo-ui-empty-state", className)}>
24
27
  {icon && (
@@ -26,7 +29,7 @@ export function EmptyState({
26
29
  {icon}
27
30
  </div>
28
31
  )}
29
- <h2 className="lo-ui-empty-state__title">{title}</h2>
32
+ <Tag className="lo-ui-empty-state__title">{title}</Tag>
30
33
  {description && (
31
34
  <p className="lo-ui-empty-state__description">{description}</p>
32
35
  )}
package/src/List.tsx CHANGED
@@ -3,16 +3,19 @@ import { classes } from "./utils.js";
3
3
 
4
4
  export interface ListProps extends HTMLAttributes<HTMLUListElement> {
5
5
  label?: ReactNode;
6
+ headingLevel?: 2 | 3 | 4 | 5 | 6;
6
7
  }
7
8
 
8
9
  export function List({
9
10
  label,
11
+ headingLevel = 2,
10
12
  children,
11
13
  className,
12
14
  "aria-label": ariaLabel,
13
15
  "aria-labelledby": ariaLabelledBy,
14
16
  ...props
15
17
  }: ListProps) {
18
+ const Tag = `h${headingLevel}` as "h2" | "h3" | "h4" | "h5" | "h6";
16
19
  const generatedId = useId();
17
20
  const labelId = label ? `${generatedId}-label` : undefined;
18
21
  const effectiveLabelledBy =
@@ -20,9 +23,9 @@ export function List({
20
23
  return (
21
24
  <section className="lo-ui-list-section">
22
25
  {label && (
23
- <h2 className="lo-ui-list-label" id={labelId}>
26
+ <Tag className="lo-ui-list-label" id={labelId}>
24
27
  {label}
25
- </h2>
28
+ </Tag>
26
29
  )}
27
30
  <ul
28
31
  {...props}
@@ -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,33 +1,51 @@
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
  />
25
33
  );
26
34
  }
27
35
 
28
- export function Heading({
29
- className,
30
- ...props
31
- }: HTMLAttributes<HTMLHeadingElement>) {
32
- return <h1 {...props} className={classes("lo-ui-heading", className)} />;
36
+ export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
37
+ level?: 1 | 2 | 3 | 4 | 5 | 6;
33
38
  }
39
+
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
@@ -9,4 +9,13 @@ export {
9
9
  type SelectionControlProps,
10
10
  } from "./SelectionControl.js";
11
11
  export { TextField, type TextFieldProps } from "./TextField.js";
12
- export { Heading, Text, type TextProps } from "./Typography.js";
12
+ export {
13
+ Heading,
14
+ Text,
15
+ type HeadingProps,
16
+ type TextProps,
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
  }
@@ -27,7 +31,12 @@
27
31
  min-height: var(--lo-size-control);
28
32
  padding: 0 var(--lo-space-5);
29
33
  border: 1px solid transparent;
30
- border-radius: var(--lo-radius-md);
34
+ border-radius: var(--lo-radius-full);
35
+ min-width: 0;
36
+ max-width: 100%;
37
+ white-space: normal;
38
+ overflow-wrap: anywhere;
39
+ text-align: center;
31
40
  display: inline-flex;
32
41
  align-items: center;
33
42
  justify-content: center;
@@ -62,7 +71,7 @@
62
71
 
63
72
  .lo-ui-button--primary {
64
73
  color: var(--lo-color-accent-contrast);
65
- background: var(--lo-color-accent);
74
+ background: var(--lo-color-accent-fill);
66
75
  }
67
76
 
68
77
  .lo-ui-button--primary:hover:not(:disabled) {
@@ -70,12 +79,19 @@
70
79
  }
71
80
 
72
81
  .lo-ui-button--secondary {
73
- color: var(--lo-color-text);
74
- background: var(--lo-color-surface);
75
- border-color: var(--lo-color-border);
82
+ color: var(--lo-color-accent-text);
83
+ background: var(--lo-color-accent-soft);
84
+ border-color: transparent;
85
+ }
86
+
87
+ .lo-ui-button--secondary:hover:not(:disabled) {
88
+ background: color-mix(
89
+ in srgb,
90
+ var(--lo-color-accent) 20%,
91
+ var(--lo-color-surface)
92
+ );
76
93
  }
77
94
 
78
- .lo-ui-button--secondary:hover:not(:disabled),
79
95
  .lo-ui-button--quiet:hover:not(:disabled) {
80
96
  background: var(--lo-color-accent-soft);
81
97
  }
@@ -91,7 +107,7 @@
91
107
  }
92
108
 
93
109
  .lo-ui-button--quiet {
94
- color: var(--lo-color-accent);
110
+ color: var(--lo-color-accent-text);
95
111
  background: transparent;
96
112
  }
97
113
 
@@ -135,7 +151,7 @@
135
151
  padding: 10px var(--lo-space-3);
136
152
  color: var(--lo-color-text);
137
153
  background: var(--lo-color-surface);
138
- border: 1px solid var(--lo-color-border);
154
+ border: 1px solid var(--lo-color-control-border);
139
155
  border-radius: var(--lo-radius-md);
140
156
  font-size: 16px;
141
157
  transition:
@@ -209,7 +225,8 @@
209
225
  justify-content: center;
210
226
  }
211
227
 
212
- .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 {
213
230
  position: absolute;
214
231
  width: 1px;
215
232
  height: 1px;
@@ -228,7 +245,7 @@
228
245
  padding: 2px;
229
246
  border: 0;
230
247
  border-radius: var(--lo-radius-full);
231
- background: var(--lo-color-border);
248
+ background: var(--lo-color-control-border);
232
249
  cursor: pointer;
233
250
  transition: background-color var(--lo-motion-fast) var(--lo-ease-out);
234
251
  }
@@ -245,7 +262,7 @@
245
262
  }
246
263
 
247
264
  .lo-ui-switch:checked {
248
- background: var(--lo-color-accent);
265
+ background: var(--lo-color-accent-fill);
249
266
  }
250
267
 
251
268
  .lo-ui-switch:checked::after {
@@ -265,7 +282,7 @@
265
282
  margin: 0;
266
283
  display: grid;
267
284
  place-items: center;
268
- border: 1.5px solid var(--lo-color-border);
285
+ border: 1.5px solid var(--lo-color-control-border);
269
286
  border-radius: 7px;
270
287
  background: var(--lo-color-surface);
271
288
  cursor: pointer;
@@ -282,8 +299,13 @@
282
299
  }
283
300
 
284
301
  .lo-ui-checkbox:checked {
285
- background: var(--lo-color-accent);
286
- border-color: var(--lo-color-accent);
302
+ background: var(--lo-color-accent-fill);
303
+ border-color: var(--lo-color-accent-fill);
304
+ }
305
+
306
+ .lo-ui-checkbox:disabled {
307
+ cursor: default;
308
+ opacity: 0.5;
287
309
  }
288
310
 
289
311
  .lo-ui-checkbox:checked::after {
@@ -384,6 +406,7 @@
384
406
 
385
407
  .lo-ui-cell__title {
386
408
  font-size: var(--lo-font-size-body);
409
+ font-weight: var(--lo-font-weight-medium);
387
410
  }
388
411
 
389
412
  .lo-ui-cell__subtitle {
@@ -424,19 +447,24 @@
424
447
  place-items: center;
425
448
  border-radius: 11px;
426
449
  color: var(--lo-color-accent-contrast);
427
- background: var(--lo-color-accent);
450
+ background: var(--lo-color-accent-fill);
451
+ font-size: 18px;
452
+ font-weight: var(--lo-font-weight-medium);
453
+ line-height: 1;
428
454
  }
429
455
 
430
456
  .lo-ui-app-icon--small {
431
457
  width: 32px;
432
458
  height: 32px;
433
459
  border-radius: 8px;
460
+ font-size: 14px;
434
461
  }
435
462
 
436
463
  .lo-ui-app-icon--large {
437
464
  width: 64px;
438
465
  height: 64px;
439
466
  border-radius: 16px;
467
+ font-size: 26px;
440
468
  }
441
469
 
442
470
  .lo-ui-app-icon > img {
@@ -452,28 +480,25 @@
452
480
  }
453
481
 
454
482
  .lo-ui-empty-state {
455
- min-height: 240px;
456
- padding: var(--lo-space-8) var(--lo-space-6);
483
+ padding: 30px 15px;
457
484
  display: flex;
458
485
  flex-direction: column;
459
486
  align-items: center;
460
487
  justify-content: center;
461
- gap: var(--lo-space-2);
488
+ gap: 10px;
462
489
  text-align: center;
463
- border: 1px dashed var(--lo-color-border);
464
- 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);
465
492
  background: var(--lo-color-surface);
466
493
  }
467
494
 
468
495
  .lo-ui-empty-state__icon {
469
496
  width: 52px;
470
497
  height: 52px;
471
- margin-bottom: var(--lo-space-2);
498
+ margin-bottom: 5px;
472
499
  display: grid;
473
500
  place-items: center;
474
- border-radius: var(--lo-radius-md);
475
- color: var(--lo-color-accent);
476
- background: var(--lo-color-accent-soft);
501
+ color: var(--lo-color-accent-text);
477
502
  }
478
503
 
479
504
  .lo-ui-empty-state__icon > svg {
@@ -489,18 +514,20 @@
489
514
  }
490
515
 
491
516
  .lo-ui-empty-state__title {
492
- font-size: var(--lo-font-size-body);
517
+ font-family: var(--lo-font-family);
518
+ color: var(--lo-color-text);
519
+ font-size: 26px;
493
520
  line-height: var(--lo-line-height-tight);
494
521
  }
495
522
 
496
523
  .lo-ui-empty-state__description {
497
524
  max-width: 36ch;
498
525
  color: var(--lo-color-text-secondary);
499
- font-size: var(--lo-font-size-label);
526
+ font-size: var(--lo-font-size-body);
500
527
  }
501
528
 
502
529
  .lo-ui-empty-state__action {
503
- margin-top: var(--lo-space-3);
530
+ margin-top: 5px;
504
531
  }
505
532
 
506
533
  .lo-ui-stack,
@@ -519,11 +546,15 @@
519
546
  }
520
547
 
521
548
  .lo-ui-heading {
549
+ font-family: var(--lo-font-family);
550
+ color: var(--lo-color-text);
551
+ font-weight: var(--lo-font-weight-bold);
522
552
  font-size: var(--lo-font-size-title);
523
553
  line-height: var(--lo-line-height-tight);
524
554
  }
525
555
 
526
556
  .lo-ui-text {
557
+ color: var(--lo-color-text);
527
558
  line-height: var(--lo-line-height-body);
528
559
  }
529
560
 
@@ -558,3 +589,129 @@
558
589
  animation: none;
559
590
  }
560
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
+ }