@monimesl/dot-renderer-react 0.1.0-alpha.19 → 0.1.0-alpha.21

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.
@@ -4,47 +4,47 @@ 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
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);
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
15
  const element = row.current;
16
- if (index === void 0 || index === reported.current || !element) return;
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(() => () => clearTimeout(restTimer.current), []);
27
27
  return /* @__PURE__ */ jsx("div", {
28
28
  ref: row,
29
29
  className: "dot-scroll",
30
30
  onScroll: onChange ? () => {
31
- clearTimeout(resting.current);
32
- resting.current = setTimeout(() => {
31
+ clearTimeout(restTimer.current);
32
+ restTimer.current = setTimeout(() => {
33
33
  const element = row.current;
34
34
  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 }));
35
+ const visibleStart = element.scrollLeft + startPadding;
36
+ const firstHalfInView = [...element.children].findIndex((item) => item.offsetLeft + item.offsetWidth / 2 >= visibleStart);
37
+ if (firstHalfInView !== -1 && firstHalfInView !== reportedIndex.current) {
38
+ reportedIndex.current = firstHalfInView;
39
+ onChange(createEvent("change", { index: firstHalfInView }));
40
40
  }
41
- }, REST_MS);
41
+ }, REST_DELAY_MS);
42
42
  } : void 0,
43
43
  style: {
44
44
  gap: SPACE[gap],
45
- ...space,
46
- scrollPaddingInlineStart: space.paddingInlineStart,
47
- scrollPaddingInlineEnd: space.paddingInlineEnd,
45
+ ...paddingCss,
46
+ scrollPaddingInlineStart: paddingCss.paddingInlineStart,
47
+ scrollPaddingInlineEnd: paddingCss.paddingInlineEnd,
48
48
  scrollSnapType: snap === "none" ? void 0 : "x mandatory",
49
49
  "--dot-scroll-snap": snap === "none" ? "none" : snap
50
50
  },
@@ -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 { CLOSE_ARTWORK } from "./icon-artwork.js";
4
+ import { IconSvg } from "./icon-svg.js";
3
5
  import { paddingStyle } from "./padding.js";
