@monimesl/dot-renderer-react 0.1.0-alpha.14 → 0.1.0-alpha.16

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.
@@ -0,0 +1,59 @@
1
+ import { CARD_RADIUS_SCALE } from "./tokens.js";
2
+ import { toneBackground } from "./tones.js";
3
+ import { BACKGROUNDS, TONES } from "@monimesl/dot-core";
4
+ //#region src/components/box.ts
5
+ const RADIUS_SCALE = {
6
+ none: 0,
7
+ small: .5,
8
+ medium: 1,
9
+ large: CARD_RADIUS_SCALE
10
+ };
11
+ const FULL_RADIUS = 9999;
12
+ const BACKGROUND_WORDS = new Set(BACKGROUNDS.words);
13
+ const TONE_WORDS = new Set(TONES);
14
+ function boxStyle(props, theme, look = {}) {
15
+ const background = props.background ?? look.background;
16
+ const border = props.border ?? look.border;
17
+ const radius = props.radius ?? look.radius;
18
+ const style = {};
19
+ if (background !== void 0) style.background = backgroundColor(background, theme);
20
+ if (border !== void 0) {
21
+ const color = border === "strong" ? theme.colors.subtle : theme.colors.border;
22
+ style.border = border === "none" ? "none" : `1px solid ${color}`;
23
+ }
24
+ if (radius !== void 0) {
25
+ style.borderRadius = radius === "full" ? FULL_RADIUS : theme.radius * RADIUS_SCALE[radius];
26
+ style.overflow = "hidden";
27
+ }
28
+ if (props.width !== void 0) {
29
+ style.width = cssLength(props.width);
30
+ style.flexShrink = 0;
31
+ }
32
+ if (props.aspect !== void 0) style.aspectRatio = props.aspect.replace(":", " / ");
33
+ else if (props.height !== void 0) {
34
+ style.height = cssLength(props.height);
35
+ style.flexShrink = 0;
36
+ }
37
+ if (props.minHeight !== void 0) style.minHeight = props.minHeight;
38
+ if (props.maxWidth !== void 0) style.maxWidth = props.maxWidth;
39
+ return style;
40
+ }
41
+ function backgroundColor(background, theme) {
42
+ if (TONE_WORDS.has(background)) return toneBackground(theme.colors, background);
43
+ if (BACKGROUND_WORDS.has(background)) return theme.colors[background];
44
+ return customColor(background, theme);
45
+ }
46
+ function customColor(name, theme) {
47
+ const color = theme.customColors[name];
48
+ if (color === void 0 && !unknownColors.has(name)) {
49
+ unknownColors.add(name);
50
+ console.warn(`The theme has no colour named "${name}". Add it to colors.custom in dot.ts.`);
51
+ }
52
+ return color;
53
+ }
54
+ const unknownColors = /* @__PURE__ */ new Set();
55
+ function cssLength(value) {
56
+ return value === "fill" ? "100%" : value;
57
+ }
58
+ //#endregion
59
+ export { boxStyle, customColor };
@@ -21,10 +21,11 @@ import { Select } from "./select.js";
21
21
  import { Sheet } from "./sheet.js";
22
22
  import { Skeleton } from "./skeleton.js";
23
23
  import { Spinner } from "./spinner.js";
24
+ import { Stack } from "./stack.js";
24
25
  import { Tab, Tabs } from "./tabs.js";
25
26
  import { Text } from "./text.js";
26
27
  import { TextArea } from "./text-area.js";
27
28
  import { Toast } from "./toast.js";
28
29
  import { Checkbox, Radio, RadioGroup, Switch } from "./toggles.js";
29
30
  import { View } from "./view.js";
30
- export { AmountInput, Badge, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, QRCode, Radio, RadioGroup, Scroll, Select, Sheet, Skeleton, Spinner, Switch, Tab, Tabs, Text, TextArea, Toast, View };
31
+ export { AmountInput, Badge, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, QRCode, Radio, RadioGroup, Scroll, Select, Sheet, Skeleton, Spinner, Stack, Switch, Tab, Tabs, Text, TextArea, Toast, View };
@@ -22,6 +22,7 @@ import { Scroll } from "./scroll.js";
22
22
  import { Sheet } from "./sheet.js";
23
23
  import { Select } from "./select.js";
24
24
  import { Skeleton } from "./skeleton.js";
25
+ import { Stack } from "./stack.js";
25
26
  import { Tab, Tabs } from "./tabs.js";
26
27
  import { Text } from "./text.js";
27
28
  import { TextArea } from "./text-area.js";
