@monimesl/dot-renderer-react 0.1.0-alpha.15 → 0.1.0-alpha.18
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/dist/components/box.js +59 -0
- package/dist/components/https.js +11 -0
- package/dist/components/index.d.ts +5 -1
- package/dist/components/index.js +13 -2
- package/dist/components/link.js +1 -8
- package/dist/components/prose-context.js +5 -0
- package/dist/components/prose.d.ts +9 -0
- package/dist/components/prose.js +67 -0
- package/dist/components/rich-text.d.ts +6 -0
- package/dist/components/rich-text.js +73 -0
- package/dist/components/slider.d.ts +6 -0
- package/dist/components/slider.js +57 -0
- package/dist/components/stack.d.ts +6 -0
- package/dist/components/stack.js +25 -0
- package/dist/components/text.js +73 -11
- package/dist/components/tokens.js +9 -2
- package/dist/components/view.js +12 -9
- package/dist/index.d.ts +5 -1
- package/dist/index.js +6 -2
- package/dist/markdown.js +226 -0
- package/dist/styles.css +1 -95
- package/dist/theme.d.ts +1 -0
- package/dist/theme.js +9 -0
- package/package.json +6 -5
|
@@ -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 };
|
|
@@ -15,16 +15,20 @@ import { Input } from "./input.js";
|
|
|
15
15
|
import { Link } from "./link.js";
|
|
16
16
|
import { List, ListItem } from "./list.js";
|
|
17
17
|
import { Option } from "./option.js";
|
|
18
|
+
import { Bullet, BulletList, Prose, Quote } from "./prose.js";
|
|
18
19
|
import { QRCode } from "./qr-code.js";
|
|
20
|
+
import { RichText } from "./rich-text.js";
|
|
19
21
|
import { Scroll } from "./scroll.js";
|
|
20
22
|
import { Select } from "./select.js";
|
|
21
23
|
import { Sheet } from "./sheet.js";
|
|
22
24
|
import { Skeleton } from "./skeleton.js";
|
|
25
|
+
import { Slider } from "./slider.js";
|
|
23
26
|
import { Spinner } from "./spinner.js";
|
|
27
|
+
import { Stack } from "./stack.js";
|
|
24
28
|
import { Tab, Tabs } from "./tabs.js";
|
|
25
29
|
import { Text } from "./text.js";
|
|
26
30
|
import { TextArea } from "./text-area.js";
|
|
27
31
|
import { Toast } from "./toast.js";
|
|
28
32
|
import { Checkbox, Radio, RadioGroup, Switch } from "./toggles.js";
|
|
29
33
|
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 };
|
|
34
|
+
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 };
|
package/dist/components/index.js
CHANGED
|
@@ -17,13 +17,17 @@ import { Input } from "./input.js";
|
|
|
17
17
|
import { Link } from "./link.js";
|
|
18
18
|
import { List, ListItem } from "./list.js";
|
|
19
19
|
import { Option } from "./option.js";
|
|
20
|
+
import { Bullet, BulletList, Prose, Quote } from "./prose.js";
|
|
20
21
|
import { QRCode } from "./qr-code.js";
|
|
22
|
+
import { Text } from "./text.js";
|
|
23
|
+
import { RichText } from "./rich-text.js";
|
|
21
24
|
import { Scroll } from "./scroll.js";
|
|
22
25
|
import { Sheet } from "./sheet.js";
|
|
23
26
|
import { Select } from "./select.js";
|
|
24
27
|
import { Skeleton } from "./skeleton.js";
|
|
28
|
+
import { Slider } from "./slider.js";
|
|
29
|
+
import { Stack } from "./stack.js";
|
|
25
30
|
import { Tab, Tabs } from "./tabs.js";
|
|
26
|
-
import { Text } from "./text.js";
|
|
27
31
|
import { TextArea } from "./text-area.js";
|
|
28
32
|
import { Toast } from "./toast.js";
|
|
29
33
|
import { Checkbox, Radio, RadioGroup, Switch } from "./toggles.js";
|
|
@@ -32,6 +36,8 @@ import { View } from "./view.js";
|
|
|
32
36
|
var components_exports = /* @__PURE__ */ __exportAll({
|
|
33
37
|
AmountInput: () => AmountInput,
|
|
34
38
|
Badge: () => Badge,
|
|
39
|
+
Bullet: () => Bullet,
|
|
40
|
+
BulletList: () => BulletList,
|
|
35
41
|
Button: () => Button,
|
|
36
42
|
Carousel: () => Carousel,
|
|
37
43
|
Checkbox: () => Checkbox,
|
|
@@ -52,14 +58,19 @@ var components_exports = /* @__PURE__ */ __exportAll({
|
|
|
52
58
|
Notice: () => Notice,
|
|
53
59
|
Option: () => Option,
|
|
54
60
|
ProgressBar: () => ProgressBar,
|
|
61
|
+
Prose: () => Prose,
|
|
55
62
|
QRCode: () => QRCode,
|
|
63
|
+
Quote: () => Quote,
|
|
56
64
|
Radio: () => Radio,
|
|
57
65
|
RadioGroup: () => RadioGroup,
|
|
66
|
+
RichText: () => RichText,
|
|
58
67
|
Scroll: () => Scroll,
|
|
59
68
|
Select: () => Select,
|
|
60
69
|
Sheet: () => Sheet,
|
|
61
70
|
Skeleton: () => Skeleton,
|
|
71
|
+
Slider: () => Slider,
|
|
62
72
|
Spinner: () => Spinner,
|
|
73
|
+
Stack: () => Stack,
|
|
63
74
|
Switch: () => Switch,
|
|
64
75
|
Tab: () => Tab,
|
|
65
76
|
Tabs: () => Tabs,
|
|
@@ -69,4 +80,4 @@ var components_exports = /* @__PURE__ */ __exportAll({
|
|
|
69
80
|
View: () => View
|
|
70
81
|
});
|
|
71
82
|
//#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 };
|
|
83
|
+
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, components_exports };
|
package/dist/components/link.js
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
import { useTheme } from "../theme.js";
|
|
2
2
|
import { toneColor } from "./tones.js";
|
|
3
3
|
import { pressable } from "./pressable.js";
|
|
4
|
+
import { isHttps } from "./https.js";
|
|
4
5
|
import { createEvent } from "@monimesl/dot-core";
|
|
5
6
|
import { jsx } from "react/jsx-runtime";
|
|
6
7
|
//#region src/components/link.tsx
|
|
7
|
-
function isHttps(href) {
|
|
8
|
-
if (!href) return false;
|
|
9
|
-
try {
|
|
10
|
-
return new URL(href).protocol === "https:";
|
|
11
|
-
} catch {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
8
|
const Link$1 = ({ href, tone, onTap, children }) => {
|
|
16
9
|
const { colors } = useTheme();
|
|
17
10
|
const style = {
|
|
@@ -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,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 };
|
|
@@ -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 [position, move] = useTypedText(value === void 0 ? void 0 : String(value), onChange !== void 0);
|
|
12
|
+
const { noteId, controlAttributes } = useFieldNote(hint, void 0);
|
|
13
|
+
const shown = position === "" ? String(min) : position;
|
|
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: shown
|
|
31
|
+
}) : null]
|
|
32
|
+
}) : null, /* @__PURE__ */ jsx("input", {
|
|
33
|
+
className: "dot-slider",
|
|
34
|
+
type: "range",
|
|
35
|
+
min,
|
|
36
|
+
max,
|
|
37
|
+
step,
|
|
38
|
+
value: shown,
|
|
39
|
+
disabled,
|
|
40
|
+
"aria-label": label,
|
|
41
|
+
...controlAttributes,
|
|
42
|
+
onChange: (event) => {
|
|
43
|
+
const next = event.currentTarget.value;
|
|
44
|
+
move(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,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 };
|
package/dist/components/text.js
CHANGED
|
@@ -1,26 +1,83 @@
|
|
|
1
1
|
import { useTheme } from "../theme.js";
|
|
2
|
-
import { FONT_SIZE, WEIGHTS } from "./tokens.js";
|
|
2
|
+
import { FONT_SIZE, SELECTABLE, WEIGHTS } from "./tokens.js";
|
|
3
3
|
import { paddingStyle } from "./padding.js";
|
|
4
4
|
import { toneColor } from "./tones.js";
|
|
5
|
+
import { InsideProse } from "./prose-context.js";
|
|
6
|
+
import { customColor } from "./box.js";
|
|
7
|
+
import { TONES } from "@monimesl/dot-core";
|
|
5
8
|
import { createContext, useContext } from "react";
|
|
6
9
|
import { jsx } from "react/jsx-runtime";
|
|
7
10
|
//#region src/components/text.tsx
|
|
8
11
|
const InsideText = createContext(false);
|
|
9
|
-
const
|
|
10
|
-
|
|
12
|
+
const VARIANTS = {
|
|
13
|
+
display: {
|
|
14
|
+
weight: "bold",
|
|
15
|
+
lineHeight: 1.15,
|
|
16
|
+
heading: true
|
|
17
|
+
},
|
|
18
|
+
title: {
|
|
19
|
+
weight: "bold",
|
|
20
|
+
lineHeight: 1.25,
|
|
21
|
+
heading: true
|
|
22
|
+
},
|
|
23
|
+
subtitle: {
|
|
24
|
+
weight: "medium",
|
|
25
|
+
lineHeight: 1.35,
|
|
26
|
+
heading: true
|
|
27
|
+
},
|
|
28
|
+
lead: {
|
|
29
|
+
weight: "regular",
|
|
30
|
+
lineHeight: 1.5,
|
|
31
|
+
heading: false
|
|
32
|
+
},
|
|
33
|
+
body: {
|
|
34
|
+
weight: "regular",
|
|
35
|
+
lineHeight: 1.5,
|
|
36
|
+
heading: false
|
|
37
|
+
},
|
|
38
|
+
caption: {
|
|
39
|
+
weight: "regular",
|
|
40
|
+
lineHeight: 1.4,
|
|
41
|
+
heading: false
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const LEADING_CHANGE = {
|
|
45
|
+
tight: -.1,
|
|
46
|
+
normal: 0,
|
|
47
|
+
relaxed: .2
|
|
48
|
+
};
|
|
49
|
+
const DECORATION = {
|
|
50
|
+
none: "none",
|
|
51
|
+
underline: "underline",
|
|
52
|
+
strikethrough: "line-through"
|
|
53
|
+
};
|
|
54
|
+
const Text$1 = ({ variant = "body", tone, weight, align, maxLines, decoration, numeric, leading, italic, selectable, children, ...padding }) => {
|
|
55
|
+
const theme = useTheme();
|
|
11
56
|
const nested = useContext(InsideText);
|
|
12
|
-
const
|
|
57
|
+
const inProse = useContext(InsideProse);
|
|
58
|
+
const { heading, lineHeight, weight: defaultWeight } = VARIANTS[variant];
|
|
59
|
+
const defaultLeading = inProse && !heading ? "relaxed" : "normal";
|
|
13
60
|
const style = {
|
|
14
61
|
display: nested ? "inline" : "block",
|
|
15
|
-
|
|
62
|
+
marginInline: 0,
|
|
63
|
+
marginBlockEnd: 0,
|
|
64
|
+
marginBlockStart: inProse && heading ? void 0 : 0,
|
|
16
65
|
fontSize: FONT_SIZE[variant],
|
|
17
|
-
lineHeight: "normal",
|
|
18
66
|
fontWeight: WEIGHTS[weight ?? defaultWeight],
|
|
19
|
-
|
|
20
|
-
|
|
67
|
+
fontStyle: italic ? "italic" : void 0,
|
|
68
|
+
letterSpacing: variant === "display" ? "-0.02em" : "normal",
|
|
69
|
+
color: tone ? textColor(tone, theme) : "inherit",
|
|
21
70
|
textAlign: align,
|
|
71
|
+
textDecorationLine: decoration ? DECORATION[decoration] : void 0,
|
|
72
|
+
fontVariantNumeric: numeric ? "tabular-nums" : void 0,
|
|
73
|
+
...selectable ? SELECTABLE : void 0,
|
|
22
74
|
...paddingStyle(padding)
|
|
23
75
|
};
|
|
76
|
+
if (!nested) {
|
|
77
|
+
style.lineHeight = lineHeight + LEADING_CHANGE[leading ?? defaultLeading];
|
|
78
|
+
style.textWrap = heading ? "balance" : "pretty";
|
|
79
|
+
style.overflowWrap = "anywhere";
|
|
80
|
+
}
|
|
24
81
|
if (maxLines) {
|
|
25
82
|
style.display = "-webkit-box";
|
|
26
83
|
style.WebkitLineClamp = maxLines;
|
|
@@ -31,8 +88,8 @@ const Text = ({ variant = "body", tone, weight, align, maxLines, children, ...pa
|
|
|
31
88
|
value: true,
|
|
32
89
|
children
|
|
33
90
|
});
|
|
34
|
-
if (variant === "title" && !nested) return /* @__PURE__ */ jsx("h2", {
|
|
35
|
-
className: "dot-text",
|
|
91
|
+
if ((variant === "title" || variant === "subtitle") && !nested) return /* @__PURE__ */ jsx(variant === "title" ? "h2" : "h3", {
|
|
92
|
+
className: "dot-text dot-heading",
|
|
36
93
|
style,
|
|
37
94
|
children: content
|
|
38
95
|
});
|
|
@@ -42,5 +99,10 @@ const Text = ({ variant = "body", tone, weight, align, maxLines, children, ...pa
|
|
|
42
99
|
children: content
|
|
43
100
|
});
|
|
44
101
|
};
|
|
102
|
+
const THEME_TONES = new Set(TONES);
|
|
103
|
+
function textColor(tone, theme) {
|
|
104
|
+
if (THEME_TONES.has(tone)) return toneColor(theme.colors, tone);
|
|
105
|
+
return tone === "onPrimary" ? theme.colors.onPrimary : customColor(tone, theme);
|
|
106
|
+
}
|
|
45
107
|
//#endregion
|
|
46
|
-
export { Text };
|
|
108
|
+
export { Text$1 as Text };
|
|
@@ -8,7 +8,10 @@ const SPACE = {
|
|
|
8
8
|
const FONT_SIZE = {
|
|
9
9
|
caption: 13,
|
|
10
10
|
body: 15,
|
|
11
|
-
|
|
11
|
+
lead: 17,
|
|
12
|
+
subtitle: 17,
|
|
13
|
+
title: 20,
|
|
14
|
+
display: 32
|
|
12
15
|
};
|
|
13
16
|
const WEIGHTS = {
|
|
14
17
|
regular: 400,
|
|
@@ -33,5 +36,9 @@ const PILL_STYLE = {
|
|
|
33
36
|
lineHeight: "16px",
|
|
34
37
|
textAlign: "center"
|
|
35
38
|
};
|
|
39
|
+
const SELECTABLE = {
|
|
40
|
+
userSelect: "text",
|
|
41
|
+
WebkitUserSelect: "text"
|
|
42
|
+
};
|
|
36
43
|
//#endregion
|
|
37
|
-
export { CARD_RADIUS_SCALE, DISABLED_OPACITY, FONT_SIZE, ICON_SIZE, PILL_STYLE, SPACE, WEIGHTS };
|
|
44
|
+
export { CARD_RADIUS_SCALE, DISABLED_OPACITY, FONT_SIZE, ICON_SIZE, PILL_STYLE, SELECTABLE, SPACE, WEIGHTS };
|
package/dist/components/view.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useTheme } from "../theme.js";
|
|
2
|
-
import {
|
|
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
|
|
21
|
-
|
|
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(
|
|
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
|
@@ -18,12 +18,16 @@ import { Input } from "./components/input.js";
|
|
|
18
18
|
import { Link } from "./components/link.js";
|
|
19
19
|
import { List, ListItem } from "./components/list.js";
|
|
20
20
|
import { Option } from "./components/option.js";
|
|
21
|
+
import { Bullet, BulletList, Prose, Quote } from "./components/prose.js";
|
|
21
22
|
import { QRCode } from "./components/qr-code.js";
|
|
23
|
+
import { RichText } from "./components/rich-text.js";
|
|
22
24
|
import { Scroll } from "./components/scroll.js";
|
|
23
25
|
import { Select } from "./components/select.js";
|
|
24
26
|
import { Sheet } from "./components/sheet.js";
|
|
25
27
|
import { Skeleton } from "./components/skeleton.js";
|
|
28
|
+
import { Slider } from "./components/slider.js";
|
|
26
29
|
import { Spinner } from "./components/spinner.js";
|
|
30
|
+
import { Stack } from "./components/stack.js";
|
|
27
31
|
import { Tab, Tabs } from "./components/tabs.js";
|
|
28
32
|
import { Text } from "./components/text.js";
|
|
29
33
|
import { TextArea } from "./components/text-area.js";
|
|
@@ -32,4 +36,4 @@ import { Checkbox, Radio, RadioGroup, Switch } from "./components/toggles.js";
|
|
|
32
36
|
import { View } from "./components/view.js";
|
|
33
37
|
import "./components/index.js";
|
|
34
38
|
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 };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -17,13 +17,17 @@ import { Input } from "./components/input.js";
|
|
|
17
17
|
import { Link } from "./components/link.js";
|
|
18
18
|
import { List, ListItem } from "./components/list.js";
|
|
19
19
|
import { Option } from "./components/option.js";
|
|
20
|
+
import { Bullet, BulletList, Prose, Quote } from "./components/prose.js";
|
|
20
21
|
import { QRCode } from "./components/qr-code.js";
|
|
22
|
+
import { Text } from "./components/text.js";
|
|
23
|
+
import { RichText } from "./components/rich-text.js";
|
|
21
24
|
import { Scroll } from "./components/scroll.js";
|
|
22
25
|
import { Sheet } from "./components/sheet.js";
|
|
23
26
|
import { Select } from "./components/select.js";
|
|
24
27
|
import { Skeleton } from "./components/skeleton.js";
|
|
28
|
+
import { Slider } from "./components/slider.js";
|
|
29
|
+
import { Stack } from "./components/stack.js";
|
|
25
30
|
import { Tab, Tabs } from "./components/tabs.js";
|
|
26
|
-
import { Text } from "./components/text.js";
|
|
27
31
|
import { TextArea } from "./components/text-area.js";
|
|
28
32
|
import { Toast } from "./components/toast.js";
|
|
29
33
|
import { Checkbox, Radio, RadioGroup, Switch } from "./components/toggles.js";
|
|
@@ -32,4 +36,4 @@ import { createReactRenderer, reactRenderer } from "./renderer.js";
|
|
|
32
36
|
//#region src/index.ts
|
|
33
37
|
var src_default = reactRenderer;
|
|
34
38
|
//#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 };
|
|
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 };
|
package/dist/markdown.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
//#region src/markdown.ts
|
|
2
|
+
const HEADING = /^(#{1,6})\s+(.*?)\s*#*\s*$/;
|
|
3
|
+
const RULE = /^ {0,3}([-*_])( *\1){2,} *$/;
|
|
4
|
+
const QUOTE = /^ {0,3}> ?/;
|
|
5
|
+
const LIST_ITEM = /^ {0,3}([-*+]|\d{1,9}[.)])\s+/;
|
|
6
|
+
const LINK = /^(!?)\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/;
|
|
7
|
+
const AUTOLINK = /^<(https?:\/\/[^>\s]+)>/;
|
|
8
|
+
const PUNCTUATION = /[!-/:-@[-`{-~]/;
|
|
9
|
+
const ITEM_INDENT = " ";
|
|
10
|
+
function parseMarkdown(markdown) {
|
|
11
|
+
return parseBlocks(markdown.replace(/\r\n?/g, "\n").split("\n"));
|
|
12
|
+
}
|
|
13
|
+
function parseBlocks(lines) {
|
|
14
|
+
const blocks = [];
|
|
15
|
+
let index = 0;
|
|
16
|
+
while (index < lines.length) {
|
|
17
|
+
const line = lines[index];
|
|
18
|
+
if (line.trim() === "") {
|
|
19
|
+
index += 1;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const single = oneLineBlock(line);
|
|
23
|
+
if (single) {
|
|
24
|
+
blocks.push(single);
|
|
25
|
+
index += 1;
|
|
26
|
+
} else if (QUOTE.test(line)) {
|
|
27
|
+
const quoted = [];
|
|
28
|
+
while (index < lines.length && QUOTE.test(lines[index])) {
|
|
29
|
+
quoted.push(lines[index].replace(QUOTE, ""));
|
|
30
|
+
index += 1;
|
|
31
|
+
}
|
|
32
|
+
blocks.push({
|
|
33
|
+
kind: "quote",
|
|
34
|
+
blocks: parseBlocks(quoted)
|
|
35
|
+
});
|
|
36
|
+
} else if (LIST_ITEM.test(line)) {
|
|
37
|
+
const { list, next } = parseList(lines, index);
|
|
38
|
+
blocks.push(list);
|
|
39
|
+
index = next;
|
|
40
|
+
} else {
|
|
41
|
+
const paragraph = [];
|
|
42
|
+
while (index < lines.length && !endsParagraph(lines[index])) {
|
|
43
|
+
paragraph.push(lines[index]);
|
|
44
|
+
index += 1;
|
|
45
|
+
}
|
|
46
|
+
blocks.push({
|
|
47
|
+
kind: "paragraph",
|
|
48
|
+
content: parseInline(joinLines(paragraph))
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return blocks;
|
|
53
|
+
}
|
|
54
|
+
function oneLineBlock(line) {
|
|
55
|
+
const heading = HEADING.exec(line);
|
|
56
|
+
if (heading) return {
|
|
57
|
+
kind: "heading",
|
|
58
|
+
level: Math.min(heading[1].length, 3),
|
|
59
|
+
content: parseInline(heading[2])
|
|
60
|
+
};
|
|
61
|
+
if (RULE.test(line)) return { kind: "rule" };
|
|
62
|
+
const trimmed = line.trim();
|
|
63
|
+
const picture = LINK.exec(trimmed);
|
|
64
|
+
if (picture && picture[1] === "!" && picture[0].length === trimmed.length) return {
|
|
65
|
+
kind: "image",
|
|
66
|
+
alt: picture[2],
|
|
67
|
+
src: picture[3]
|
|
68
|
+
};
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function endsParagraph(line) {
|
|
72
|
+
return line.trim() === "" || HEADING.test(line) || RULE.test(line) || QUOTE.test(line) || LIST_ITEM.test(line);
|
|
73
|
+
}
|
|
74
|
+
function joinLines(lines) {
|
|
75
|
+
let text = "";
|
|
76
|
+
lines.forEach((line, index) => {
|
|
77
|
+
text += line.trim().replace(/\\$/, "");
|
|
78
|
+
if (index < lines.length - 1) text += /( {2,}|\\)$/.test(line) ? "\n" : " ";
|
|
79
|
+
});
|
|
80
|
+
return text;
|
|
81
|
+
}
|
|
82
|
+
function parseList(lines, start) {
|
|
83
|
+
const ordered = isOrdered(LIST_ITEM.exec(lines[start]));
|
|
84
|
+
const items = [];
|
|
85
|
+
let index = start;
|
|
86
|
+
while (index < lines.length) {
|
|
87
|
+
const marker = LIST_ITEM.exec(lines[index]);
|
|
88
|
+
if (!marker || isOrdered(marker) !== ordered) break;
|
|
89
|
+
const indent = marker[0].length;
|
|
90
|
+
const itemLines = [lines[index].slice(indent)];
|
|
91
|
+
index += 1;
|
|
92
|
+
while (index < lines.length) {
|
|
93
|
+
const line = lines[index];
|
|
94
|
+
if (line.trim() === "") {
|
|
95
|
+
if (!lines[index + 1]?.startsWith(ITEM_INDENT)) break;
|
|
96
|
+
itemLines.push("");
|
|
97
|
+
} else if (line.startsWith(ITEM_INDENT)) itemLines.push(withoutIndent(line, indent));
|
|
98
|
+
else if (endsParagraph(line)) break;
|
|
99
|
+
else itemLines.push(line);
|
|
100
|
+
index += 1;
|
|
101
|
+
}
|
|
102
|
+
items.push(parseBlocks(itemLines));
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
list: {
|
|
106
|
+
kind: "list",
|
|
107
|
+
ordered,
|
|
108
|
+
items
|
|
109
|
+
},
|
|
110
|
+
next: index
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function isOrdered(marker) {
|
|
114
|
+
return /\d/.test(marker[1]);
|
|
115
|
+
}
|
|
116
|
+
function withoutIndent(line, indent) {
|
|
117
|
+
const spaces = line.length - line.trimStart().length;
|
|
118
|
+
return line.slice(Math.min(spaces, indent));
|
|
119
|
+
}
|
|
120
|
+
function parseInline(text) {
|
|
121
|
+
const inlines = [];
|
|
122
|
+
let plain = "";
|
|
123
|
+
let index = 0;
|
|
124
|
+
const flush = () => {
|
|
125
|
+
if (plain) {
|
|
126
|
+
inlines.push({
|
|
127
|
+
kind: "text",
|
|
128
|
+
text: plain
|
|
129
|
+
});
|
|
130
|
+
plain = "";
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const take = (inline, length) => {
|
|
134
|
+
flush();
|
|
135
|
+
inlines.push(inline);
|
|
136
|
+
index += length;
|
|
137
|
+
};
|
|
138
|
+
while (index < text.length) {
|
|
139
|
+
const char = text[index];
|
|
140
|
+
const next = text[index + 1];
|
|
141
|
+
const rest = text.slice(index);
|
|
142
|
+
if (char === "\\" && next !== void 0 && PUNCTUATION.test(next)) {
|
|
143
|
+
plain += next;
|
|
144
|
+
index += 2;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (char === "\n") {
|
|
148
|
+
take({ kind: "break" }, 1);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const codeEnd = char === "`" ? text.indexOf("`", index + 1) : -1;
|
|
152
|
+
if (codeEnd > index + 1) {
|
|
153
|
+
take({
|
|
154
|
+
kind: "code",
|
|
155
|
+
text: text.slice(index + 1, codeEnd)
|
|
156
|
+
}, codeEnd + 1 - index);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const link = LINK.exec(rest);
|
|
160
|
+
if (link) {
|
|
161
|
+
const [whole, picture, label, href] = link;
|
|
162
|
+
take(picture === "!" ? {
|
|
163
|
+
kind: "text",
|
|
164
|
+
text: label
|
|
165
|
+
} : {
|
|
166
|
+
kind: "link",
|
|
167
|
+
href,
|
|
168
|
+
children: parseInline(label)
|
|
169
|
+
}, whole.length);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const autolink = AUTOLINK.exec(rest);
|
|
173
|
+
if (autolink) {
|
|
174
|
+
const [whole, href] = autolink;
|
|
175
|
+
take({
|
|
176
|
+
kind: "link",
|
|
177
|
+
href,
|
|
178
|
+
children: [{
|
|
179
|
+
kind: "text",
|
|
180
|
+
text: href
|
|
181
|
+
}]
|
|
182
|
+
}, whole.length);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const strong = char === "*" || char === "_" ? between(text, index, char + char) : null;
|
|
186
|
+
if (strong) {
|
|
187
|
+
take({
|
|
188
|
+
kind: "strong",
|
|
189
|
+
children: parseInline(strong.inner)
|
|
190
|
+
}, strong.length);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const emphasis = char === "*" || char === "_" ? between(text, index, char) : null;
|
|
194
|
+
if (emphasis) {
|
|
195
|
+
take({
|
|
196
|
+
kind: "emphasis",
|
|
197
|
+
children: parseInline(emphasis.inner)
|
|
198
|
+
}, emphasis.length);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
plain += char;
|
|
202
|
+
index += 1;
|
|
203
|
+
}
|
|
204
|
+
flush();
|
|
205
|
+
return inlines;
|
|
206
|
+
}
|
|
207
|
+
function between(text, start, delimiter) {
|
|
208
|
+
const open = start + delimiter.length;
|
|
209
|
+
if (!text.startsWith(delimiter, start) || open >= text.length || /\s/.test(text[open])) return null;
|
|
210
|
+
const underscore = delimiter.startsWith("_");
|
|
211
|
+
if (underscore && /\w/.test(text[start - 1] ?? "")) return null;
|
|
212
|
+
let close = text.indexOf(delimiter, open + 1);
|
|
213
|
+
while (close !== -1) {
|
|
214
|
+
const touchesSpace = /\s/.test(text[close - 1]);
|
|
215
|
+
const insideWord = underscore && /\w/.test(text[close + delimiter.length] ?? "");
|
|
216
|
+
const startsPair = delimiter.length === 1 && text[close + 1] === delimiter;
|
|
217
|
+
if (!touchesSpace && !insideWord && !startsPair) return {
|
|
218
|
+
inner: text.slice(open, close),
|
|
219
|
+
length: close + delimiter.length - start
|
|
220
|
+
};
|
|
221
|
+
close = text.indexOf(delimiter, close + (startsPair ? 2 : 1));
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
//#endregion
|
|
226
|
+
export { parseInline, parseMarkdown };
|
package/dist/styles.css
CHANGED
|
@@ -1,95 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Dot's stylesheet, for what inline styles can't do, such as pseudo-elements, keyframes and
|
|
3
|
-
* rules for every element. Global rules sit in the lowest layer, so they never override a
|
|
4
|
-
* component's own styles. Component rules stay outside the layers.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
@layer base {
|
|
8
|
-
.dot-theme-root,
|
|
9
|
-
.dot-theme-root *,
|
|
10
|
-
.dot-theme-root ::before,
|
|
11
|
-
.dot-theme-root ::after {
|
|
12
|
-
box-sizing: border-box;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.dot-theme-root :is(button, input, select, textarea) {
|
|
16
|
-
font: inherit;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
[data-dot-scheme='light'] {
|
|
20
|
-
color-scheme: light;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
[data-dot-scheme='dark'] {
|
|
24
|
-
color-scheme: dark;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/* Skeleton: pulses down to 40% every 1.2s. */
|
|
29
|
-
@keyframes dot-skeleton-pulse {
|
|
30
|
-
0%,
|
|
31
|
-
100% {
|
|
32
|
-
opacity: 1;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
50% {
|
|
36
|
-
opacity: 0.4;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/* Image: no wider than the space it's given, unless a Scroll lets it keep its own width. */
|
|
41
|
-
.dot-image {
|
|
42
|
-
display: block;
|
|
43
|
-
max-width: 100%;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/* List: a full-width line under each row but the last, in the color the list passes. */
|
|
47
|
-
.dot-list > .dot-list-item:not(:last-child) {
|
|
48
|
-
border-bottom: 1px solid var(--dot-list-divider);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/* Scroll: a row that scrolls sideways with the finger, without a scroll bar. */
|
|
52
|
-
.dot-scroll {
|
|
53
|
-
position: relative;
|
|
54
|
-
display: flex;
|
|
55
|
-
flex-direction: row;
|
|
56
|
-
overflow-x: auto;
|
|
57
|
-
overflow-y: hidden;
|
|
58
|
-
overscroll-behavior-x: contain;
|
|
59
|
-
scrollbar-width: none;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.dot-scroll::-webkit-scrollbar {
|
|
63
|
-
display: none;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/* Each child keeps its own width. A View is as wide as its widest fixed-size child. Children are
|
|
67
|
-
styled here instead of wrapped, because a For loop's items reach the row as one child. */
|
|
68
|
-
.dot-scroll > * {
|
|
69
|
-
flex: 0 0 auto;
|
|
70
|
-
width: min-content;
|
|
71
|
-
scroll-snap-align: var(--dot-scroll-snap);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/* A picture's own width sets its item's width. With max-width: 100% it would count for nothing. */
|
|
75
|
-
.dot-scroll .dot-image {
|
|
76
|
-
max-width: none;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/* Sheet: slides up over a dimmed page, and back down when it closes. Base UI marks the first and
|
|
80
|
-
last frames, and waits for these transitions before it removes the sheet. */
|
|
81
|
-
.dot-sheet-backdrop {
|
|
82
|
-
transition: opacity 0.2s;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.dot-sheet {
|
|
86
|
-
transition: transform 0.2s ease-out;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.dot-sheet-backdrop:is([data-starting-style], [data-ending-style]) {
|
|
90
|
-
opacity: 0;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.dot-sheet:is([data-starting-style], [data-ending-style]) {
|
|
94
|
-
transform: translateY(100%);
|
|
95
|
-
}
|
|
1
|
+
@layer base{.dot-theme-root,.dot-theme-root *,.dot-theme-root :before,.dot-theme-root :after{box-sizing:border-box}.dot-theme-root :is(button,input,select,textarea){font:inherit}[data-dot-scheme=light]{color-scheme:light}[data-dot-scheme=dark]{color-scheme:dark}.dot-theme-root{-webkit-user-select:none;user-select:none}.dot-theme-root :is(input,textarea){-webkit-user-select:text;user-select:text}}@keyframes dot-skeleton-pulse{0%,to{opacity:1}50%{opacity:.4}}.dot-image{max-width:100%;display:block}.dot-list>.dot-list-item:not(:last-child){border-bottom:1px solid var(--dot-list-divider)}.dot-scroll{overscroll-behavior-x:contain;scrollbar-width:none;flex-direction:row;display:flex;position:relative;overflow:auto hidden}.dot-scroll::-webkit-scrollbar{display:none}.dot-scroll>*{scroll-snap-align:var(--dot-scroll-snap);flex:none;width:min-content}.dot-scroll .dot-image{max-width:none}.dot-sheet-backdrop{transition:opacity .2s}.dot-sheet{transition:transform .2s ease-out}.dot-sheet-backdrop:is([data-starting-style],[data-ending-style]){opacity:0}.dot-sheet:is([data-starting-style],[data-ending-style]){transform:translateY(100%)}.dot-prose>.dot-heading{margin-block-start:.5em}.dot-prose>.dot-heading:first-child{margin-block-start:0}
|
package/dist/theme.d.ts
CHANGED
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.
|
|
3
|
+
"version": "0.1.0-alpha.18",
|
|
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.
|
|
33
|
-
"@monimesl/dot-webview": "0.1.0-alpha.
|
|
32
|
+
"@monimesl/dot-core": "0.1.0-alpha.18",
|
|
33
|
+
"@monimesl/dot-webview": "0.1.0-alpha.18"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@base-ui/react": "1.8.0",
|
|
@@ -39,19 +39,20 @@
|
|
|
39
39
|
"@types/react": "^19.3.0",
|
|
40
40
|
"@types/react-dom": "^19.3.0",
|
|
41
41
|
"jsdom": "^30.1.1",
|
|
42
|
+
"lightningcss": "1.33.0",
|
|
42
43
|
"publint": "^0.3.24",
|
|
43
44
|
"rimraf": "^6.1.3",
|
|
44
45
|
"rolldown": "^1.2.9",
|
|
45
46
|
"tsdown": "^0.23.0",
|
|
46
47
|
"typescript": "^5.9.3",
|
|
47
48
|
"vitest": "^5.0.1",
|
|
48
|
-
"@monimesl/dot-service": "0.1.0-alpha.
|
|
49
|
+
"@monimesl/dot-service": "0.1.0-alpha.18"
|
|
49
50
|
},
|
|
50
51
|
"publishConfig": {
|
|
51
52
|
"access": "public"
|
|
52
53
|
},
|
|
53
54
|
"scripts": {
|
|
54
|
-
"build": "pnpm icons:generate && tsdown &&
|
|
55
|
+
"build": "pnpm icons:generate && tsdown && node scripts/build-styles.mjs && cp node_modules/@phosphor-icons/core/LICENSE dist/LICENSE-PHOSPHOR && node scripts/build-react-host.mjs",
|
|
55
56
|
"icons:generate": "node scripts/generate-icon-artwork.mjs && prettier --write src/components/icon-artwork.ts",
|
|
56
57
|
"dev": "tsdown --watch",
|
|
57
58
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|