4
- import { IconGraphic } from "./icon.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";
@@ -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 { 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,94 @@
1
+ import { useTheme } from "../theme.js";
2
+ import { 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 [shown, show] = useTypedText(value === void 0 ? void 0 : String(value), onChange !== void 0);
13
+ const { noteId, controlAttributes } = useFieldNote(hint, void 0);
14
+ const current = shown === "" ? min ?? 0 : Number(shown);
15
+ const moveTo = (next) => {
16
+ show(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
+ display: "flex",
75
+ alignItems: "center",
76
+ justifyContent: "center",
77
+ width: 40,
78
+ height: 40,
79
+ border: "none",
80
+ borderRadius: radius,
81
+ background: colors.muted,
82
+ color: colors.text,
83
+ opacity: disabled ? DISABLED_OPACITY : 1,
84
+ cursor: disabled ? "default" : "pointer"
85
+ },
86
+ children: /* @__PURE__ */ jsx(IconGraphic, {
87
+ name: icon,
88
+ size: ICON_SIZE.medium,
89
+ color: "currentColor"
90
+ })
91
+ });
92
+ }
93
+ //#endregion
94
+ 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 };
@@ -0,0 +1,112 @@
1
+ import { useTheme } from "../theme.js";
2
+ import { FONT_SIZE, WEIGHTS } from "./tokens.js";
3
+ import { paddingStyle } from "./padding.js";
4
+ import { IconGraphic } from "./icon.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/steps.tsx
7
+ const MARK_SIZE = 24;
8
+ const Steps = ({ children, ...padding }) => /* @__PURE__ */ jsx("ol", {
9
+ className: "dot-steps",
10
+ style: {
11
+ display: "flex",
12
+ flexDirection: "column",
13
+ margin: 0,
14
+ ...paddingStyle(padding)
15
+ },
16
+ children
17
+ });
18
+ function mark(colors, status) {
19
+ switch (status) {
20
+ case "done": return {
21
+ background: colors.success,
22
+ border: colors.success,
23
+ icon: "check"
24
+ };
25
+ case "failed": return {
26
+ background: colors.danger,
27
+ border: colors.danger,
28
+ icon: "close"
29
+ };
30
+ case "current": return {
31
+ background: colors.primary,
32
+ border: colors.primary,
33
+ icon: void 0
34
+ };
35
+ case "upcoming": return {
36
+ background: "transparent",
37
+ border: colors.subtle,
38
+ icon: void 0
39
+ };
40
+ }
41
+ }
42
+ const Step = ({ title, text, status = "upcoming" }) => {
43
+ const { colors } = useTheme();
44
+ const { background, border, icon } = mark(colors, status);
45
+ return /* @__PURE__ */ jsxs("li", {
46
+ className: "dot-step",
47
+ "aria-current": status === "current" ? "step" : void 0,
48
+ style: {
49
+ display: "flex",
50
+ gap: 12,
51
+ listStyle: "none"
52
+ },
53
+ children: [/* @__PURE__ */ jsxs("span", {
54
+ style: {
55
+ display: "flex",
56
+ flexDirection: "column",
57
+ alignItems: "center"
58
+ },
59
+ children: [/* @__PURE__ */ jsx("span", {
60
+ style: {
61
+ display: "flex",
62
+ alignItems: "center",
63
+ justifyContent: "center",
64
+ flexShrink: 0,
65
+ width: MARK_SIZE,
66
+ height: MARK_SIZE,
67
+ boxSizing: "border-box",
68
+ borderRadius: "50%",
69
+ border: `2px solid ${border}`,
70
+ background
71
+ },
72
+ children: icon ? /* @__PURE__ */ jsx(IconGraphic, {
73
+ name: icon,
74
+ size: 14,
75
+ color: "#ffffff"
76
+ }) : null
77
+ }), /* @__PURE__ */ jsx("span", {
78
+ className: "dot-step-line",
79
+ style: {
80
+ flex: 1,
81
+ width: 2,
82
+ minHeight: 12,
83
+ background: colors.border
84
+ }
85
+ })]
86
+ }), /* @__PURE__ */ jsxs("span", {
87
+ style: {
88
+ display: "flex",
89
+ flexDirection: "column",
90
+ gap: 2,
91
+ paddingBottom: 16
92
+ },
93
+ children: [/* @__PURE__ */ jsx("span", {
94
+ style: {
95
+ fontSize: FONT_SIZE.body,
96
+ fontWeight: status === "current" ? WEIGHTS.bold : WEIGHTS.medium,
97
+ color: status === "upcoming" ? colors.subtle : colors.text,
98
+ lineHeight: `${MARK_SIZE}px`
99
+ },
100
+ children: title
101
+ }), text ? /* @__PURE__ */ jsx("span", {
102
+ style: {
103
+ fontSize: FONT_SIZE.caption,
104
+ color: colors.subtle
105
+ },
106
+ children: text
107
+ }) : null]
108
+ })]
109
+ });
110
+ };
111
+ //#endregion
112
+ export { Step, Steps };
@@ -1,10 +1,9 @@
1
1
  import { useTheme } from "../theme.js";
2
2
  import { FONT_SIZE, SELECTABLE, WEIGHTS } from "./tokens.js";
3
3
  import { paddingStyle } from "./padding.js";
4
- import { toneColor } from "./tones.js";
4
+ import { isTone, toneColor } from "./tones.js";
5
5
  import { InsideProse } from "./prose-context.js";
6
6
  import { customColor } from "./box.js";
7
- import { TONES } from "@monimesl/dot-core";
8
7
  import { createContext, useContext } from "react";
9
8
  import { jsx } from "react/jsx-runtime";
10
9
  //#region src/components/text.tsx
@@ -51,7 +50,7 @@ const DECORATION = {
51
50
  underline: "underline",
52
51
  strikethrough: "line-through"
53
52
  };
