@monimesl/dot-renderer-react 0.1.0-alpha.9 → 1.0.0-beta.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.
Files changed (61) hide show
  1. package/README.md +24 -20
  2. package/dist/color.js +25 -36
  3. package/dist/components/amount-input.js +26 -21
  4. package/dist/components/avatar.d.ts +6 -0
  5. package/dist/components/avatar.js +68 -0
  6. package/dist/components/box.js +56 -0
  7. package/dist/components/carousel.js +70 -66
  8. package/dist/components/code-input.js +6 -7
  9. package/dist/components/disclosure.d.ts +6 -0
  10. package/dist/components/disclosure.js +76 -0
  11. package/dist/components/empty-state.js +2 -4
  12. package/dist/components/feedback.js +39 -23
  13. package/dist/components/footer.js +3 -2
  14. package/dist/components/grid.js +4 -5
  15. package/dist/components/https.js +11 -0
  16. package/dist/components/icon-artwork.js +139 -70
  17. package/dist/components/icon-button.js +28 -0
  18. package/dist/components/icon-svg.js +27 -0
  19. package/dist/components/icon.js +5 -20
  20. package/dist/components/index.d.ts +9 -1
  21. package/dist/components/index.js +22 -2
  22. package/dist/components/input.js +24 -2
  23. package/dist/components/link.js +1 -8
  24. package/dist/components/list.js +17 -17
  25. package/dist/components/numbers.js +9 -0
  26. package/dist/components/option.js +4 -3
  27. package/dist/components/padding.js +18 -7
  28. package/dist/components/prose-context.js +5 -0
  29. package/dist/components/prose.d.ts +9 -0
  30. package/dist/components/prose.js +67 -0
  31. package/dist/components/rich-text.d.ts +6 -0
  32. package/dist/components/rich-text.js +73 -0
  33. package/dist/components/scroll.js +27 -25
  34. package/dist/components/select.js +4 -3
  35. package/dist/components/sheet.js +9 -8
  36. package/dist/components/slider.d.ts +6 -0
  37. package/dist/components/slider.js +57 -0
  38. package/dist/components/stack.d.ts +6 -0
  39. package/dist/components/stack.js +25 -0
  40. package/dist/components/stepper.d.ts +6 -0
  41. package/dist/components/stepper.js +92 -0
  42. package/dist/components/steps.d.ts +7 -0
  43. package/dist/components/steps.js +110 -0
  44. package/dist/components/tabs.js +23 -19
  45. package/dist/components/text.js +74 -13
  46. package/dist/components/toast.js +4 -4
  47. package/dist/components/toggles.js +6 -7
  48. package/dist/components/tokens.js +14 -2
  49. package/dist/components/tones.js +13 -7
  50. package/dist/components/typed-text.js +2 -2
  51. package/dist/components/view.js +19 -9
  52. package/dist/index.d.ts +9 -1
  53. package/dist/index.js +10 -2
  54. package/dist/markdown.js +255 -0
  55. package/dist/page-root.js +1 -1
  56. package/dist/pull-to-refresh.js +120 -0
  57. package/dist/root.js +31 -11
  58. package/dist/styles.css +1 -95
  59. package/dist/theme.d.ts +3 -2
  60. package/dist/theme.js +60 -15
  61. package/package.json +8 -7
@@ -1,5 +1,7 @@
1
1
  import { useTheme } from "../theme.js";
2
- import { CARD_RADIUS_SCALE, FONT_SIZE, ICON_SIZE, WEIGHTS } from "./tokens.js";
2
+ import { CARD_RADIUS_SCALE, CENTERED, FONT_SIZE, ICON_SIZE, WEIGHTS } from "./tokens.js";
3
+ import { CHEVRON_RIGHT_ARTWORK } from "./icon-artwork.js";
4
+ import { IconSvg } from "./icon-svg.js";
3
5
  import { insets, paddingStyle } from "./padding.js";
4
6
  import { IconGraphic } from "./icon.js";
5
7
  import { createEvent } from "@monimesl/dot-core";
@@ -9,22 +11,22 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
11
  const END_MARGIN = "0px 0px 200px 0px";