@@ -60,6 +61,7 @@ var components_exports = /* @__PURE__ */ __exportAll({
60
61
  Sheet: () => Sheet,
61
62
  Skeleton: () => Skeleton,
62
63
  Spinner: () => Spinner,
64
+ Stack: () => Stack,
63
65
  Switch: () => Switch,
64
66
  Tab: () => Tab,
65
67
  Tabs: () => Tabs,
@@ -69,4 +71,4 @@ var components_exports = /* @__PURE__ */ __exportAll({
69
71
  View: () => View
70
72
  });
71
73
  //#endregion
72
- export { AmountInput, Badge, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, QRCode, Radio, RadioGroup, Scroll, Select, Sheet, Skeleton, Spinner, Switch, Tab, Tabs, Text, TextArea, Toast, View, components_exports };
74
+ export { AmountInput, Badge, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, QRCode, Radio, RadioGroup, Scroll, Select, Sheet, Skeleton, Spinner, Stack, Switch, Tab, Tabs, Text, TextArea, Toast, View, components_exports };
@@ -0,0 +1,6 @@
1
+ import { ReactComponent } from "../types.js";
2
+ import { Stack } from "@monimesl/dot-core";
3
+ //#region src/components/stack.d.ts
4
+ declare const Stack$1: ReactComponent<typeof Stack>;
5
+ //#endregion
6
+ export { Stack$1 as Stack };
@@ -0,0 +1,25 @@
1
+ import { useTheme } from "../theme.js";
2
+ import { boxStyle } from "./box.js";
3
+ import { Children } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/components/stack.tsx
6
+ const Stack = (props) => {
7
+ const theme = useTheme();
8
+ return /* @__PURE__ */ jsx("div", {
9
+ className: "dot-stack",
10
+ style: {
11
+ display: "grid",
12
+ ...boxStyle(props, theme)
13
+ },
14
+ children: Children.map(props.children, (child) => /* @__PURE__ */ jsx("div", {
15
+ style: {
16
+ gridArea: "1 / 1",
17
+ display: "grid",
18
+ minWidth: 0
19
+ },
20
+ children: child
21
+ }))
22
+ });
23
+ };
24
+ //#endregion
25
+ export { Stack };
@@ -2,23 +2,38 @@ import { useTheme } from "../theme.js";
2
2
  import { FONT_SIZE, WEIGHTS } from "./tokens.js";
3
3
  import { paddingStyle } from "./padding.js";
4
4
  import { toneColor } from "./tones.js";
5
+ import { customColor } from "./box.js";
6
+ import { TONES } from "@monimesl/dot-core";
5
7
  import { createContext, useContext } from "react";
6
8
  import { jsx } from "react/jsx-runtime";
7
9
  //#region src/components/text.tsx
8
10
  const InsideText = createContext(false);
9
- const Text = ({ variant = "body", tone, weight, align, maxLines, children, ...padding }) => {
10
- const { colors } = useTheme();
11
+ const DEFAULT_WEIGHT = {
12
+ display: "bold",
13
+ title: "bold",
14
+ subtitle: "medium",
15
+ body: "regular",
16
+ caption: "regular"
17
+ };
18
+ const DECORATION = {
19
+ none: "none",
20
+ underline: "underline",
21
+ strikethrough: "line-through"
22
+ };
23
+ const Text$1 = ({ variant = "body", tone, weight, align, maxLines, decoration, numeric, children, ...padding }) => {
24
+ const theme = useTheme();
11
25
  const nested = useContext(InsideText);
12
- const defaultWeight = variant === "title" ? "bold" : "regular";
13
26
  const style = {
14
27
  display: nested ? "inline" : "block",
15
28
  margin: 0,
16
29
  fontSize: FONT_SIZE[variant],
17
30
  lineHeight: "normal",
18
- fontWeight: WEIGHTS[weight ?? defaultWeight],
31
+ fontWeight: WEIGHTS[weight ?? DEFAULT_WEIGHT[variant]],
19
32
  letterSpacing: "normal",
20
- color: tone ? toneColor(colors, tone) : "inherit",
33
+ color: tone ? textColor(tone, theme) : "inherit",
21
34
  textAlign: align,
35
+ textDecorationLine: decoration ? DECORATION[decoration] : void 0,
36
+ fontVariantNumeric: numeric ? "tabular-nums" : void 0,
22
37
  ...paddingStyle(padding)
23
38
  };
24
39
  if (maxLines) {
@@ -42,5 +57,10 @@ const Text = ({ variant = "body", tone, weight, align, maxLines, children, ...pa
42
57
  children: content
43
58
  });
44
59
  };
60
+ const THEME_TONES = new Set(TONES);
61
+ function textColor(tone, theme) {
62
+ if (THEME_TONES.has(tone)) return toneColor(theme.colors, tone);
63
+ return tone === "onPrimary" ? theme.colors.onPrimary : customColor(tone, theme);
64
+ }
45
65
  //#endregion
46
- export { Text };
66
+ export { Text$1 as Text };
@@ -8,7 +8,9 @@ const SPACE = {
8
8
  const FONT_SIZE = {
9
9
  caption: 13,
10
10
  body: 15,
11
- title: 20
11
+ subtitle: 17,
12
+ title: 20,
13
+ display: 32
12
14
  };
13
15
  const WEIGHTS = {
14
16
  regular: 400,
@@ -1,7 +1,8 @@
1
1
  import { useTheme } from "../theme.js";
2
- import { CARD_RADIUS_SCALE, SPACE } from "./tokens.js";
2
+ import { SPACE } from "./tokens.js";
3
3
  import { insets, paddingStyle } from "./padding.js";
4
4
  import { pressable } from "./pressable.js";
5
+ import { boxStyle } from "./box.js";
5
6
  import { createEvent } from "@monimesl/dot-core";
6
7
  import { jsx } from "react/jsx-runtime";
7
8
  //#region src/components/view.tsx
@@ -17,8 +18,14 @@ const JUSTIFY = {
17
18
  end: "flex-end",
18
19
  between: "space-between"
19
20
  };
20
- const View$1 = ({ direction = "column", gap = "medium", align = "stretch", justify = "start", wrap = false, grow = false, variant = "plain", onTap, children, ...padding }) => {
21
- const { colors, radius } = useTheme();
21
+ const CARD_LOOK = {
22
+ background: "surface",
23
+ border: "subtle",
24
+ radius: "large"
25
+ };
26
+ const View$1 = (props) => {
27
+ const { direction = "column", gap = "medium", align = "stretch", justify = "start", wrap = false, grow = false, variant = "plain", onTap, children } = props;
28
+ const theme = useTheme();
22
29
  const card = variant === "card";
23
30
  const style = {
24
31
  display: "flex",
@@ -27,18 +34,14 @@ const View$1 = ({ direction = "column", gap = "medium", align = "stretch", justi
27
34
  justifyContent: JUSTIFY[justify],
28
35
  flexWrap: wrap ? "wrap" : "nowrap",
29
36
  gap: SPACE[gap],
30
- ...paddingStyle(padding, card ? insets(SPACE.large) : void 0),
37
+ ...paddingStyle(props, card ? insets(SPACE.large) : void 0),
38
+ ...boxStyle(props, theme, card ? CARD_LOOK : void 0),
31
39
  cursor: onTap ? "pointer" : void 0
32
40
  };
33
41
  if (grow) {
34
42
  style.flexGrow = 1;
35
43
  style.minWidth = 0;
36
44
  }
37
- if (card) {
38
- style.background = colors.surface;
39
- style.border = `1px solid ${colors.border}`;
40
- style.borderRadius = radius * CARD_RADIUS_SCALE;
41
- }
42
45
  const press = onTap ? pressable(() => onTap(createEvent("tap"))) : void 0;
43
46
  return /* @__PURE__ */ jsx("div", {
44
47
  className: "dot-view",
package/dist/index.d.ts CHANGED
@@ -24,6 +24,7 @@ import { Select } from "./components/select.js";
24
24
  import { Sheet } from "./components/sheet.js";
25
25
  import { Skeleton } from "./components/skeleton.js";
26
26
  import { Spinner } from "./components/spinner.js";
27
+ import { Stack } from "./components/stack.js";
27
28
  import { Tab, Tabs } from "./components/tabs.js";
28
29
  import { Text } from "./components/text.js";
29
30
  import { TextArea } from "./components/text-area.js";
@@ -32,4 +33,4 @@ import { Checkbox, Radio, RadioGroup, Switch } from "./components/toggles.js";
32
33
  import { View } from "./components/view.js";
33
34
  import "./components/index.js";
34
35
  import { ResolvedColors, ResolvedTheme, resolveTheme, useTheme } from "./theme.js";
35
- export { AmountInput, Badge, type BuiltinReactComponents, Button, Carousel, Checkbox, Chip, CodeInput, type CreateReactRendererOptions, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, QRCode, Radio, RadioGroup, type ReactComponent, type ReactComponents, type ReactRendererOptions, type ResolvedColors, type ResolvedTheme, Scroll, Select, Sheet, Skeleton, Spinner, Switch, Tab, Tabs, Text, TextArea, Toast, View, type Wrapper, createReactRenderer, reactRenderer as default, resolveTheme, useTheme };
36
+ export { AmountInput, Badge, type BuiltinReactComponents, Button, Carousel, Checkbox, Chip, CodeInput, type CreateReactRendererOptions, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, QRCode, Radio, RadioGroup, type ReactComponent, type ReactComponents, type ReactRendererOptions, type ResolvedColors, type ResolvedTheme, Scroll, Select, Sheet, Skeleton, Spinner, Stack, Switch, Tab, Tabs, Text, TextArea, Toast, View, type Wrapper, createReactRenderer, reactRenderer as default, resolveTheme, useTheme };
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ import { Scroll } from "./components/scroll.js";
22
22
  import { Sheet } from "./components/sheet.js";
23
23
  import { Select } from "./components/select.js";
24
24
  import { Skeleton } from "./components/skeleton.js";
25
+ import { Stack } from "./components/stack.js";
25
26
  import { Tab, Tabs } from "./components/tabs.js";
26
27
  import { Text } from "./components/text.js";
27
28
  import { TextArea } from "./components/text-area.js";
@@ -32,4 +33,4 @@ import { createReactRenderer, reactRenderer } from "./renderer.js";
32
33
  //#region src/index.ts
33
34
  var src_default = reactRenderer;
34
35
  //#endregion
35
- export { AmountInput, Badge, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, QRCode, Radio, RadioGroup, Scroll, Select, Sheet, Skeleton, Spinner, Switch, Tab, Tabs, Text, TextArea, Toast, View, createReactRenderer, src_default as default, resolveTheme, useTheme };
36
+ export { AmountInput, Badge, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, QRCode, Radio, RadioGroup, Scroll, Select, Sheet, Skeleton, Spinner, Stack, Switch, Tab, Tabs, Text, TextArea, Toast, View, createReactRenderer, src_default as default, resolveTheme, useTheme };
package/dist/theme.d.ts CHANGED
@@ -17,6 +17,7 @@ export interface ResolvedColors {
17
17
  export interface ResolvedTheme {
18
18
  scheme: ColorScheme;
19
19
  colors: ResolvedColors;
20
+ customColors: Readonly<Record<string, string>>;
20
21
  shape: ThemeShape;
21
22
  radius: number;
22
23
  }
package/dist/theme.js CHANGED
@@ -55,10 +55,19 @@ function resolveTheme(theme, systemScheme) {
55
55
  surface,
56
56
  text
57
57
  },
58
+ customColors: resolveCustomColors(colors.custom ?? {}, scheme),
58
59
  shape,
59
60
  radius: SHAPE_RADIUS[shape]
60
61
  };
61
62
  }
63
+ function resolveCustomColors(custom, scheme) {
64
+ const resolved = {};
65
+ for (const [name, color] of Object.entries(custom)) {
66
+ const value = color[scheme] ?? color.light ?? color.dark;
67
+ if (value) resolved[name] = value;
68
+ }
69
+ return resolved;
70
+ }
62
71
  function primaryAndOnPrimary(primary, surface, text, scheme) {
63
72
  if (contrast(primary, surface) >= 4.5) return {
64
73
  primary,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monimesl/dot-renderer-react",
3
- "version": "0.1.0-alpha.14",
3
+ "version": "0.1.0-alpha.16",
4
4
  "description": "React renderer for Dot webviews",
5
5
  "type": "module",
6
6
  "repository": {
@@ -29,8 +29,8 @@
29
29
  "react": "^19.3.0",
30
30
  "react-dom": "^19.3.0",
31
31
  "uqr": "^0.1.3",
32
- "@monimesl/dot-core": "0.1.0-alpha.14",
33
- "@monimesl/dot-webview": "0.1.0-alpha.14"
32
+ "@monimesl/dot-webview": "0.1.0-alpha.16",
33
+ "@monimesl/dot-core": "0.1.0-alpha.16"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@base-ui/react": "1.8.0",
@@ -45,7 +45,7 @@
45
45
  "tsdown": "^0.23.0",
46
46
  "typescript": "^5.9.3",
47
47
  "vitest": "^5.0.1",
48
- "@monimesl/dot-service": "0.1.0-alpha.14"
48
+ "@monimesl/dot-service": "0.1.0-alpha.16"
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public"