@colixsystems/widget-sdk 0.122.0 → 0.124.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -3
- package/dist/contract.cjs +54 -4
- package/dist/contract.js +54 -4
- package/dist/index.d.ts +129 -1
- package/dist/index.js +17 -0
- package/dist/index.native.js +15 -0
- package/dist/linter.cjs +43 -0
- package/dist/linter.js +58 -0
- package/dist/markdown-edit.js +97 -0
- package/dist/markdown-input-view.js +171 -0
- package/dist/markdown-input.js +9 -0
- package/dist/markdown-input.native.js +12 -0
- package/dist/markdown.js +229 -0
- package/dist/richtext-tokens.js +59 -0
- package/dist/richtext-view.js +156 -0
- package/dist/richtext.js +11 -0
- package/dist/richtext.native.js +8 -0
- package/package.json +2 -2
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// sc-6970 — the ONE implementation behind the `<RichText>` SDK primitive.
|
|
2
|
+
//
|
|
3
|
+
// Renders the markdown-subset block tree from `markdown.js` with React Native
|
|
4
|
+
// primitives, so formatted content reads the same in the web Player and the
|
|
5
|
+
// exported Expo app. There is deliberately no HTML path — see `markdown.js`.
|
|
6
|
+
//
|
|
7
|
+
// The two platform bindings (`richtext.js` / `richtext.native.js`) differ ONLY
|
|
8
|
+
// in where the primitives come from; the component is defined once here so the
|
|
9
|
+
// hosts cannot drift (CLAUDE.md §3, §8).
|
|
10
|
+
|
|
11
|
+
import React from "react";
|
|
12
|
+
import { useHostTheme } from "./hooks.js";
|
|
13
|
+
import { parseMarkdown, isHttpImageSrc } from "./markdown.js";
|
|
14
|
+
import { resolveRichTextTokens } from "./richtext-tokens.js";
|
|
15
|
+
|
|
16
|
+
export function makeRichText(rn) {
|
|
17
|
+
const { Text, View, Image } = rn;
|
|
18
|
+
|
|
19
|
+
function Spans({ spans, tokens }) {
|
|
20
|
+
return spans.map((span, i) =>
|
|
21
|
+
React.createElement(
|
|
22
|
+
Text,
|
|
23
|
+
{
|
|
24
|
+
key: i,
|
|
25
|
+
style: [
|
|
26
|
+
span.bold ? { fontWeight: "700" } : null,
|
|
27
|
+
span.italic ? { fontStyle: "italic" } : null,
|
|
28
|
+
span.code
|
|
29
|
+
? {
|
|
30
|
+
// A code span needs a mono face; the theme has no mono token.
|
|
31
|
+
fontFamily: "monospace",
|
|
32
|
+
fontSize: tokens.codeSize,
|
|
33
|
+
color: tokens.mutedColor,
|
|
34
|
+
}
|
|
35
|
+
: null,
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
span.text,
|
|
39
|
+
),
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function RichText({ value, renderImage, style, testID }) {
|
|
44
|
+
const theme = useHostTheme();
|
|
45
|
+
const tokens = React.useMemo(() => resolveRichTextTokens(theme), [theme]);
|
|
46
|
+
const blocks = React.useMemo(() => parseMarkdown(value), [value]);
|
|
47
|
+
|
|
48
|
+
if (blocks.length === 0) return null;
|
|
49
|
+
|
|
50
|
+
const paragraph = {
|
|
51
|
+
fontFamily: tokens.bodyFont,
|
|
52
|
+
fontSize: tokens.bodySize,
|
|
53
|
+
lineHeight: tokens.lineHeight,
|
|
54
|
+
color: tokens.color,
|
|
55
|
+
marginBottom: tokens.blockGap,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return React.createElement(
|
|
59
|
+
View,
|
|
60
|
+
{ style, testID },
|
|
61
|
+
blocks.map((block, i) => {
|
|
62
|
+
const spans = React.createElement(Spans, { spans: block.spans, tokens });
|
|
63
|
+
|
|
64
|
+
if (block.type === "heading") {
|
|
65
|
+
return React.createElement(
|
|
66
|
+
Text,
|
|
67
|
+
{
|
|
68
|
+
key: i,
|
|
69
|
+
style: [
|
|
70
|
+
paragraph,
|
|
71
|
+
{
|
|
72
|
+
fontFamily: tokens.headingFont,
|
|
73
|
+
fontWeight: "700",
|
|
74
|
+
fontSize: tokens.headingSizes[block.level] || tokens.headingSizes[3],
|
|
75
|
+
lineHeight: undefined,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
spans,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (block.type === "image") {
|
|
84
|
+
if (typeof renderImage === "function") {
|
|
85
|
+
return React.createElement(
|
|
86
|
+
View,
|
|
87
|
+
{ key: i, style: { marginBottom: tokens.blockGap } },
|
|
88
|
+
renderImage(block),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
// Without a resolver only an absolute URL can be shown; a filestore
|
|
92
|
+
// id needs the widget's own scopes, so it renders as its caption.
|
|
93
|
+
return React.createElement(
|
|
94
|
+
View,
|
|
95
|
+
{
|
|
96
|
+
key: i,
|
|
97
|
+
style: {
|
|
98
|
+
marginBottom: tokens.blockGap,
|
|
99
|
+
width: tokens.imageWidth[block.size] || tokens.imageWidth.full,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
isHttpImageSrc(block.src)
|
|
103
|
+
? React.createElement(Image, {
|
|
104
|
+
source: { uri: block.src },
|
|
105
|
+
accessibilityLabel: block.alt || undefined,
|
|
106
|
+
resizeMode: "cover",
|
|
107
|
+
style: {
|
|
108
|
+
width: "100%",
|
|
109
|
+
aspectRatio: 16 / 9,
|
|
110
|
+
borderRadius: tokens.radius,
|
|
111
|
+
backgroundColor: tokens.surface,
|
|
112
|
+
},
|
|
113
|
+
})
|
|
114
|
+
: null,
|
|
115
|
+
block.alt
|
|
116
|
+
? React.createElement(
|
|
117
|
+
Text,
|
|
118
|
+
{
|
|
119
|
+
style: {
|
|
120
|
+
fontFamily: tokens.bodyFont,
|
|
121
|
+
fontSize: tokens.codeSize,
|
|
122
|
+
color: tokens.mutedColor,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
block.alt,
|
|
126
|
+
)
|
|
127
|
+
: null,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (block.type === "bullet" || block.type === "ordered") {
|
|
132
|
+
return React.createElement(
|
|
133
|
+
View,
|
|
134
|
+
{ key: i, style: { flexDirection: "row" } },
|
|
135
|
+
React.createElement(
|
|
136
|
+
Text,
|
|
137
|
+
{
|
|
138
|
+
style: [
|
|
139
|
+
paragraph,
|
|
140
|
+
{ color: tokens.mutedColor, marginRight: tokens.markerGap },
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
block.marker,
|
|
144
|
+
),
|
|
145
|
+
React.createElement(Text, { style: [paragraph, { flex: 1 }] }, spans),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return React.createElement(Text, { key: i, style: paragraph }, spans);
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
RichText.displayName = "RichText";
|
|
155
|
+
return RichText;
|
|
156
|
+
}
|
package/dist/richtext.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// sc-6970 — `<RichText>` (web). Binds the shared implementation in
|
|
2
|
+
// ./richtext-view.js to react-native-web's primitives.
|
|
3
|
+
//
|
|
4
|
+
// The import is `react-native-web` rather than the bare `react-native`
|
|
5
|
+
// specifier for the rolldown optional-peer-dep reason spelled out at the top of
|
|
6
|
+
// ./primitives.js.
|
|
7
|
+
|
|
8
|
+
import * as ReactNative from "react-native-web";
|
|
9
|
+
import { makeRichText } from "./richtext-view.js";
|
|
10
|
+
|
|
11
|
+
export const RichText = makeRichText(ReactNative);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// sc-6970 — `<RichText>` (native). Binds the shared implementation in
|
|
2
|
+
// ./richtext-view.js to React Native's own primitives. Only the import differs
|
|
3
|
+
// from the web mirror in ./richtext.js.
|
|
4
|
+
|
|
5
|
+
import { Text, View, Image } from "react-native";
|
|
6
|
+
import { makeRichText } from "./richtext-view.js";
|
|
7
|
+
|
|
8
|
+
export const RichText = makeRichText({ Text, View, Image });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.124.0",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"homepage": "https://github.com/Colix-AB/AppStudio",
|
|
6
6
|
"type": "module",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
],
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "node scripts/build.js",
|
|
52
|
-
"test": "node --test src/__tests__/contract.test.js src/__tests__/vetted-imports-audit.test.js src/__tests__/hooks-users.test.js src/__tests__/hooks-groups.test.js src/__tests__/hooks-invites.test.js src/__tests__/hooks-schema.test.js src/__tests__/hooks-assets-by-tag.test.js src/__tests__/hooks-filestore-upload.test.js src/__tests__/hooks-filestore-file.test.js src/__tests__/hooks-mutation.test.js src/__tests__/hooks-payments.test.js src/__tests__/hooks-record-permissions.test.js src/__tests__/hooks-geolocation.test.js src/__tests__/hooks-section-empty.test.js src/__tests__/hooks-widget-event.test.js src/__tests__/hooks-widget-input.test.js src/__tests__/hooks-identification.test.js src/__tests__/hooks-subscription.test.js src/__tests__/hooks-volatile-query-key.test.js src/__tests__/linter-users-scope.test.js src/__tests__/linter-comments.test.js src/__tests__/linter-translation-api.test.js src/__tests__/linter-page-url.test.js src/__tests__/linter-image-height.test.js src/__tests__/linter-hardcoded-design.test.js src/__tests__/linter-measured-padding.test.js src/__tests__/linter-payment-error.test.js src/__tests__/linter-platform.test.js src/__tests__/linter-react-import.test.js src/__tests__/lucide-icon-names.test.js src/__tests__/lucideIconName.test.js src/__tests__/manifest-actions.test.js src/__tests__/widget-translations.test.js src/__tests__/hooks-translate.test.js src/__tests__/devserver.test.js src/__tests__/flatten-entry.test.js src/__tests__/host-externals.test.js src/__tests__/datetimepicker.test.js src/__tests__/property-schema-resolve.test.js src/__tests__/corner-radius.test.js src/__tests__/theme-components-parity.test.js src/__tests__/navigation-parity.test.js src/__tests__/theme-depth-tokens.test.js src/__tests__/interaction-lift.test.js src/__tests__/toast-host.test.js src/__tests__/overlay-tokens.test.js src/__tests__/hooks-domain-error-mapping.test.js src/__tests__/linter-datastore-error.test.js src/__tests__/linter-write-gating.test.js src/__tests__/hooks-speech-to-text.test.js src/__tests__/hooks-camera.test.js src/__tests__/hooks-bound-columns.test.js src/__tests__/hooks-stable-query.test.js src/__tests__/hooks-can-write.test.js src/__tests__/widget-route.test.js"
|
|
52
|
+
"test": "node --test src/__tests__/contract.test.js src/__tests__/vetted-imports-audit.test.js src/__tests__/hooks-users.test.js src/__tests__/hooks-groups.test.js src/__tests__/hooks-invites.test.js src/__tests__/hooks-schema.test.js src/__tests__/hooks-assets-by-tag.test.js src/__tests__/hooks-filestore-upload.test.js src/__tests__/hooks-filestore-file.test.js src/__tests__/hooks-mutation.test.js src/__tests__/hooks-payments.test.js src/__tests__/hooks-record-permissions.test.js src/__tests__/hooks-geolocation.test.js src/__tests__/hooks-section-empty.test.js src/__tests__/hooks-widget-event.test.js src/__tests__/hooks-widget-input.test.js src/__tests__/hooks-identification.test.js src/__tests__/hooks-subscription.test.js src/__tests__/hooks-volatile-query-key.test.js src/__tests__/linter-users-scope.test.js src/__tests__/linter-comments.test.js src/__tests__/linter-translation-api.test.js src/__tests__/linter-page-url.test.js src/__tests__/linter-image-height.test.js src/__tests__/linter-hardcoded-design.test.js src/__tests__/linter-measured-padding.test.js src/__tests__/linter-payment-error.test.js src/__tests__/linter-platform.test.js src/__tests__/linter-react-import.test.js src/__tests__/lucide-icon-names.test.js src/__tests__/lucideIconName.test.js src/__tests__/manifest-actions.test.js src/__tests__/widget-translations.test.js src/__tests__/hooks-translate.test.js src/__tests__/devserver.test.js src/__tests__/flatten-entry.test.js src/__tests__/host-externals.test.js src/__tests__/datetimepicker.test.js src/__tests__/property-schema-resolve.test.js src/__tests__/corner-radius.test.js src/__tests__/theme-components-parity.test.js src/__tests__/navigation-parity.test.js src/__tests__/theme-depth-tokens.test.js src/__tests__/interaction-lift.test.js src/__tests__/toast-host.test.js src/__tests__/overlay-tokens.test.js src/__tests__/hooks-domain-error-mapping.test.js src/__tests__/linter-datastore-error.test.js src/__tests__/linter-write-gating.test.js src/__tests__/hooks-speech-to-text.test.js src/__tests__/hooks-camera.test.js src/__tests__/hooks-bound-columns.test.js src/__tests__/hooks-stable-query.test.js src/__tests__/hooks-can-write.test.js src/__tests__/widget-route.test.js src/__tests__/linter-html-in-content.test.js src/__tests__/markdown.test.js src/__tests__/markdown-edit.test.js src/__tests__/richtext-tokens.test.js"
|
|
53
53
|
},
|
|
54
54
|
"engines": {
|
|
55
55
|
"node": ">=18"
|