54
- const Text$1 = ({ variant = "body", tone, weight, align, maxLines, decoration, numeric, leading, italic, selectable, children, ...padding }) => {
53
+ const Text = ({ variant = "body", tone, weight, align, maxLines, decoration, numeric, leading, italic, selectable, children, ...padding }) => {
55
54
  const theme = useTheme();
56
55
  const nested = useContext(InsideText);
57
56
  const inProse = useContext(InsideProse);
@@ -99,10 +98,9 @@ const Text$1 = ({ variant = "body", tone, weight, align, maxLines, decoration, n
99
98
  children: content
100
99
  });
101
100
  };
102
- const THEME_TONES = new Set(TONES);
103
101
  function textColor(tone, theme) {
104
- if (THEME_TONES.has(tone)) return toneColor(theme.colors, tone);
102
+ if (isTone(tone)) return toneColor(theme.colors, tone);
105
103
  return tone === "onPrimary" ? theme.colors.onPrimary : customColor(tone, theme);
106
104
  }
107
105
  //#endregion
108
- export { Text$1 as Text };
106
+ export { Text };
@@ -1,7 +1,7 @@
1
1
  import { useTheme } from "../theme.js";
2
2
  import { FONT_SIZE, ICON_SIZE, SPACE } from "./tokens.js";
3
- import { STATUS_ICONS } from "./tones.js";
4
- import { IconGraphic } from "./icon.js";
3
+ import { IconSvg } from "./icon-svg.js";
4
+ import { STATUS_ARTWORK } from "./tones.js";
5
5
  import { createEvent } from "@monimesl/dot-core";
6
6
  import { useEffect, useEffectEvent, useState } from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -45,8 +45,8 @@ const Toast$1 = ({ message, tone = "default", duration = 2500, onHide }) => {
45
45
  fontSize: FONT_SIZE.body,
46
46
  boxShadow: "0 4px 16px rgba(0, 0, 0, 0.2)"
47
47
  },
48
- children: [tone === "default" ? null : /* @__PURE__ */ jsx(IconGraphic, {
49
- name: STATUS_ICONS[tone],
48
+ children: [tone === "default" ? null : /* @__PURE__ */ jsx(IconSvg, {
49
+ artwork: STATUS_ARTWORK[tone],
50
50
  size: ICON_SIZE.medium,
51
51
  color: colors.onPrimary
52
52
  }), /* @__PURE__ */ jsx("span", { children: message })]
@@ -1,7 +1,8 @@
1
1
  import { useTheme } from "../theme.js";
2
2
  import { DISABLED_OPACITY, FONT_SIZE, ICON_SIZE, SPACE } from "./tokens.js";
3
3
  import { FieldLabel } from "./field.js";
4
- import { IconGraphic } from "./icon.js";
4
+ import { CHECK_ARTWORK } from "./icon-artwork.js";
5
+ import { IconSvg } from "./icon-svg.js";
5
6
  import { CheckboxRoot } from "../vendor/@base-ui/react/checkbox/root/CheckboxRoot.js";
6
7
  import { CheckboxIndicator } from "../vendor/@base-ui/react/checkbox/indicator/CheckboxIndicator.js";
7
8
  import { RadioRoot } from "../vendor/@base-ui/react/radio/root/RadioRoot.js";
@@ -94,8 +95,8 @@ const Checkbox$1 = ({ checked = false, label, disabled, onChange }) => {
94
95
  checked,
95
96
  children: /* @__PURE__ */ jsx(CheckboxIndicator, {
96
97
  style: { display: "flex" },
97
- children: /* @__PURE__ */ jsx(IconGraphic, {
98
- name: "check",
98
+ children: /* @__PURE__ */ jsx(IconSvg, {
99
+ artwork: CHECK_ARTWORK,
99
100
  size: ICON_SIZE.small,
100
101
  color: colors.onPrimary
101
102
  })
@@ -1,10 +1,16 @@
1
+ import { ERROR_ARTWORK, INFO_ARTWORK, SUCCESS_ARTWORK, WARNING_ARTWORK } from "./icon-artwork.js";
2
+ import { TONES } from "@monimesl/dot-core";
1
3
  //#region src/components/tones.ts
2
- const STATUS_ICONS = {
3
- default: "info",
4
- info: "info",
5
- success: "success",
6
- warning: "warning",
7
- danger: "error"
4
+ const TONE_WORDS = new Set(TONES);
5
+ function isTone(word) {
6
+ return TONE_WORDS.has(word);
7
+ }
8
+ const STATUS_ARTWORK = {
9
+ default: INFO_ARTWORK,
10
+ info: INFO_ARTWORK,
11
+ success: SUCCESS_ARTWORK,
12
+ warning: WARNING_ARTWORK,
13
+ danger: ERROR_ARTWORK
8
14
  };
9
15
  function toneColor(colors, tone) {
10
16
  switch (tone) {
@@ -21,4 +27,4 @@ function withOpacity(color, opacity) {
21
27
  return `${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")}`;
22
28
  }
23
29
  //#endregion
24
- export { STATUS_ICONS, toneBackground, toneColor };
30
+ export { STATUS_ARTWORK, isTone, toneBackground, toneColor };
@@ -6,8 +6,8 @@ function useTypedText(value, sendsChanges, show = (text) => text) {
6
6
  const [previousValue, setPreviousValue] = useState(value);
7
7
  if (value !== previousValue) {
8
8
  setPreviousValue(value);
9
- const echo = awaitingEcho.indexOf(value ?? "");
10
- if (echo >= 0) setAwaitingEcho(awaitingEcho.slice(echo + 1));
9
+ const echoIndex = awaitingEcho.indexOf(value ?? "");
10
+ if (echoIndex >= 0) setAwaitingEcho(awaitingEcho.slice(echoIndex + 1));
11
11
  else {
12
12
  setAwaitingEcho([]);
13
13
  setText(show(value ?? ""));
@@ -0,0 +1,6 @@
1
+ //#region src/components/utils.ts
2
+ function clamp(value, min, max) {
3
+ return Math.max(min, Math.min(value, max));
4
+ }
5
+ //#endregion
6
+ export { clamp };
package/dist/index.d.ts CHANGED
@@ -2,11 +2,13 @@ import { Wrapper } from "./root.js";
2
2
  import { BuiltinReactComponents, ReactComponent, ReactComponents } from "./types.js";
3
3
  import { CreateReactRendererOptions, ReactRendererOptions, createReactRenderer, reactRenderer } from "./renderer.js";
4
4
  import { AmountInput } from "./components/amount-input.js";
5
+ import { Avatar } from "./components/avatar.js";
5
6
  import { Button } from "./components/button.js";
6
7
  import { Carousel } from "./components/carousel.js";
7
8
  import { Chip } from "./components/chip.js";
8
9
  import { CodeInput } from "./components/code-input.js";
9
10
  import { DetailRow } from "./components/detail-row.js";
11
+ import { Disclosure } from "./components/disclosure.js";
10
12
  import { Divider } from "./components/divider.js";
11
13
  import { EmptyState } from "./components/empty-state.js";
12
14
  import { Badge, Notice, ProgressBar } from "./components/feedback.js";
@@ -28,6 +30,8 @@ import { Skeleton } from "./components/skeleton.js";
28
30
  import { Slider } from "./components/slider.js";
29
31
  import { Spinner } from "./components/spinner.js";
30
32
  import { Stack } from "./components/stack.js";
33
+ import { Step, Steps } from "./components/steps.js";
34
+ import { Stepper } from "./components/stepper.js";
31
35
  import { Tab, Tabs } from "./components/tabs.js";
32
36
  import { Text } from "./components/text.js";
33
37
  import { TextArea } from "./components/text-area.js";
@@ -36,4 +40,4 @@ import { Checkbox, Radio, RadioGroup, Switch } from "./components/toggles.js";
36
40
  import { View } from "./components/view.js";
37
41
  import "./components/index.js";
38
42
  import { ResolvedColors, ResolvedTheme, resolveTheme, useTheme } from "./theme.js";
39
- export { AmountInput, Badge, type BuiltinReactComponents, Bullet, BulletList, Button, Carousel, Checkbox, Chip, CodeInput, type CreateReactRendererOptions, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, Prose, QRCode, Quote, Radio, RadioGroup, type ReactComponent, type ReactComponents, type ReactRendererOptions, type ResolvedColors, type ResolvedTheme, RichText, Scroll, Select, Sheet, Skeleton, Slider, Spinner, Stack, Switch, Tab, Tabs, Text, TextArea, Toast, View, type Wrapper, createReactRenderer, reactRenderer as default, resolveTheme, useTheme };
43
+ export { AmountInput, Avatar, Badge, type BuiltinReactComponents, Bullet, BulletList, Button, Carousel, Checkbox, Chip, CodeInput, type CreateReactRendererOptions, DetailRow, Disclosure, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, Prose, QRCode, Quote, Radio, RadioGroup, type ReactComponent, type ReactComponents, type ReactRendererOptions, type ResolvedColors, type ResolvedTheme, RichText, Scroll, Select, Sheet, Skeleton, Slider, Spinner, Stack, Step, Stepper, Steps, Switch, Tab, Tabs, Text, TextArea, Toast, View, type Wrapper, createReactRenderer, reactRenderer as default, resolveTheme, useTheme };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { resolveTheme, useTheme } from "./theme.js";
2
2
  import { AmountInput } from "./components/amount-input.js";
3
+ import { Avatar } from "./components/avatar.js";
3
4
  import { Spinner } from "./components/spinner.js";
4
5
  import { Button } from "./components/button.js";
5
6
  import { Carousel } from "./components/carousel.js";
@@ -7,6 +8,7 @@ import { Icon } from "./components/icon.js";
7
8
  import { Chip } from "./components/chip.js";
8
9
  import { CodeInput } from "./components/code-input.js";
9
10
  import { DetailRow } from "./components/detail-row.js";
11
+ import { Disclosure } from "./components/disclosure.js";
10
12
  import { Divider } from "./components/divider.js";
11
13
  import { EmptyState } from "./components/empty-state.js";
12
14
  import { Badge, Notice, ProgressBar } from "./components/feedback.js";
@@ -27,6 +29,8 @@ import { Select } from "./components/select.js";
27
29
  import { Skeleton } from "./components/skeleton.js";
28
30
  import { Slider } from "./components/slider.js";
29
31
  import { Stack } from "./components/stack.js";
32
+ import { Step, Steps } from "./components/steps.js";
33
+ import { Stepper } from "./components/stepper.js";
30
34
  import { Tab, Tabs } from "./components/tabs.js";
31
35
  import { TextArea } from "./components/text-area.js";
32
36
  import { Toast } from "./components/toast.js";
@@ -36,4 +40,4 @@ import { createReactRenderer, reactRenderer } from "./renderer.js";
36
40
  //#region src/index.ts
37
41
  var src_default = reactRenderer;
38
42
  //#endregion
39
- export { AmountInput, Badge, Bullet, BulletList, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, Prose, QRCode, Quote, Radio, RadioGroup, RichText, Scroll, Select, Sheet, Skeleton, Slider, Spinner, Stack, Switch, Tab, Tabs, Text, TextArea, Toast, View, createReactRenderer, src_default as default, resolveTheme, useTheme };
43
+ export { AmountInput, Avatar, Badge, Bullet, BulletList, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Disclosure, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, Prose, QRCode, Quote, Radio, RadioGroup, RichText, Scroll, Select, Sheet, Skeleton, Slider, Spinner, Stack, Step, Stepper, Steps, Switch, Tab, Tabs, Text, TextArea, Toast, View, createReactRenderer, src_default as default, resolveTheme, useTheme };
@@ -0,0 +1,118 @@
1
+ import { useTheme } from "./theme.js";
2
+ import { LoadingIcon } from "./components/spinner.js";
3
+ import { useEffect, useRef, useState, useSyncExternalStore } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/pull-to-refresh.tsx
6
+ const PULL_DISTANCE = 64;
7
+ const RESISTANCE = .5;
8
+ const INDICATOR_SIZE = 36;
9
+ const DRAG_DISTANCE = 6;
10
+ function PullToRefresh({ page, children }) {
11
+ const { colors } = useTheme();
12
+ const refreshing = useSyncExternalStore(page.subscribeToRefreshing, page.isRefreshing);
13
+ const [pull, setPull] = useState(0);
14
+ const area = useRef(null);
15
+ useEffect(() => {
16
+ const element = area.current;
17
+ const view = element.ownerDocument.defaultView;
18
+ let startY;
19
+ let pulled = 0;
20
+ let dragged = false;
21
+ const begin = (y) => {
22
+ const atTop = view.scrollY <= 0;
23
+ startY = page.refreshable && atTop && !page.isRefreshing() ? y : void 0;
24
+ dragged = false;
25
+ };
26
+ const move = (y, event) => {
27
+ if (startY === void 0) return;
28
+ const distance = (y - startY) * RESISTANCE;
29
+ if (distance <= 0) {
30
+ pulled = 0;
31
+ setPull(0);
32
+ return;
33
+ }
34
+ if (event.cancelable) event.preventDefault();
35
+ if (distance > DRAG_DISTANCE) dragged = true;
36
+ pulled = Math.min(distance, PULL_DISTANCE * 1.5);
37
+ setPull(pulled);
38
+ };
39
+ const end = () => {
40
+ if (startY !== void 0 && pulled >= PULL_DISTANCE) page.refresh();
41
+ startY = void 0;
42
+ pulled = 0;
43
+ setPull(0);
44
+ };
45
+ const ignoreDragClick = (event) => {
46
+ if (dragged) {
47
+ dragged = false;
48
+ event.stopPropagation();
49
+ event.preventDefault();
50
+ }
51
+ };
52
+ const touchStart = (event) => begin(event.touches[0].clientY);
53
+ const touchMove = (event) => move(event.touches[0].clientY, event);
54
+ const mouseDown = (event) => {
55
+ if (event.button === 0) begin(event.clientY);
56
+ };
57
+ const mouseMove = (event) => move(event.clientY, event);
58
+ const stops = [
59
+ listen(element, "touchstart", touchStart, { passive: true }),
60
+ listen(element, "touchmove", touchMove, { passive: false }),
61
+ listen(element, "touchend", end),
62
+ listen(element, "touchcancel", end),
63
+ listen(element, "mousedown", mouseDown),
64
+ listen(element, "click", ignoreDragClick, { capture: true }),
65
+ listen(view, "mousemove", mouseMove),
66
+ listen(view, "mouseup", end)
67
+ ];
68
+ return () => stops.forEach((stop) => stop());
69
+ }, [page]);
70
+ const shown = refreshing ? PULL_DISTANCE : pull;
71
+ const ready = pull >= PULL_DISTANCE;
72
+ return /* @__PURE__ */ jsxs("div", {
73
+ ref: area,
74
+ className: "dot-pull-to-refresh",
75
+ style: { display: "contents" },
76
+ children: [children, shown > 0 ? /* @__PURE__ */ jsx("span", {
77
+ role: refreshing ? "status" : void 0,
78
+ "aria-label": refreshing ? "Refreshing" : void 0,
79
+ style: {
80
+ position: "fixed",
81
+ top: 0,
82
+ left: "50%",
83
+ zIndex: 2,
84
+ display: "flex",
85
+ alignItems: "center",
86
+ justifyContent: "center",
87
+ width: INDICATOR_SIZE,
88
+ height: INDICATOR_SIZE,
89
+ marginLeft: -18,
90
+ borderRadius: "50%",
91
+ background: colors.surface,
92
+ color: colors.primary,
93
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.2)",
94
+ transform: `translateY(${shown - INDICATOR_SIZE / 2}px)`,
95
+ transition: pull > 0 ? "none" : "transform 0.2s",
96
+ pointerEvents: "none"
97
+ },
98
+ children: refreshing ? /* @__PURE__ */ jsx(LoadingIcon, { size: 20 }) : /* @__PURE__ */ jsx("svg", {
99
+ width: 20,
100
+ height: 20,
101
+ viewBox: "0 0 24 24",
102
+ fill: "none",
103
+ stroke: "currentColor",
104
+ strokeWidth: 2.5,
105
+ strokeLinecap: "round",
106
+ strokeLinejoin: "round",
107
+ style: { transform: `rotate(${ready ? 180 : pull / PULL_DISTANCE * 180}deg)` },
108
+ children: /* @__PURE__ */ jsx("path", { d: "M12 5v14M6 13l6 6 6-6" })
109
+ })
110
+ }) : null]
111
+ });
112
+ }
113
+ function listen(target, type, listener, options) {
114
+ target.addEventListener(type, listener, options);
115
+ return () => target.removeEventListener(type, listener, options);
116
+ }
117
+ //#endregion
118
+ export { PullToRefresh };