@getrheo/renderer-core 1.0.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.
@@ -0,0 +1,213 @@
1
+ export { TEXT_FONT_FAMILY_SYSTEM_UI, WEB_DOCUMENT_FONT_STACK, brandingWebFontFacesCss, buildBrandingFontLoadMap, nativeFontRegistrationNameForStyle, resolveNativeTextFontFamilyName, resolveWebRootFontFamilyCss, resolveWebTextFontFamilyCss } from '@getrheo/flow-runtime/layerTypography';
2
+ export { ScreenSizeBucket, getScreenSizeBucketForWidth } from '@getrheo/flow-runtime/responsive/breakpoints';
3
+ export { resolveCheckboxGlyphForRender } from '@getrheo/flow-runtime/checkboxGlyphStyle';
4
+ import { ButtonAction, TextStyle, ThemedColor, EmailPasswordAuthMode, EmailPasswordAuthLayer, EmailPasswordSlot, OAuthLoginLayer, OAuthLoginPreset, WidthValue, CommonLayoutHeight, Padding, Border, DropShadow, CarouselLayer, SingleChoiceLayer, MultipleChoiceLayer, ScaleInputLayer, TextInputLayer } from '@getrheo/contracts/layers';
5
+ import { ValidateEmailPasswordAuthResult } from '@getrheo/flow-runtime/emailPasswordAuthValidation';
6
+ import { Branding } from '@getrheo/contracts/dashboard';
7
+ import { Theme } from '@getrheo/contracts/manifest';
8
+ import { NativeDropShadowStyle } from '@getrheo/flow-runtime';
9
+
10
+ type RendererActionMode = 'interactive' | 'static' | 'native';
11
+ type RendererButtonActionModel = {
12
+ actionKind: ButtonAction['kind'];
13
+ submitsScreen: boolean;
14
+ recordsSkip: boolean;
15
+ terminal: boolean;
16
+ navigates: boolean;
17
+ requestsPermission: boolean;
18
+ requestsAppReview: boolean;
19
+ disabled: boolean;
20
+ disabledReasons: string[];
21
+ };
22
+ declare const rendererButtonActionModel: ({ action, mode, checkboxContinueBlocked, inputDraftInvalid, nativePermissionAvailable, }: {
23
+ action: ButtonAction;
24
+ mode: RendererActionMode;
25
+ checkboxContinueBlocked?: boolean;
26
+ inputDraftInvalid?: boolean;
27
+ nativePermissionAvailable?: boolean;
28
+ }) => RendererButtonActionModel;
29
+
30
+ type RendererPalette = 'light' | 'dark';
31
+ type RendererTypographyModel = {
32
+ fontFamily: string | undefined;
33
+ webFontFamily: string | undefined;
34
+ nativeFontFamily: string | undefined;
35
+ fontSize: number | undefined;
36
+ fontWeight: number | undefined;
37
+ color: string | undefined;
38
+ align: TextStyle['align'];
39
+ lineHeight: number | undefined;
40
+ };
41
+ declare const rendererTypographyModel: ({ style, theme, palette, branding, fallbackColor, }: {
42
+ style: Pick<TextStyle, "fontFamily" | "fontSize" | "fontWeight" | "color" | "align" | "lineHeight"> | undefined;
43
+ theme: Theme | undefined;
44
+ palette: RendererPalette;
45
+ branding?: Branding;
46
+ fallbackColor?: ThemedColor;
47
+ }) => RendererTypographyModel;
48
+
49
+ type RendererOAuthPresetBrandModel = {
50
+ backgroundColor: string;
51
+ labelColor: string;
52
+ iconColor: string;
53
+ borderColor: string;
54
+ borderWidth: number;
55
+ fontFamily: string;
56
+ fontWeight: number;
57
+ fontSize: number;
58
+ lineHeight: number;
59
+ webBoxShadow?: string;
60
+ };
61
+ declare const rendererOAuthPresetBrandModel: (preset: OAuthLoginPreset, theme: RendererPalette) => RendererOAuthPresetBrandModel;
62
+ type RendererOAuthAlignAxis = 'start' | 'center' | 'end' | 'stretch';
63
+ declare const rendererOAuthLoginAlignAxis: (align: OAuthLoginLayer["align"] | undefined) => RendererOAuthAlignAxis;
64
+ type RendererOAuthRowInteractionModel = {
65
+ disabled: boolean;
66
+ busy: boolean;
67
+ };
68
+ declare const rendererOAuthRowInteractionModel: ({ interactive, pendingRowKey, rowKey, staticPicker, }: {
69
+ interactive: boolean;
70
+ pendingRowKey: string | null;
71
+ rowKey: string;
72
+ /** When true, rows stay enabled for layer picking (builder sim). */
73
+ staticPicker?: boolean;
74
+ }) => RendererOAuthRowInteractionModel;
75
+ type RendererEmailPasswordValues = {
76
+ email: string;
77
+ password: string;
78
+ confirm: string;
79
+ };
80
+ type RendererEmailPasswordAuthModel = {
81
+ mode: EmailPasswordAuthMode;
82
+ minPasswordLength: number;
83
+ values: RendererEmailPasswordValues;
84
+ validation: ValidateEmailPasswordAuthResult;
85
+ canSubmit: boolean;
86
+ };
87
+ declare const rendererEmailPasswordAuthModel: (layer: Pick<EmailPasswordAuthLayer, "mode" | "minPasswordLength">, values: RendererEmailPasswordValues) => RendererEmailPasswordAuthModel;
88
+ declare const rendererEmailPasswordFieldInputType: (slot: EmailPasswordSlot) => "email" | "password" | "text";
89
+ type RendererEmailPasswordSimInputColors = {
90
+ background: string;
91
+ border: string;
92
+ };
93
+ declare const rendererEmailPasswordSimInputColors: (theme: RendererPalette) => RendererEmailPasswordSimInputColors;
94
+
95
+ type RendererBoxEdges = {
96
+ top: number;
97
+ right: number;
98
+ bottom: number;
99
+ left: number;
100
+ };
101
+ type RendererLayoutModel = {
102
+ padding: RendererBoxEdges;
103
+ margin: RendererBoxEdges;
104
+ width: WidthValue | undefined;
105
+ height: CommonLayoutHeight | undefined;
106
+ position: 'absolute' | undefined;
107
+ inset: RendererBoxEdges | undefined;
108
+ zIndex: number | undefined;
109
+ };
110
+ declare const boxEdges: (value: Padding | undefined) => RendererBoxEdges;
111
+ declare const boxEdgesOrUndefined: (value: Padding | undefined) => RendererBoxEdges | undefined;
112
+ declare const rendererLayoutModel: (style: {
113
+ padding?: Padding;
114
+ margin?: Padding;
115
+ width?: WidthValue;
116
+ height?: CommonLayoutHeight;
117
+ position?: "absolute";
118
+ inset?: Padding;
119
+ zIndex?: number;
120
+ } | undefined) => RendererLayoutModel;
121
+
122
+ type RendererSurfaceModel = {
123
+ radius: number | undefined;
124
+ opacity: number | undefined;
125
+ background: string | undefined;
126
+ nativeBackgroundColor: string | undefined;
127
+ borderWidth: number | undefined;
128
+ borderColor: string | undefined;
129
+ webBoxShadow: string | undefined;
130
+ nativeShadow: NativeDropShadowStyle;
131
+ };
132
+ declare const rendererSurfaceModel: ({ style, theme, palette, branding, }: {
133
+ style: {
134
+ radius?: number;
135
+ opacity?: number;
136
+ background?: ThemedColor;
137
+ border?: Border;
138
+ shadow?: DropShadow;
139
+ } | undefined;
140
+ theme: Theme | undefined;
141
+ palette: RendererPalette;
142
+ branding?: Branding;
143
+ }) => RendererSurfaceModel;
144
+
145
+ type RendererCarouselAlignAxis = 'start' | 'center' | 'end';
146
+ declare const rendererCarouselSlideIndex: (layer: Pick<CarouselLayer, "openOn">, slideCount: number) => number;
147
+ type RendererCarouselLayoutModel = {
148
+ peek: number;
149
+ spacing: number;
150
+ alignAxis: RendererCarouselAlignAxis;
151
+ autoAdvanceMs: number;
152
+ loop: boolean;
153
+ slideCount: number;
154
+ };
155
+ declare const rendererCarouselLayoutModel: (layer: CarouselLayer) => RendererCarouselLayoutModel;
156
+ declare const rendererCarouselSlideWidth: (containerWidth: number, peek: number) => number;
157
+ type RendererCarouselPageDotModel = {
158
+ active: boolean;
159
+ width: number;
160
+ height: number;
161
+ backgroundColor: string;
162
+ opacity: number;
163
+ borderWidth: number | undefined;
164
+ borderColor: string | undefined;
165
+ borderRadius: number;
166
+ };
167
+ type RendererCarouselPageDotsModel = {
168
+ visible: boolean;
169
+ position: 'top' | 'bottom';
170
+ spacing: number;
171
+ padding: RendererBoxEdges;
172
+ margin: RendererBoxEdges;
173
+ containerSurface: ReturnType<typeof rendererSurfaceModel>;
174
+ dots: RendererCarouselPageDotModel[];
175
+ };
176
+ declare const rendererCarouselPageDotsModel: ({ layer, activeIndex, theme, manifestTheme, }: {
177
+ layer: CarouselLayer;
178
+ activeIndex: number;
179
+ theme: RendererPalette;
180
+ manifestTheme: Theme | undefined;
181
+ }) => RendererCarouselPageDotsModel;
182
+ declare const rendererCarouselIndexFromScrollOffset: (offset: number, slideWidth: number, spacing: number, slideCount: number) => number | null;
183
+ declare const rendererCarouselScrollOffset: (index: number, slideWidth: number, spacing: number) => number;
184
+ /** Swipe-only carousels: emit flow completion when the user lands on the last slide. */
185
+ declare const rendererCarouselShouldEmitComplete: (previousIndex: number, index: number, slideCount: number, loop: boolean) => boolean;
186
+ declare const rendererCarouselAdvanceIndex: (index: number, slideCount: number, loop: boolean) => number;
187
+
188
+ type RendererChoiceSelectionModel = {
189
+ selectedOptionIds: string[];
190
+ selectedSet: Set<string>;
191
+ minSelections: number | undefined;
192
+ maxSelections: number | undefined;
193
+ canToggleMore: boolean;
194
+ };
195
+ declare const rendererChoiceSelectionModel: (layer: SingleChoiceLayer | MultipleChoiceLayer, selectedOptionIds: readonly string[]) => RendererChoiceSelectionModel;
196
+ type RendererTextInputModel = {
197
+ value: string;
198
+ trimmedValue: string;
199
+ required: boolean;
200
+ valid: boolean;
201
+ invalidReason: string | undefined;
202
+ };
203
+ declare const rendererTextInputModel: (layer: TextInputLayer, value: string) => RendererTextInputModel;
204
+ type RendererScaleInputModel = {
205
+ value: number;
206
+ snappedValue: number;
207
+ step: number;
208
+ inRange: boolean;
209
+ onStep: boolean;
210
+ };
211
+ declare const rendererScaleInputModel: (layer: ScaleInputLayer, value: number) => RendererScaleInputModel;
212
+
213
+ export { type RendererActionMode, type RendererBoxEdges, type RendererButtonActionModel, type RendererCarouselAlignAxis, type RendererCarouselLayoutModel, type RendererCarouselPageDotModel, type RendererCarouselPageDotsModel, type RendererChoiceSelectionModel, type RendererEmailPasswordAuthModel, type RendererEmailPasswordSimInputColors, type RendererEmailPasswordValues, type RendererLayoutModel, type RendererOAuthAlignAxis, type RendererOAuthPresetBrandModel, type RendererOAuthRowInteractionModel, type RendererPalette, type RendererScaleInputModel, type RendererSurfaceModel, type RendererTextInputModel, type RendererTypographyModel, boxEdges, boxEdgesOrUndefined, rendererButtonActionModel, rendererCarouselAdvanceIndex, rendererCarouselIndexFromScrollOffset, rendererCarouselLayoutModel, rendererCarouselPageDotsModel, rendererCarouselScrollOffset, rendererCarouselShouldEmitComplete, rendererCarouselSlideIndex, rendererCarouselSlideWidth, rendererChoiceSelectionModel, rendererEmailPasswordAuthModel, rendererEmailPasswordFieldInputType, rendererEmailPasswordSimInputColors, rendererLayoutModel, rendererOAuthLoginAlignAxis, rendererOAuthPresetBrandModel, rendererOAuthRowInteractionModel, rendererScaleInputModel, rendererSurfaceModel, rendererTextInputModel, rendererTypographyModel };
package/dist/index.js ADDED
@@ -0,0 +1,330 @@
1
+ export { TEXT_FONT_FAMILY_SYSTEM_UI, WEB_DOCUMENT_FONT_STACK, brandingWebFontFacesCss, buildBrandingFontLoadMap, nativeFontRegistrationNameForStyle, resolveNativeTextFontFamilyName, resolveWebRootFontFamilyCss, resolveWebTextFontFamilyCss } from '@getrheo/flow-runtime/layerTypography';
2
+ export { getScreenSizeBucketForWidth } from '@getrheo/flow-runtime/responsive/breakpoints';
3
+ export { resolveCheckboxGlyphForRender } from '@getrheo/flow-runtime/checkboxGlyphStyle';
4
+ import { validateEmailPasswordAuthFields } from '@getrheo/flow-runtime/emailPasswordAuthValidation';
5
+ import { nativeBrandBackgroundFromThemedColor, dropShadowToNativeStyle, dropShadowToBoxShadow, resolveThemedColor, resolveThemedBackground, validateTextInputValue, scaleValueIsOnStep, scaleValueInRange, scaleStep, snapScaleValue, resolveNativeTextFontFamilyName, resolveWebTextFontFamilyCss } from '@getrheo/flow-runtime';
6
+
7
+ // src/index.ts
8
+
9
+ // src/actionModel.ts
10
+ var rendererButtonActionModel = ({
11
+ action,
12
+ mode,
13
+ checkboxContinueBlocked = false,
14
+ inputDraftInvalid = false,
15
+ nativePermissionAvailable = true
16
+ }) => {
17
+ const disabledReasons = [];
18
+ if (mode === "static") disabledReasons.push("static-mode");
19
+ if (action.kind === "continue" && checkboxContinueBlocked) disabledReasons.push("checkbox-blocked");
20
+ if (action.kind === "continue" && inputDraftInvalid) disabledReasons.push("input-invalid");
21
+ if (mode === "native" && action.kind === "request_os_permission" && !nativePermissionAvailable) {
22
+ disabledReasons.push("native-permission-unavailable");
23
+ }
24
+ return {
25
+ actionKind: action.kind,
26
+ submitsScreen: action.kind === "continue",
27
+ recordsSkip: action.kind === "skip",
28
+ terminal: action.kind === "end_flow",
29
+ navigates: action.kind === "go_to_step" || action.kind === "go_back_one_screen",
30
+ requestsPermission: action.kind === "request_os_permission",
31
+ requestsAppReview: action.kind === "request_app_review",
32
+ disabled: disabledReasons.length > 0,
33
+ disabledReasons
34
+ };
35
+ };
36
+ var OAUTH_BODY_FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif';
37
+ var OAUTH_APPLE_FONT = '-apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif';
38
+ var rendererOAuthPresetBrandModel = (preset, theme) => {
39
+ if (preset === "google") {
40
+ const fill = "#4285F4";
41
+ if (theme === "dark") {
42
+ return {
43
+ backgroundColor: "#ffffff",
44
+ labelColor: fill,
45
+ iconColor: fill,
46
+ borderColor: "#d1d5db",
47
+ borderWidth: 1,
48
+ fontFamily: OAUTH_BODY_FONT,
49
+ fontWeight: 600,
50
+ fontSize: 14,
51
+ lineHeight: 1.25,
52
+ webBoxShadow: "0 1px 2px rgba(0,0,0,0.08)"
53
+ };
54
+ }
55
+ return {
56
+ backgroundColor: fill,
57
+ labelColor: "#ffffff",
58
+ iconColor: "#ffffff",
59
+ borderColor: fill,
60
+ borderWidth: 1,
61
+ fontFamily: OAUTH_BODY_FONT,
62
+ fontWeight: 600,
63
+ fontSize: 14,
64
+ lineHeight: 1.25,
65
+ webBoxShadow: "0 1px 2px rgba(0,0,0,0.12)"
66
+ };
67
+ }
68
+ if (preset === "apple") {
69
+ if (theme === "dark") {
70
+ return {
71
+ backgroundColor: "#ffffff",
72
+ labelColor: "#000000",
73
+ iconColor: "#000000",
74
+ borderColor: "#d1d5db",
75
+ borderWidth: 1,
76
+ fontFamily: OAUTH_APPLE_FONT,
77
+ fontWeight: 600,
78
+ fontSize: 16,
79
+ lineHeight: 1.25
80
+ };
81
+ }
82
+ return {
83
+ backgroundColor: "#000000",
84
+ labelColor: "#ffffff",
85
+ iconColor: "#ffffff",
86
+ borderColor: "#000000",
87
+ borderWidth: 1,
88
+ fontFamily: OAUTH_APPLE_FONT,
89
+ fontWeight: 600,
90
+ fontSize: 16,
91
+ lineHeight: 1.25
92
+ };
93
+ }
94
+ return {
95
+ backgroundColor: "#24292f",
96
+ labelColor: "#ffffff",
97
+ iconColor: "#ffffff",
98
+ borderColor: "#24292f",
99
+ borderWidth: 1,
100
+ fontFamily: OAUTH_BODY_FONT,
101
+ fontWeight: 600,
102
+ fontSize: 14,
103
+ lineHeight: 1.25
104
+ };
105
+ };
106
+ var rendererOAuthLoginAlignAxis = (align) => {
107
+ if (align === "center") return "center";
108
+ if (align === "end") return "end";
109
+ if (align === "stretch") return "stretch";
110
+ return "start";
111
+ };
112
+ var rendererOAuthRowInteractionModel = ({
113
+ interactive,
114
+ pendingRowKey,
115
+ rowKey,
116
+ staticPicker = false
117
+ }) => ({
118
+ disabled: pendingRowKey !== null || !staticPicker && !interactive,
119
+ busy: pendingRowKey === rowKey
120
+ });
121
+ var rendererEmailPasswordAuthModel = (layer, values) => {
122
+ const minPasswordLength = layer.minPasswordLength ?? 8;
123
+ const validation = validateEmailPasswordAuthFields({
124
+ mode: layer.mode,
125
+ email: values.email,
126
+ password: values.password,
127
+ confirmPassword: values.confirm,
128
+ minPasswordLength
129
+ });
130
+ return {
131
+ mode: layer.mode,
132
+ minPasswordLength,
133
+ values,
134
+ validation,
135
+ canSubmit: validation.ok
136
+ };
137
+ };
138
+ var rendererEmailPasswordFieldInputType = (slot) => {
139
+ if (slot === "email") return "email";
140
+ if (slot === "password" || slot === "confirm") return "password";
141
+ return "text";
142
+ };
143
+ var rendererEmailPasswordSimInputColors = (theme) => ({
144
+ background: theme === "dark" ? "#18181b" : "#fafafa",
145
+ border: theme === "dark" ? "#27272a" : "#e4e4e7"
146
+ });
147
+
148
+ // src/spacingModel.ts
149
+ var boxEdges = (value) => ({
150
+ top: value?.t ?? 0,
151
+ right: value?.r ?? 0,
152
+ bottom: value?.b ?? 0,
153
+ left: value?.l ?? 0
154
+ });
155
+ var boxEdgesOrUndefined = (value) => value === void 0 ? void 0 : boxEdges(value);
156
+ var rendererLayoutModel = (style) => ({
157
+ padding: boxEdges(style?.padding),
158
+ margin: boxEdges(style?.margin),
159
+ width: style?.width,
160
+ height: style?.height,
161
+ position: style?.position,
162
+ inset: style?.position === "absolute" ? boxEdges(style?.inset) : void 0,
163
+ zIndex: style?.zIndex
164
+ });
165
+ var rendererSurfaceModel = ({
166
+ style,
167
+ theme,
168
+ palette,
169
+ branding
170
+ }) => {
171
+ const nativeBackground = nativeBrandBackgroundFromThemedColor(
172
+ theme,
173
+ branding,
174
+ palette,
175
+ style?.background
176
+ );
177
+ return {
178
+ radius: style?.radius,
179
+ opacity: style?.opacity,
180
+ background: resolveThemedBackground(theme, branding, palette, style?.background),
181
+ nativeBackgroundColor: nativeBackground.solid,
182
+ borderWidth: style?.border?.width,
183
+ borderColor: resolveThemedColor(theme, palette, style?.border?.color),
184
+ webBoxShadow: dropShadowToBoxShadow(style?.shadow, theme, palette),
185
+ nativeShadow: dropShadowToNativeStyle(style?.shadow, theme, palette)
186
+ };
187
+ };
188
+
189
+ // src/carouselModel.ts
190
+ var rendererCarouselSlideIndex = (layer, slideCount) => {
191
+ if (slideCount <= 0) return 0;
192
+ return Math.max(0, Math.min(layer.openOn ?? 0, slideCount - 1));
193
+ };
194
+ var rendererCarouselLayoutModel = (layer) => {
195
+ const alignAxis = layer.pageAlignment === "top" ? "start" : layer.pageAlignment === "bottom" ? "end" : "center";
196
+ return {
197
+ peek: layer.pagePeek ?? 0,
198
+ spacing: layer.pageSpacing ?? 0,
199
+ alignAxis,
200
+ autoAdvanceMs: layer.autoAdvanceMs ?? 4e3,
201
+ loop: layer.loop ?? false,
202
+ slideCount: layer.slides.length
203
+ };
204
+ };
205
+ var rendererCarouselSlideWidth = (containerWidth, peek) => Math.max(0, containerWidth - peek * 2);
206
+ var rendererCarouselPageDotsModel = ({
207
+ layer,
208
+ activeIndex,
209
+ theme,
210
+ manifestTheme
211
+ }) => {
212
+ const pc = layer.pageControl;
213
+ if (!pc) {
214
+ return {
215
+ visible: false,
216
+ position: "bottom",
217
+ spacing: 6,
218
+ padding: boxEdgesOrUndefined(void 0) ?? boxEdges(void 0),
219
+ margin: boxEdgesOrUndefined(void 0) ?? boxEdges(void 0),
220
+ containerSurface: rendererSurfaceModel({
221
+ style: void 0,
222
+ theme: manifestTheme,
223
+ palette: theme
224
+ }),
225
+ dots: []
226
+ };
227
+ }
228
+ const ind = pc.indicators ?? {};
229
+ const defaultColor = resolveThemedColor(manifestTheme, theme, ind.defaultColor) ?? "#52525b";
230
+ const activeColor = resolveThemedColor(manifestTheme, theme, ind.activeColor) ?? "#fafafa";
231
+ const w = ind.width ?? 6;
232
+ const h = ind.height ?? 6;
233
+ const aw = ind.activeWidth ?? w;
234
+ const ah = ind.activeHeight ?? h;
235
+ const dots = layer.slides.map((_, i) => {
236
+ const active = i === activeIndex;
237
+ const dotHeight = active ? ah : h;
238
+ const dotBorder = active ? ind.activeBorder ?? ind.border : ind.border;
239
+ return {
240
+ active,
241
+ width: active ? aw : w,
242
+ height: dotHeight,
243
+ backgroundColor: active ? activeColor : defaultColor,
244
+ opacity: active ? ind.activeOpacity ?? 1 : ind.defaultOpacity ?? 1,
245
+ borderWidth: dotBorder?.width,
246
+ borderColor: resolveThemedColor(manifestTheme, theme, dotBorder?.color),
247
+ borderRadius: Math.max(dotHeight, 1)
248
+ };
249
+ });
250
+ return {
251
+ visible: true,
252
+ position: pc.position,
253
+ spacing: pc.spacing ?? 6,
254
+ padding: boxEdgesOrUndefined(pc.padding) ?? boxEdges(void 0),
255
+ margin: boxEdgesOrUndefined(pc.margin) ?? boxEdges(void 0),
256
+ containerSurface: rendererSurfaceModel({
257
+ style: { border: pc.border, shadow: pc.shadow },
258
+ theme: manifestTheme,
259
+ palette: theme
260
+ }),
261
+ dots
262
+ };
263
+ };
264
+ var rendererCarouselIndexFromScrollOffset = (offset, slideWidth, spacing, slideCount) => {
265
+ if (slideWidth <= 0 || slideCount <= 0) return null;
266
+ const next = Math.round(offset / (slideWidth + spacing));
267
+ if (next < 0 || next >= slideCount) return null;
268
+ return next;
269
+ };
270
+ var rendererCarouselScrollOffset = (index, slideWidth, spacing) => index * (slideWidth + spacing);
271
+ var rendererCarouselShouldEmitComplete = (previousIndex, index, slideCount, loop) => {
272
+ if (loop || slideCount <= 1) return false;
273
+ const last = slideCount - 1;
274
+ return index === last && previousIndex < last;
275
+ };
276
+ var rendererCarouselAdvanceIndex = (index, slideCount, loop) => {
277
+ if (index + 1 < slideCount) return index + 1;
278
+ return loop ? 0 : index;
279
+ };
280
+ var rendererChoiceSelectionModel = (layer, selectedOptionIds) => {
281
+ const selectedSet = new Set(selectedOptionIds);
282
+ const maxSelections = layer.kind === "multiple_choice" ? layer.maxSelections : 1;
283
+ return {
284
+ selectedOptionIds: [...selectedSet],
285
+ selectedSet,
286
+ minSelections: layer.kind === "multiple_choice" ? layer.minSelections : void 0,
287
+ maxSelections,
288
+ canToggleMore: maxSelections === void 0 || selectedSet.size < maxSelections
289
+ };
290
+ };
291
+ var rendererTextInputModel = (layer, value) => {
292
+ const result = validateTextInputValue(layer, value);
293
+ return {
294
+ value,
295
+ trimmedValue: value.trim(),
296
+ required: layer.required !== false,
297
+ valid: result.ok,
298
+ invalidReason: result.ok ? void 0 : result.reason
299
+ };
300
+ };
301
+ var rendererScaleInputModel = (layer, value) => ({
302
+ value,
303
+ snappedValue: snapScaleValue(layer, value),
304
+ step: scaleStep(layer),
305
+ inRange: scaleValueInRange(layer, value),
306
+ onStep: scaleValueIsOnStep(layer, value)
307
+ });
308
+ var rendererTypographyModel = ({
309
+ style,
310
+ theme,
311
+ palette,
312
+ branding,
313
+ fallbackColor
314
+ }) => {
315
+ const color = resolveThemedColor(theme, palette, style?.color ?? fallbackColor);
316
+ return {
317
+ fontFamily: style?.fontFamily,
318
+ webFontFamily: resolveWebTextFontFamilyCss(style?.fontFamily),
319
+ nativeFontFamily: resolveNativeTextFontFamilyName(branding, style?.fontFamily, style?.fontWeight),
320
+ fontSize: style?.fontSize,
321
+ fontWeight: style?.fontWeight,
322
+ color,
323
+ align: style?.align,
324
+ lineHeight: style?.lineHeight
325
+ };
326
+ };
327
+
328
+ export { boxEdges, boxEdgesOrUndefined, rendererButtonActionModel, rendererCarouselAdvanceIndex, rendererCarouselIndexFromScrollOffset, rendererCarouselLayoutModel, rendererCarouselPageDotsModel, rendererCarouselScrollOffset, rendererCarouselShouldEmitComplete, rendererCarouselSlideIndex, rendererCarouselSlideWidth, rendererChoiceSelectionModel, rendererEmailPasswordAuthModel, rendererEmailPasswordFieldInputType, rendererEmailPasswordSimInputColors, rendererLayoutModel, rendererOAuthLoginAlignAxis, rendererOAuthPresetBrandModel, rendererOAuthRowInteractionModel, rendererScaleInputModel, rendererSurfaceModel, rendererTextInputModel, rendererTypographyModel };
329
+ //# sourceMappingURL=index.js.map
330
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/actionModel.ts","../src/authModel.ts","../src/spacingModel.ts","../src/surfaceModel.ts","../src/carouselModel.ts","../src/inputModel.ts","../src/typographyModel.ts"],"names":["resolveThemedColor"],"mappings":"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","file":"index.js","sourcesContent":["import type { ButtonAction } from '@getrheo/contracts/layers';\n\nexport type RendererActionMode = 'interactive' | 'static' | 'native';\n\nexport type RendererButtonActionModel = {\n actionKind: ButtonAction['kind'];\n submitsScreen: boolean;\n recordsSkip: boolean;\n terminal: boolean;\n navigates: boolean;\n requestsPermission: boolean;\n requestsAppReview: boolean;\n disabled: boolean;\n disabledReasons: string[];\n};\n\nexport const rendererButtonActionModel = ({\n action,\n mode,\n checkboxContinueBlocked = false,\n inputDraftInvalid = false,\n nativePermissionAvailable = true,\n}: {\n action: ButtonAction;\n mode: RendererActionMode;\n checkboxContinueBlocked?: boolean;\n inputDraftInvalid?: boolean;\n nativePermissionAvailable?: boolean;\n}): RendererButtonActionModel => {\n const disabledReasons: string[] = [];\n if (mode === 'static') disabledReasons.push('static-mode');\n if (action.kind === 'continue' && checkboxContinueBlocked) disabledReasons.push('checkbox-blocked');\n if (action.kind === 'continue' && inputDraftInvalid) disabledReasons.push('input-invalid');\n if (mode === 'native' && action.kind === 'request_os_permission' && !nativePermissionAvailable) {\n disabledReasons.push('native-permission-unavailable');\n }\n\n return {\n actionKind: action.kind,\n submitsScreen: action.kind === 'continue',\n recordsSkip: action.kind === 'skip',\n terminal: action.kind === 'end_flow',\n navigates: action.kind === 'go_to_step' || action.kind === 'go_back_one_screen',\n requestsPermission: action.kind === 'request_os_permission',\n requestsAppReview: action.kind === 'request_app_review',\n disabled: disabledReasons.length > 0,\n disabledReasons,\n };\n};\n","import type {\n EmailPasswordAuthLayer,\n EmailPasswordAuthMode,\n EmailPasswordSlot,\n OAuthLoginLayer,\n OAuthLoginPreset,\n} from '@getrheo/contracts/layers';\nimport {\n validateEmailPasswordAuthFields,\n type ValidateEmailPasswordAuthResult,\n} from '@getrheo/flow-runtime/emailPasswordAuthValidation';\nimport type { RendererPalette } from './typographyModel';\n\nconst OAUTH_BODY_FONT =\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif';\nconst OAUTH_APPLE_FONT =\n '-apple-system, BlinkMacSystemFont, \"SF Pro Text\", system-ui, sans-serif';\n\nexport type RendererOAuthPresetBrandModel = {\n backgroundColor: string;\n labelColor: string;\n iconColor: string;\n borderColor: string;\n borderWidth: number;\n fontFamily: string;\n fontWeight: number;\n fontSize: number;\n lineHeight: number;\n webBoxShadow?: string;\n};\n\nexport const rendererOAuthPresetBrandModel = (\n preset: OAuthLoginPreset,\n theme: RendererPalette,\n): RendererOAuthPresetBrandModel => {\n if (preset === 'google') {\n const fill = '#4285F4';\n if (theme === 'dark') {\n return {\n backgroundColor: '#ffffff',\n labelColor: fill,\n iconColor: fill,\n borderColor: '#d1d5db',\n borderWidth: 1,\n fontFamily: OAUTH_BODY_FONT,\n fontWeight: 600,\n fontSize: 14,\n lineHeight: 1.25,\n webBoxShadow: '0 1px 2px rgba(0,0,0,0.08)',\n };\n }\n return {\n backgroundColor: fill,\n labelColor: '#ffffff',\n iconColor: '#ffffff',\n borderColor: fill,\n borderWidth: 1,\n fontFamily: OAUTH_BODY_FONT,\n fontWeight: 600,\n fontSize: 14,\n lineHeight: 1.25,\n webBoxShadow: '0 1px 2px rgba(0,0,0,0.12)',\n };\n }\n if (preset === 'apple') {\n if (theme === 'dark') {\n return {\n backgroundColor: '#ffffff',\n labelColor: '#000000',\n iconColor: '#000000',\n borderColor: '#d1d5db',\n borderWidth: 1,\n fontFamily: OAUTH_APPLE_FONT,\n fontWeight: 600,\n fontSize: 16,\n lineHeight: 1.25,\n };\n }\n return {\n backgroundColor: '#000000',\n labelColor: '#ffffff',\n iconColor: '#ffffff',\n borderColor: '#000000',\n borderWidth: 1,\n fontFamily: OAUTH_APPLE_FONT,\n fontWeight: 600,\n fontSize: 16,\n lineHeight: 1.25,\n };\n }\n return {\n backgroundColor: '#24292f',\n labelColor: '#ffffff',\n iconColor: '#ffffff',\n borderColor: '#24292f',\n borderWidth: 1,\n fontFamily: OAUTH_BODY_FONT,\n fontWeight: 600,\n fontSize: 14,\n lineHeight: 1.25,\n };\n};\n\nexport type RendererOAuthAlignAxis = 'start' | 'center' | 'end' | 'stretch';\n\nexport const rendererOAuthLoginAlignAxis = (\n align: OAuthLoginLayer['align'] | undefined,\n): RendererOAuthAlignAxis => {\n if (align === 'center') return 'center';\n if (align === 'end') return 'end';\n if (align === 'stretch') return 'stretch';\n return 'start';\n};\n\nexport type RendererOAuthRowInteractionModel = {\n disabled: boolean;\n busy: boolean;\n};\n\nexport const rendererOAuthRowInteractionModel = ({\n interactive,\n pendingRowKey,\n rowKey,\n staticPicker = false,\n}: {\n interactive: boolean;\n pendingRowKey: string | null;\n rowKey: string;\n /** When true, rows stay enabled for layer picking (builder sim). */\n staticPicker?: boolean;\n}): RendererOAuthRowInteractionModel => ({\n disabled: pendingRowKey !== null || (!staticPicker && !interactive),\n busy: pendingRowKey === rowKey,\n});\n\nexport type RendererEmailPasswordValues = {\n email: string;\n password: string;\n confirm: string;\n};\n\nexport type RendererEmailPasswordAuthModel = {\n mode: EmailPasswordAuthMode;\n minPasswordLength: number;\n values: RendererEmailPasswordValues;\n validation: ValidateEmailPasswordAuthResult;\n canSubmit: boolean;\n};\n\nexport const rendererEmailPasswordAuthModel = (\n layer: Pick<EmailPasswordAuthLayer, 'mode' | 'minPasswordLength'>,\n values: RendererEmailPasswordValues,\n): RendererEmailPasswordAuthModel => {\n const minPasswordLength = layer.minPasswordLength ?? 8;\n const validation = validateEmailPasswordAuthFields({\n mode: layer.mode,\n email: values.email,\n password: values.password,\n confirmPassword: values.confirm,\n minPasswordLength,\n });\n return {\n mode: layer.mode,\n minPasswordLength,\n values,\n validation,\n canSubmit: validation.ok,\n };\n};\n\nexport const rendererEmailPasswordFieldInputType = (\n slot: EmailPasswordSlot,\n): 'email' | 'password' | 'text' => {\n if (slot === 'email') return 'email';\n if (slot === 'password' || slot === 'confirm') return 'password';\n return 'text';\n};\n\nexport type RendererEmailPasswordSimInputColors = {\n background: string;\n border: string;\n};\n\nexport const rendererEmailPasswordSimInputColors = (\n theme: RendererPalette,\n): RendererEmailPasswordSimInputColors => ({\n background: theme === 'dark' ? '#18181b' : '#fafafa',\n border: theme === 'dark' ? '#27272a' : '#e4e4e7',\n});\n","import type { CommonLayoutHeight, Padding, WidthValue } from '@getrheo/contracts/layers';\n\nexport type RendererBoxEdges = {\n top: number;\n right: number;\n bottom: number;\n left: number;\n};\n\nexport type RendererLayoutModel = {\n padding: RendererBoxEdges;\n margin: RendererBoxEdges;\n width: WidthValue | undefined;\n height: CommonLayoutHeight | undefined;\n position: 'absolute' | undefined;\n inset: RendererBoxEdges | undefined;\n zIndex: number | undefined;\n};\n\nexport const boxEdges = (value: Padding | undefined): RendererBoxEdges => ({\n top: value?.t ?? 0,\n right: value?.r ?? 0,\n bottom: value?.b ?? 0,\n left: value?.l ?? 0,\n});\n\nexport const boxEdgesOrUndefined = (value: Padding | undefined): RendererBoxEdges | undefined =>\n value === undefined ? undefined : boxEdges(value);\n\nexport const rendererLayoutModel = (style: {\n padding?: Padding;\n margin?: Padding;\n width?: WidthValue;\n height?: CommonLayoutHeight;\n position?: 'absolute';\n inset?: Padding;\n zIndex?: number;\n} | undefined): RendererLayoutModel => ({\n padding: boxEdges(style?.padding),\n margin: boxEdges(style?.margin),\n width: style?.width,\n height: style?.height,\n position: style?.position,\n inset: style?.position === 'absolute' ? boxEdges(style?.inset) : undefined,\n zIndex: style?.zIndex,\n});\n","import type { Branding } from '@getrheo/contracts/dashboard';\nimport type { Border, DropShadow, ThemedColor } from '@getrheo/contracts/layers';\nimport type { Theme } from '@getrheo/contracts/manifest';\nimport {\n dropShadowToBoxShadow,\n dropShadowToNativeStyle,\n nativeBrandBackgroundFromThemedColor,\n resolveThemedBackground,\n resolveThemedColor,\n type NativeDropShadowStyle,\n} from '@getrheo/flow-runtime';\nimport type { RendererPalette } from './typographyModel';\n\nexport type RendererSurfaceModel = {\n radius: number | undefined;\n opacity: number | undefined;\n background: string | undefined;\n nativeBackgroundColor: string | undefined;\n borderWidth: number | undefined;\n borderColor: string | undefined;\n webBoxShadow: string | undefined;\n nativeShadow: NativeDropShadowStyle;\n};\n\nexport const rendererSurfaceModel = ({\n style,\n theme,\n palette,\n branding,\n}: {\n style:\n | {\n radius?: number;\n opacity?: number;\n background?: ThemedColor;\n border?: Border;\n shadow?: DropShadow;\n }\n | undefined;\n theme: Theme | undefined;\n palette: RendererPalette;\n branding?: Branding;\n}): RendererSurfaceModel => {\n const nativeBackground = nativeBrandBackgroundFromThemedColor(\n theme,\n branding,\n palette,\n style?.background,\n );\n return {\n radius: style?.radius,\n opacity: style?.opacity,\n background: resolveThemedBackground(theme, branding, palette, style?.background),\n nativeBackgroundColor: nativeBackground.solid,\n borderWidth: style?.border?.width,\n borderColor: resolveThemedColor(theme, palette, style?.border?.color),\n webBoxShadow: dropShadowToBoxShadow(style?.shadow, theme, palette),\n nativeShadow: dropShadowToNativeStyle(style?.shadow, theme, palette),\n };\n};\n","import type { CarouselLayer } from '@getrheo/contracts/layers';\nimport type { Theme } from '@getrheo/contracts/manifest';\nimport { resolveThemedColor } from '@getrheo/flow-runtime';\nimport { boxEdges, boxEdgesOrUndefined, type RendererBoxEdges } from './spacingModel';\nimport { rendererSurfaceModel } from './surfaceModel';\nimport type { RendererPalette } from './typographyModel';\n\nexport type RendererCarouselAlignAxis = 'start' | 'center' | 'end';\n\nexport const rendererCarouselSlideIndex = (\n layer: Pick<CarouselLayer, 'openOn'>,\n slideCount: number,\n): number => {\n if (slideCount <= 0) return 0;\n return Math.max(0, Math.min(layer.openOn ?? 0, slideCount - 1));\n};\n\nexport type RendererCarouselLayoutModel = {\n peek: number;\n spacing: number;\n alignAxis: RendererCarouselAlignAxis;\n autoAdvanceMs: number;\n loop: boolean;\n slideCount: number;\n};\n\nexport const rendererCarouselLayoutModel = (layer: CarouselLayer): RendererCarouselLayoutModel => {\n const alignAxis: RendererCarouselAlignAxis =\n layer.pageAlignment === 'top'\n ? 'start'\n : layer.pageAlignment === 'bottom'\n ? 'end'\n : 'center';\n return {\n peek: layer.pagePeek ?? 0,\n spacing: layer.pageSpacing ?? 0,\n alignAxis,\n autoAdvanceMs: layer.autoAdvanceMs ?? 4000,\n loop: layer.loop ?? false,\n slideCount: layer.slides.length,\n };\n};\n\nexport const rendererCarouselSlideWidth = (containerWidth: number, peek: number): number =>\n Math.max(0, containerWidth - peek * 2);\n\nexport type RendererCarouselPageDotModel = {\n active: boolean;\n width: number;\n height: number;\n backgroundColor: string;\n opacity: number;\n borderWidth: number | undefined;\n borderColor: string | undefined;\n borderRadius: number;\n};\n\nexport type RendererCarouselPageDotsModel = {\n visible: boolean;\n position: 'top' | 'bottom';\n spacing: number;\n padding: RendererBoxEdges;\n margin: RendererBoxEdges;\n containerSurface: ReturnType<typeof rendererSurfaceModel>;\n dots: RendererCarouselPageDotModel[];\n};\n\nexport const rendererCarouselPageDotsModel = ({\n layer,\n activeIndex,\n theme,\n manifestTheme,\n}: {\n layer: CarouselLayer;\n activeIndex: number;\n theme: RendererPalette;\n manifestTheme: Theme | undefined;\n}): RendererCarouselPageDotsModel => {\n const pc = layer.pageControl;\n if (!pc) {\n return {\n visible: false,\n position: 'bottom',\n spacing: 6,\n padding: boxEdgesOrUndefined(undefined) ?? boxEdges(undefined),\n margin: boxEdgesOrUndefined(undefined) ?? boxEdges(undefined),\n containerSurface: rendererSurfaceModel({\n style: undefined,\n theme: manifestTheme,\n palette: theme,\n }),\n dots: [],\n };\n }\n\n const ind = pc.indicators ?? {};\n const defaultColor =\n (resolveThemedColor(manifestTheme, theme, ind.defaultColor) as string | undefined) ??\n '#52525b';\n const activeColor =\n (resolveThemedColor(manifestTheme, theme, ind.activeColor) as string | undefined) ??\n '#fafafa';\n const w = ind.width ?? 6;\n const h = ind.height ?? 6;\n const aw = ind.activeWidth ?? w;\n const ah = ind.activeHeight ?? h;\n\n const dots = layer.slides.map((_, i) => {\n const active = i === activeIndex;\n const dotHeight = active ? ah : h;\n const dotBorder = active ? ind.activeBorder ?? ind.border : ind.border;\n return {\n active,\n width: active ? aw : w,\n height: dotHeight,\n backgroundColor: active ? activeColor : defaultColor,\n opacity: active ? ind.activeOpacity ?? 1 : ind.defaultOpacity ?? 1,\n borderWidth: dotBorder?.width,\n borderColor: resolveThemedColor(manifestTheme, theme, dotBorder?.color),\n borderRadius: Math.max(dotHeight, 1),\n };\n });\n\n return {\n visible: true,\n position: pc.position,\n spacing: pc.spacing ?? 6,\n padding: boxEdgesOrUndefined(pc.padding) ?? boxEdges(undefined),\n margin: boxEdgesOrUndefined(pc.margin) ?? boxEdges(undefined),\n containerSurface: rendererSurfaceModel({\n style: { border: pc.border, shadow: pc.shadow },\n theme: manifestTheme,\n palette: theme,\n }),\n dots,\n };\n};\n\nexport const rendererCarouselIndexFromScrollOffset = (\n offset: number,\n slideWidth: number,\n spacing: number,\n slideCount: number,\n): number | null => {\n if (slideWidth <= 0 || slideCount <= 0) return null;\n const next = Math.round(offset / (slideWidth + spacing));\n if (next < 0 || next >= slideCount) return null;\n return next;\n};\n\nexport const rendererCarouselScrollOffset = (\n index: number,\n slideWidth: number,\n spacing: number,\n): number => index * (slideWidth + spacing);\n\n/** Swipe-only carousels: emit flow completion when the user lands on the last slide. */\nexport const rendererCarouselShouldEmitComplete = (\n previousIndex: number,\n index: number,\n slideCount: number,\n loop: boolean,\n): boolean => {\n if (loop || slideCount <= 1) return false;\n const last = slideCount - 1;\n return index === last && previousIndex < last;\n};\n\nexport const rendererCarouselAdvanceIndex = (\n index: number,\n slideCount: number,\n loop: boolean,\n): number => {\n if (index + 1 < slideCount) return index + 1;\n return loop ? 0 : index;\n};\n","import type {\n MultipleChoiceLayer,\n ScaleInputLayer,\n SingleChoiceLayer,\n TextInputLayer,\n} from '@getrheo/contracts/layers';\nimport {\n scaleStep,\n scaleValueInRange,\n scaleValueIsOnStep,\n snapScaleValue,\n validateTextInputValue,\n} from '@getrheo/flow-runtime';\n\nexport type RendererChoiceSelectionModel = {\n selectedOptionIds: string[];\n selectedSet: Set<string>;\n minSelections: number | undefined;\n maxSelections: number | undefined;\n canToggleMore: boolean;\n};\n\nexport const rendererChoiceSelectionModel = (\n layer: SingleChoiceLayer | MultipleChoiceLayer,\n selectedOptionIds: readonly string[],\n): RendererChoiceSelectionModel => {\n const selectedSet = new Set(selectedOptionIds);\n const maxSelections = layer.kind === 'multiple_choice' ? layer.maxSelections : 1;\n return {\n selectedOptionIds: [...selectedSet],\n selectedSet,\n minSelections: layer.kind === 'multiple_choice' ? layer.minSelections : undefined,\n maxSelections,\n canToggleMore: maxSelections === undefined || selectedSet.size < maxSelections,\n };\n};\n\nexport type RendererTextInputModel = {\n value: string;\n trimmedValue: string;\n required: boolean;\n valid: boolean;\n invalidReason: string | undefined;\n};\n\nexport const rendererTextInputModel = (\n layer: TextInputLayer,\n value: string,\n): RendererTextInputModel => {\n const result = validateTextInputValue(layer, value);\n return {\n value,\n trimmedValue: value.trim(),\n required: layer.required !== false,\n valid: result.ok,\n invalidReason: result.ok ? undefined : result.reason,\n };\n};\n\nexport type RendererScaleInputModel = {\n value: number;\n snappedValue: number;\n step: number;\n inRange: boolean;\n onStep: boolean;\n};\n\nexport const rendererScaleInputModel = (\n layer: ScaleInputLayer,\n value: number,\n): RendererScaleInputModel => ({\n value,\n snappedValue: snapScaleValue(layer, value),\n step: scaleStep(layer),\n inRange: scaleValueInRange(layer, value),\n onStep: scaleValueIsOnStep(layer, value),\n});\n","import type { Branding } from '@getrheo/contracts/dashboard';\nimport type { TextStyle, ThemedColor } from '@getrheo/contracts/layers';\nimport type { Theme } from '@getrheo/contracts/manifest';\nimport {\n resolveNativeTextFontFamilyName,\n resolveThemedColor,\n resolveWebTextFontFamilyCss,\n} from '@getrheo/flow-runtime';\n\nexport type RendererPalette = 'light' | 'dark';\n\nexport type RendererTypographyModel = {\n fontFamily: string | undefined;\n webFontFamily: string | undefined;\n nativeFontFamily: string | undefined;\n fontSize: number | undefined;\n fontWeight: number | undefined;\n color: string | undefined;\n align: TextStyle['align'];\n lineHeight: number | undefined;\n};\n\nexport const rendererTypographyModel = ({\n style,\n theme,\n palette,\n branding,\n fallbackColor,\n}: {\n style: Pick<\n TextStyle,\n 'fontFamily' | 'fontSize' | 'fontWeight' | 'color' | 'align' | 'lineHeight'\n > | undefined;\n theme: Theme | undefined;\n palette: RendererPalette;\n branding?: Branding;\n fallbackColor?: ThemedColor;\n}): RendererTypographyModel => {\n const color = resolveThemedColor(theme, palette, style?.color ?? fallbackColor);\n return {\n fontFamily: style?.fontFamily,\n webFontFamily: resolveWebTextFontFamilyCss(style?.fontFamily),\n nativeFontFamily: resolveNativeTextFontFamilyName(branding, style?.fontFamily, style?.fontWeight),\n fontSize: style?.fontSize,\n fontWeight: style?.fontWeight,\n color,\n align: style?.align,\n lineHeight: style?.lineHeight,\n };\n};\n"]}
@@ -0,0 +1,6 @@
1
+ [
2
+ {
3
+ "exportKey": ".",
4
+ "distFile": "./dist/index.js"
5
+ }
6
+ ]
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@getrheo/renderer-core",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "@getrheo/contracts": "1.0.0",
16
+ "@getrheo/flow-runtime": "1.0.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^22.10.1",
20
+ "typescript": "^5.6.3",
21
+ "vitest": "^3.2.6",
22
+ "@rheo/config": "0.1.0"
23
+ },
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/madeinusmate/onboardly.git",
28
+ "directory": "packages/renderer-core"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "lint": "eslint .",
39
+ "typecheck": "tsc --noEmit",
40
+ "test": "vitest run",
41
+ "build": "node ../../scripts/build-publishable-package.mjs"
42
+ }
43
+ }