10
12
  const List$1 = ({ onEndReached, children, ...padding }) => {
11
13
  const { colors, radius } = useTheme();
12
- const list = useRef(null);
13
- const reachedAt = useRef(null);
14
+ const listRef = useRef(null);
15
+ const lastRowReached = useRef(null);
14
16
  useEffect(() => {
15
- const last = list.current?.lastElementChild;
16
- if (!onEndReached || !last || typeof IntersectionObserver === "undefined") return;
17
+ const lastRow = listRef.current?.lastElementChild;
18
+ if (!onEndReached || !lastRow || typeof IntersectionObserver === "undefined") return;
17
19
  const observer = new IntersectionObserver((entries) => {
18
- if (entries.some((entry) => entry.isIntersecting) && reachedAt.current !== last) {
19
- reachedAt.current = last;
20
+ if (entries.some((entry) => entry.isIntersecting) && lastRowReached.current !== lastRow) {
21
+ lastRowReached.current = lastRow;
20
22
  onEndReached(createEvent("endReached"));
21
23
  }
22
24
  }, { rootMargin: END_MARGIN });
23
- observer.observe(last);
25
+ observer.observe(lastRow);
24
26
  return () => observer.disconnect();
25
27
  });
26
28
  return /* @__PURE__ */ jsx("ul", {
27
- ref: list,
29
+ ref: listRef,
28
30
  className: "dot-list",
29
31
  style: {
30
32
  display: "flex",
@@ -57,9 +59,7 @@ const ListItem$1 = ({ title, subtitle, value, icon, image, onTap, children, ...p
57
59
  });
58
60
  else if (icon) leading = /* @__PURE__ */ jsx("span", {
59
61
  style: {
60
- display: "flex",
61
- alignItems: "center",
62
- justifyContent: "center",
62
+ ...CENTERED,
63
63
  width: 36,
64
64
  height: 36,
65
65
  borderRadius: "50%",
@@ -106,14 +106,14 @@ const ListItem$1 = ({ title, subtitle, value, icon, image, onTap, children, ...p
106
106
  flexShrink: 0,
107
107
  color: colors.subtle
108
108
  },
109
- children: [trailing, onTap ? /* @__PURE__ */ jsx(IconGraphic, {
110
- name: "chevron-right",
109
+ children: [trailing, onTap ? /* @__PURE__ */ jsx(IconSvg, {
110
+ artwork: CHEVRON_RIGHT_ARTWORK,
111
111
  size: ICON_SIZE.small,
112
112
  color: colors.subtle
113
113
  }) : null]
114
114
  }) : null
115
115
  ] });
116
- const row = {
116
+ const rowStyle = {
117
117
  display: "flex",
118
118
  alignItems: "center",
119
119
  gap: 12,
@@ -126,12 +126,12 @@ const ListItem$1 = ({ title, subtitle, value, icon, image, onTap, children, ...p
126
126
  };
127
127
  return /* @__PURE__ */ jsx("li", {
128
128
  className: "dot-list-item",
129
- style: onTap ? { background: colors.surface } : row,
129
+ style: onTap ? { background: colors.surface } : rowStyle,
130
130
  children: onTap ? /* @__PURE__ */ jsx("button", {
131
131
  type: "button",
132
132
  onClick: () => onTap(createEvent("tap")),
133
133
  style: {
134
- ...row,
134
+ ...rowStyle,
135
135
  border: "none",
136
136
  cursor: "pointer"
137
137
  },
@@ -0,0 +1,9 @@
1
+ //#region src/components/numbers.ts
2
+ function clamp(value, min, max) {
3
+ return Math.max(min, Math.min(value, max));
4
+ }
5
+ function wholeCount(count) {
6
+ return Math.max(1, Math.round(count));
7
+ }
8
+ //#endregion
9
+ export { clamp, wholeCount };
@@ -1,6 +1,7 @@
1
1
  import { useTheme } from "../theme.js";
2
2
  import { FONT_SIZE, ICON_SIZE, WEIGHTS } from "./tokens.js";
3
- import { IconGraphic } from "./icon.js";
3
+ import { CHECK_ARTWORK } from "./icon-artwork.js";
4
+ import { IconSvg } from "./icon-svg.js";
4
5
  import { OptionPlaceContext } from "./option-place.js";
5
6
  import { useContext } from "react";
6
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -32,8 +33,8 @@ const Option = ({ value, label }) => {
32
33
  textAlign: "start",
33
34
  cursor: "pointer"
34
35
  },
35
- children: [/* @__PURE__ */ jsx("span", { children: label }), chosen ? /* @__PURE__ */ jsx(IconGraphic, {
36
- name: "check",
36
+ children: [/* @__PURE__ */ jsx("span", { children: label }), chosen ? /* @__PURE__ */ jsx(IconSvg, {
37
+ artwork: CHECK_ARTWORK,
37
38
  size: ICON_SIZE.medium,
38
39
  color: colors.primary
39
40
  }) : null]
@@ -14,14 +14,25 @@ function insets(block, inline = block) {
14
14
  bottom: block
15
15
  };
16
16
  }
17
- function paddingStyle(props, own = NO_INSETS) {
18
- const side = (space, pixels) => space === void 0 ? pixels : SPACE[space];
17
+ function paddingStyle(props, ownInsets = NO_INSETS) {
19
18
  return {
20
- paddingTop: side(props.paddingTop ?? props.padding, own.top),
21
- paddingInlineStart: side(props.paddingStart ?? props.padding, own.start),
22
- paddingInlineEnd: side(props.paddingEnd ?? props.padding, own.end),
23
- paddingBottom: side(props.paddingBottom ?? props.padding, own.bottom)
19
+ paddingTop: sidePadding(props.paddingTop ?? props.padding, ownInsets.top),
20
+ paddingInlineStart: sidePadding(props.paddingStart ?? props.padding, ownInsets.start),
21
+ paddingInlineEnd: sidePadding(props.paddingEnd ?? props.padding, ownInsets.end),
22
+ paddingBottom: sidePadding(props.paddingBottom ?? props.padding, ownInsets.bottom)
23
+ };
24
+ }
25
+ function sidePadding(pageSpace, ownPixels) {
26
+ if (pageSpace === void 0) return ownPixels;
27
+ return SPACE[pageSpace];
28
+ }
29
+ const HOME_INDICATOR = "env(safe-area-inset-bottom, 0px)";
30
+ function pinnedPaddingStyle(props, ownInsets) {
31
+ const style = paddingStyle(props, ownInsets);
32
+ return {
33
+ ...style,
34
+ paddingBottom: `calc(${style.paddingBottom}px + ${HOME_INDICATOR})`
24
35
  };
25
36
  }
26
37
  //#endregion
27
- export { insets, paddingStyle };
38
+ export { HOME_INDICATOR, insets, paddingStyle, pinnedPaddingStyle };
@@ -0,0 +1,5 @@
1
+ import { createContext } from "react";
2
+ //#region src/components/prose-context.ts
3
+ const InsideProse = createContext(false);
4
+ //#endregion
5
+ export { InsideProse };
@@ -0,0 +1,9 @@
1
+ import { ReactComponent } from "../types.js";
2
+ import { Bullet, BulletList, Prose, Quote } from "@monimesl/dot-core";
3
+ //#region src/components/prose.d.ts
4
+ declare const Prose$1: ReactComponent<typeof Prose>;
5
+ declare const Quote$1: ReactComponent<typeof Quote>;
6
+ declare const BulletList$1: ReactComponent<typeof BulletList>;
7
+ declare const Bullet$1: ReactComponent<typeof Bullet>;
8
+ //#endregion
9
+ export { Bullet$1 as Bullet, BulletList$1 as BulletList, Prose$1 as Prose, Quote$1 as Quote };
@@ -0,0 +1,67 @@
1
+ import { useTheme } from "../theme.js";
2
+ import { FONT_SIZE, SELECTABLE } from "./tokens.js";
3
+ import { paddingStyle } from "./padding.js";
4
+ import { InsideProse } from "./prose-context.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/prose.tsx
7
+ const READING_WIDTH = 680;
8
+ const Prose = ({ children, ...padding }) => /* @__PURE__ */ jsx("div", {
9
+ className: "dot-prose",
10
+ style: {
11
+ display: "flex",
12
+ flexDirection: "column",
13
+ gap: 12,
14
+ width: "100%",
15
+ maxWidth: READING_WIDTH,
16
+ marginInline: "auto",
17
+ ...SELECTABLE,
18
+ ...paddingStyle(padding)
19
+ },
20
+ children: /* @__PURE__ */ jsx(InsideProse.Provider, {
21
+ value: true,
22
+ children
23
+ })
24
+ });
25
+ const Quote = ({ cite, children }) => {
26
+ const { colors } = useTheme();
27
+ return /* @__PURE__ */ jsxs("blockquote", {
28
+ className: "dot-quote",
29
+ style: {
30
+ display: "flex",
31
+ flexDirection: "column",
32
+ gap: 6,
33
+ margin: 0,
34
+ paddingInlineStart: 14,
35
+ borderInlineStart: `3px solid ${colors.subtle}`,
36
+ fontStyle: "italic"
37
+ },
38
+ children: [children, cite && /* @__PURE__ */ jsxs("span", {
39
+ style: {
40
+ fontSize: FONT_SIZE.caption,
41
+ fontStyle: "normal",
42
+ color: colors.subtle
43
+ },
44
+ children: ["— ", cite]
45
+ })]
46
+ });
47
+ };
48
+ const BulletList = ({ ordered, children }) => {
49
+ return /* @__PURE__ */ jsx(ordered ? "ol" : "ul", {
50
+ className: "dot-bullets",
51
+ style: {
52
+ display: "grid",
53
+ gap: 6,
54
+ margin: 0,
55
+ paddingInlineStart: 22,
56
+ listStyleType: ordered ? "decimal" : "disc"
57
+ },
58
+ children
59
+ });
60
+ };
61
+ const Bullet = ({ children }) => /* @__PURE__ */ jsx("li", {
62
+ className: "dot-bullet",
63
+ style: { display: "list-item" },
64
+ children
65
+ });
66
+ //#endregion
67
+ export { Bullet, BulletList, Prose, Quote };
@@ -0,0 +1,6 @@
1
+ import { ReactComponent } from "../types.js";
2
+ import { RichText } from "@monimesl/dot-core";
3
+ //#region src/components/rich-text.d.ts
4
+ declare const RichText$1: ReactComponent<typeof RichText>;
5
+ //#endregion
6
+ export { RichText$1 as RichText };
@@ -0,0 +1,73 @@
1
+ import { useTheme } from "../theme.js";
2
+ import { Divider } from "./divider.js";
3
+ import { Image } from "./image.js";
4
+ import { isHttps } from "./https.js";
5
+ import { Link } from "./link.js";
6
+ import { Bullet, BulletList, Prose, Quote } from "./prose.js";
7
+ import { parseMarkdown } from "../markdown.js";
8
+ import { Text } from "./text.js";
9
+ import { useMemo } from "react";
10
+ import { jsx } from "react/jsx-runtime";
11
+ //#region src/components/rich-text.tsx
12
+ const HEADING_TEXT = {
13
+ 1: { variant: "title" },
14
+ 2: { variant: "subtitle" },
15
+ 3: { weight: "bold" }
16
+ };
17
+ const RichText = ({ markdown }) => {
18
+ const blocks = useMemo(() => parseMarkdown(markdown ?? ""), [markdown]);
19
+ return /* @__PURE__ */ jsx(Prose, { children: blocks.map(renderBlock) });
20
+ };
21
+ function renderBlock(block, key) {
22
+ switch (block.kind) {
23
+ case "heading": return /* @__PURE__ */ jsx(Text, {
24
+ ...HEADING_TEXT[block.level],
25
+ children: block.content.map(renderInline)
26
+ }, key);
27
+ case "paragraph": return /* @__PURE__ */ jsx(Text, { children: block.content.map(renderInline) }, key);
28
+ case "list": return /* @__PURE__ */ jsx(BulletList, {
29
+ ordered: block.ordered,
30
+ children: block.items.map((item, itemKey) => /* @__PURE__ */ jsx(Bullet, { children: item.map(renderBlock) }, itemKey))
31
+ }, key);
32
+ case "quote": return /* @__PURE__ */ jsx(Quote, { children: block.blocks.map(renderBlock) }, key);
33
+ case "image": return /* @__PURE__ */ jsx(Image, {
34
+ src: block.src,
35
+ alt: block.alt
36
+ }, key);
37
+ case "rule": return /* @__PURE__ */ jsx(Divider, {}, key);
38
+ }
39
+ }
40
+ function renderInline(inline, key) {
41
+ switch (inline.kind) {
42
+ case "text": return inline.text;
43
+ case "strong": return /* @__PURE__ */ jsx(Text, {
44
+ weight: "bold",
45
+ children: inline.children.map(renderInline)
46
+ }, key);
47
+ case "emphasis": return /* @__PURE__ */ jsx(Text, {
48
+ italic: true,
49
+ children: inline.children.map(renderInline)
50
+ }, key);
51
+ case "code": return /* @__PURE__ */ jsx(Code, { text: inline.text }, key);
52
+ case "link": return isHttps(inline.href) ? /* @__PURE__ */ jsx(Link, {
53
+ href: inline.href,
54
+ children: inline.children.map(renderInline)
55
+ }, key) : inline.children.map(renderInline);
56
+ case "break": return /* @__PURE__ */ jsx("br", {}, key);
57
+ }
58
+ }
59
+ function Code({ text }) {
60
+ const { colors } = useTheme();
61
+ return /* @__PURE__ */ jsx("code", {
62
+ style: {
63
+ padding: "1px 4px",
64
+ borderRadius: 4,
65
+ background: colors.muted,
66
+ fontFamily: "ui-monospace, monospace",
67
+ fontSize: "0.9em"
68
+ },
69
+ children: text
70
+ });
71
+ }
72
+ //#endregion
73
+ export { RichText };
@@ -4,47 +4,49 @@ import { createEvent } from "@monimesl/dot-core";
4
4
  import { useEffect, useRef } from "react";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/components/scroll.tsx
7
- const REST_MS = 120;
7
+ const REST_DELAY_MS = 120;
8
8
  const Scroll$1 = ({ gap = "medium", snap = "none", index, onChange, children, ...padding }) => {
9
- const row = useRef(null);
10
- const reported = useRef(void 0);
11
- const resting = useRef(void 0);
12
- const space = paddingStyle(padding);
13
- const start = Number(space.paddingInlineStart);
9
+ const rowRef = useRef(null);
10
+ const reportedIndex = useRef(void 0);
11
+ const restTimer = useRef(void 0);
12
+ const paddingCss = paddingStyle(padding);
13
+ const startPadding = Number(paddingCss.paddingInlineStart);
14
14
  useEffect(() => {
15
- const element = row.current;
16
- if (index === void 0 || index === reported.current || !element) return;
15
+ const element = rowRef.current;
16
+ if (index === void 0 || index === reportedIndex.current || !element) return;
17
17
  const child = element.children[index];
18
18
  if (child) {
19
- reported.current = index;
19
+ reportedIndex.current = index;
20
20
  element.scrollTo?.({
21
- left: child.offsetLeft - start,
21
+ left: child.offsetLeft - startPadding,
22
22
  behavior: "smooth"
23
23
  });
24
24
  }
25
- }, [index, start]);
26
- useEffect(() => () => clearTimeout(resting.current), []);
25
+ }, [index, startPadding]);
26
+ useEffect(() => {
27
+ return () => clearTimeout(restTimer.current);
28
+ }, []);
27
29
  return /* @__PURE__ */ jsx("div", {
28
- ref: row,
30
+ ref: rowRef,
29
31
  className: "dot-scroll",
30
32
  onScroll: onChange ? () => {
31
- clearTimeout(resting.current);
32
- resting.current = setTimeout(() => {
33
- const element = row.current;
33
+ clearTimeout(restTimer.current);
34
+ restTimer.current = setTimeout(() => {
35
+ const element = rowRef.current;
34
36
  if (!element) return;
35
- const left = element.scrollLeft + start;
36
- const first = [...element.children].findIndex((item) => item.offsetLeft + item.offsetWidth / 2 >= left);
37
- if (first !== -1 && first !== reported.current) {
38
- reported.current = first;
39
- onChange(createEvent("change", { index: first }));
37
+ const visibleStart = element.scrollLeft + startPadding;
38
+ const firstShownIndex = [...element.children].findIndex((item) => item.offsetLeft + item.offsetWidth / 2 >= visibleStart);
39
+ if (firstShownIndex !== -1 && firstShownIndex !== reportedIndex.current) {
40
+ reportedIndex.current = firstShownIndex;
41
+ onChange(createEvent("change", { index: firstShownIndex }));
40
42
  }
41
- }, REST_MS);
43
+ }, REST_DELAY_MS);
42
44
  } : void 0,
43
45
  style: {
44
46
  gap: SPACE[gap],
45
- ...space,
46
- scrollPaddingInlineStart: space.paddingInlineStart,
47
- scrollPaddingInlineEnd: space.paddingInlineEnd,
47
+ ...paddingCss,
48
+ scrollPaddingInlineStart: paddingCss.paddingInlineStart,
49
+ scrollPaddingInlineEnd: paddingCss.paddingInlineEnd,
48
50
  scrollSnapType: snap === "none" ? void 0 : "x mandatory",
49
51
  "--dot-scroll-snap": snap === "none" ? "none" : snap
50
52
  },
@@ -2,7 +2,8 @@ import { useTheme } from "../theme.js";
2
2
  import { ICON_SIZE, SPACE } from "./tokens.js";
3
3
  import { Field } from "./field.js";
4
4
  import { useFieldBox, useFieldNote } from "./field-box.js";
5
- import { IconGraphic } from "./icon.js";
5
+ import { CHEVRON_DOWN_ARTWORK } from "./icon-artwork.js";
6
+ import { IconSvg } from "./icon-svg.js";
6
7
  import { OptionPlaceContext } from "./option-place.js";
7
8
  import { SheetPanel } from "./sheet.js";
8
9
  import { createEvent } from "@monimesl/dot-core";
@@ -60,8 +61,8 @@ const Select$1 = ({ value, label, placeholder, hint, error, disabled, onChange,
60
61
  style: { color: colors.subtle },
61
62
  children: placeholder
62
63
  })
63
- }), /* @__PURE__ */ jsx(IconGraphic, {
64
- name: "chevron-down",
64
+ }), /* @__PURE__ */ jsx(IconSvg, {
65
+ artwork: CHEVRON_DOWN_ARTWORK,
65
66
  size: ICON_SIZE.small,
66
67
  color: colors.subtle
67
68
  })]
@@ -1,7 +1,8 @@
1
1
  import { FONT_FAMILY, useTheme } from "../theme.js";
2
2
  import { CARD_RADIUS_SCALE, FONT_SIZE, ICON_SIZE, SPACE, WEIGHTS } from "./tokens.js";
3
- import { paddingStyle } from "./padding.js";
4
- import { IconGraphic } from "./icon.js";
3
+ import { CLOSE_ARTWORK } from "./icon-artwork.js";
4
+ import { IconSvg } from "./icon-svg.js";
5
+ import { pinnedPaddingStyle } from "./padding.js";
5
6
  import { DialogBackdrop } from "../vendor/@base-ui/react/dialog/backdrop/DialogBackdrop.js";
6
7
  import { DialogClose } from "../vendor/@base-ui/react/dialog/close/DialogClose.js";
7
8
  import { DialogPopup } from "../vendor/@base-ui/react/dialog/popup/DialogPopup.js";
@@ -15,7 +16,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
15
16
  const SheetPanel = ({ open, title, showCloseIcon = false, onClose, children, ...padding }) => {
16
17
  const { colors, radius } = useTheme();
17
18
  const container = usePortalContainer();
18
- const corner = radius * CARD_RADIUS_SCALE;
19
+ const cornerRadius = radius * CARD_RADIUS_SCALE;
19
20
  return /* @__PURE__ */ jsx(DialogRoot, {
20
21
  open,
21
22
  onOpenChange: (next) => {
@@ -44,14 +45,14 @@ const SheetPanel = ({ open, title, showCloseIcon = false, onClose, children, ...
44
45
  gap: SPACE.medium,
45
46
  maxHeight: "85vh",
46
47
  overflowY: "auto",
47
- ...paddingStyle(padding, {
48
+ ...pinnedPaddingStyle(padding, {
48
49
  top: 16,
49
50
  start: 16,
50
51
  end: 16,
51
52
  bottom: 24
52
53
  }),
53
- borderTopLeftRadius: corner,
54
- borderTopRightRadius: corner,
54
+ borderTopLeftRadius: cornerRadius,
55
+ borderTopRightRadius: cornerRadius,
55
56
  background: colors.surface,
56
57
  color: colors.text,
57
58
  fontFamily: FONT_FAMILY,
@@ -81,8 +82,8 @@ const SheetPanel = ({ open, title, showCloseIcon = false, onClose, children, ...
81
82
  background: "transparent",
82
83
  cursor: "pointer"
83
84
  },
84
- children: /* @__PURE__ */ jsx(IconGraphic, {
85
- name: "close",
85
+ children: /* @__PURE__ */ jsx(IconSvg, {
86
+ artwork: CLOSE_ARTWORK,
86
87
  size: ICON_SIZE.medium,
87
88
  color: colors.subtle
88
89
  })
@@ -0,0 +1,6 @@
1
+ import { ReactComponent } from "../types.js";
2
+ import { Slider } from "@monimesl/dot-core";
3
+ //#region src/components/slider.d.ts
4
+ declare const Slider$1: ReactComponent<typeof Slider>;
5
+ //#endregion
6
+ export { Slider$1 as Slider };
@@ -0,0 +1,57 @@
1
+ import { useTheme } from "../theme.js";
2
+ import { DISABLED_OPACITY, FONT_SIZE } from "./tokens.js";
3
+ import { Field, FieldLabel } from "./field.js";
4
+ import { useFieldNote } from "./field-box.js";
5
+ import { useTypedText } from "./typed-text.js";
6
+ import { createEvent } from "@monimesl/dot-core";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/components/slider.tsx
9
+ const Slider$1 = ({ value, min = 0, max = 100, step = 1, showValue, label, hint, disabled, onChange }) => {
10
+ const { colors } = useTheme();
11
+ const [positionText, showPosition] = useTypedText(value === void 0 ? void 0 : String(value), onChange !== void 0);
12
+ const { noteId, controlAttributes } = useFieldNote(hint, void 0);
13
+ const shownValue = positionText === "" ? String(min) : positionText;
14
+ return /* @__PURE__ */ jsxs(Field, {
15
+ label: void 0,
16
+ hint,
17
+ error: void 0,
18
+ noteId,
19
+ children: [label || showValue ? /* @__PURE__ */ jsxs("span", {
20
+ style: {
21
+ display: "flex",
22
+ justifyContent: "space-between"
23
+ },
24
+ children: [/* @__PURE__ */ jsx(FieldLabel, { children: label }), showValue ? /* @__PURE__ */ jsx("span", {
25
+ style: {
26
+ fontSize: FONT_SIZE.caption,
27
+ color: colors.subtle,
28
+ fontVariantNumeric: "tabular-nums"
29
+ },
30
+ children: shownValue
31
+ }) : null]
32
+ }) : null, /* @__PURE__ */ jsx("input", {
33
+ className: "dot-slider",
34
+ type: "range",
35
+ min,
36
+ max,
37
+ step,
38
+ value: shownValue,
39
+ disabled,
40
+ "aria-label": label,
41
+ ...controlAttributes,
42
+ onChange: (event) => {
43
+ const next = event.currentTarget.value;
44
+ showPosition(next);
45
+ onChange?.(createEvent("change", { value: Number(next) }));
46
+ },
47
+ style: {
48
+ width: "100%",
49
+ margin: 0,
50
+ accentColor: colors.primary,
51
+ opacity: disabled ? DISABLED_OPACITY : 1
52
+ }
53
+ })]
54
+ });
55
+ };
56
+ //#endregion
57
+ export { Slider$1 as Slider };
@@ -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 };
@@ -0,0 +1,6 @@
1
+ import { ReactComponent } from "../types.js";
2
+ import { Stepper } from "@monimesl/dot-core";
3
+ //#region src/components/stepper.d.ts
4
+ declare const Stepper$1: ReactComponent<typeof Stepper>;
5
+ //#endregion
6
+ export { Stepper$1 as Stepper };
@@ -0,0 +1,92 @@
1
+ import { useTheme } from "../theme.js";
2
+ import { CENTERED, DISABLED_OPACITY, FONT_SIZE, ICON_SIZE, WEIGHTS } from "./tokens.js";
3
+ import { Field } from "./field.js";
4
+ import { useFieldNote } from "./field-box.js";
5
+ import { useTypedText } from "./typed-text.js";
6
+ import { IconGraphic } from "./icon.js";
7
+ import { createEvent } from "@monimesl/dot-core";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/components/stepper.tsx
10
+ const Stepper$1 = ({ value, min, max, step = 1, label, hint, disabled, onChange }) => {
11
+ const { colors } = useTheme();
12
+ const [shownText, showText] = useTypedText(value === void 0 ? void 0 : String(value), onChange !== void 0);
13
+ const { noteId, controlAttributes } = useFieldNote(hint, void 0);
14
+ const current = shownText === "" ? min ?? 0 : Number(shownText);
15
+ const moveTo = (next) => {
16
+ showText(String(next));
17
+ onChange?.(createEvent("change", { value: next }));
18
+ };
19
+ const atMin = min !== void 0 && current - step < min;
20
+ const atMax = max !== void 0 && current + step > max;
21
+ return /* @__PURE__ */ jsx(Field, {
22
+ label,
23
+ hint,
24
+ error: void 0,
25
+ noteId,
26
+ children: /* @__PURE__ */ jsxs("span", {
27
+ className: "dot-stepper",
28
+ role: "group",
29
+ "aria-label": label,
30
+ ...controlAttributes,
31
+ style: {
32
+ display: "flex",
33
+ alignItems: "center",
34
+ gap: 12,
35
+ width: "fit-content"
36
+ },
37
+ children: [
38
+ /* @__PURE__ */ jsx(StepButton, {
39
+ icon: "minus",
40
+ label: "Less",
41
+ disabled: disabled || atMin,
42
+ onPress: () => moveTo(current - step)
43
+ }),
44
+ /* @__PURE__ */ jsx("span", {
45
+ "aria-live": "polite",
46
+ style: {
47
+ minWidth: 32,
48
+ textAlign: "center",
49
+ fontSize: FONT_SIZE.subtitle,
50
+ fontWeight: WEIGHTS.bold,
51
+ fontVariantNumeric: "tabular-nums",
52
+ color: colors.text
53
+ },
54
+ children: current
55
+ }),
56
+ /* @__PURE__ */ jsx(StepButton, {
57
+ icon: "plus",
58
+ label: "More",
59
+ disabled: disabled || atMax,
60
+ onPress: () => moveTo(current + step)
61
+ })
62
+ ]
63
+ })
64
+ });
65
+ };
66
+ function StepButton({ icon, label, disabled, onPress }) {
67
+ const { colors, radius } = useTheme();
68
+ return /* @__PURE__ */ jsx("button", {
69
+ type: "button",
70
+ "aria-label": label,
71
+ disabled,
72
+ onClick: onPress,
73
+ style: {
74
+ ...CENTERED,
75
+ width: 40,
76
+ height: 40,
77
+ border: "none",
78
+ borderRadius: radius,
79
+ background: colors.muted,
80
+ color: colors.text,
81
+ opacity: disabled ? DISABLED_OPACITY : 1,
82
+ cursor: disabled ? "default" : "pointer"
83
+ },
84
+ children: /* @__PURE__ */ jsx(IconGraphic, {
85
+ name: icon,
86
+ size: ICON_SIZE.medium,
87
+ color: "currentColor"
88
+ })
89
+ });
90
+ }
91
+ //#endregion
92
+ export { Stepper$1 as Stepper };
@@ -0,0 +1,7 @@
1
+ import { ReactComponent } from "../types.js";
2
+ import { Step, Steps } from "@monimesl/dot-core";
3
+ //#region src/components/steps.d.ts
4
+ declare const Steps$1: ReactComponent<typeof Steps>;
5
+ declare const Step$1: ReactComponent<typeof Step>;
6
+ //#endregion
7
+ export { Step$1 as Step, Steps$1 as Steps };