@thewhileloop/whileui 4.0.0 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +186 -20
  2. package/dist/blocks/chat/chat-conversation.d.ts +8 -0
  3. package/dist/blocks/chat/chat-conversation.js +36 -0
  4. package/dist/blocks/chat/chat.js +5 -11
  5. package/dist/blocks/chat/index.d.ts +1 -0
  6. package/dist/blocks/chat/index.js +1 -0
  7. package/dist/blocks/layout/smart-input.js +2 -1
  8. package/dist/blocks/media/smart-image.js +5 -7
  9. package/dist/code.d.ts +1 -0
  10. package/dist/code.js +1 -0
  11. package/dist/components/avatar/avatar.d.ts +3 -2
  12. package/dist/components/avatar/avatar.js +19 -13
  13. package/dist/components/avatar/index.d.ts +1 -1
  14. package/dist/components/card/card.d.ts +1 -1
  15. package/dist/components/card/card.js +4 -25
  16. package/dist/components/code-block/code-block.d.ts +12 -0
  17. package/dist/components/code-block/code-block.js +13 -0
  18. package/dist/components/code-block/index.d.ts +1 -0
  19. package/dist/components/code-block/index.js +1 -0
  20. package/dist/components/form-field/form-field.d.ts +8 -0
  21. package/dist/components/form-field/form-field.js +3 -0
  22. package/dist/components/form-field/index.d.ts +1 -1
  23. package/dist/components/form-field/index.js +1 -1
  24. package/dist/components/input/input.d.ts +1 -0
  25. package/dist/components/input/input.js +11 -6
  26. package/dist/components/markdown/index.d.ts +1 -0
  27. package/dist/components/markdown/index.js +1 -0
  28. package/dist/components/markdown/markdown.d.ts +14 -0
  29. package/dist/components/markdown/markdown.js +94 -0
  30. package/dist/components/numeric-input/numeric-input.d.ts +1 -0
  31. package/dist/components/numeric-input/numeric-input.js +11 -6
  32. package/dist/components/select/select.d.ts +2 -1
  33. package/dist/components/select/select.js +44 -24
  34. package/dist/components/surface/index.d.ts +1 -0
  35. package/dist/components/surface/index.js +1 -0
  36. package/dist/components/surface/surface.d.ts +14 -0
  37. package/dist/components/surface/surface.js +35 -0
  38. package/dist/components/text/text.d.ts +42 -42
  39. package/dist/components/text/text.js +39 -17
  40. package/dist/components/textarea/textarea.d.ts +1 -0
  41. package/dist/components/textarea/textarea.js +7 -3
  42. package/dist/components/toast/toast.js +5 -1
  43. package/dist/index.d.ts +3 -2
  44. package/dist/index.js +2 -1
  45. package/dist/lib/theme-bridge.d.ts +1 -1
  46. package/dist/lib/theme-bridge.js +52 -18
  47. package/dist/lib/web-autofill.d.ts +9 -0
  48. package/dist/lib/web-autofill.js +9 -0
  49. package/dist/markdown.d.ts +1 -0
  50. package/dist/markdown.js +1 -0
  51. package/package.json +16 -2
@@ -4,37 +4,59 @@ import { Text as RNText } from 'react-native';
4
4
  import { cn } from '../../lib/cn';
5
5
  import { tv } from '../../lib/tv';
6
6
  import { useResolveFontFamily } from '../../lib/font-context';
7
+ import { useTypography } from '../../lib/recipes';
7
8
  const textVariants = tv({
8
9
  base: 'text-foreground',
9
10
  variants: {
10
11
  variant: {
11
12
  default: 'font-normal',
12
- heading: 'text-2xl font-bold tracking-tight',
13
- title: 'text-xl font-semibold',
14
- subtitle: 'text-lg font-medium',
15
- body: 'text-base font-normal',
16
- caption: 'text-sm text-muted-foreground font-normal',
17
- label: 'text-sm font-medium leading-tight',
18
- code: 'font-mono text-sm bg-muted rounded px-1 py-0.5',
13
+ heading: 'font-bold tracking-tight',
14
+ title: 'font-semibold',
15
+ subtitle: 'font-medium',
16
+ body: 'font-normal',
17
+ caption: 'text-muted-foreground font-normal',
18
+ label: 'font-medium leading-tight',
19
+ code: 'font-mono bg-muted rounded px-1 py-0.5',
19
20
  },
20
21
  size: {
21
- xs: 'text-xs',
22
- sm: 'text-sm',
23
- base: 'text-base',
24
- lg: 'text-lg',
25
- xl: 'text-xl',
26
- '2xl': 'text-2xl',
27
- '3xl': 'text-3xl',
22
+ xs: '',
23
+ sm: '',
24
+ base: '',
25
+ lg: '',
26
+ xl: '',
27
+ '2xl': '',
28
+ '3xl': '',
28
29
  },
29
30
  },
30
31
  defaultVariants: {
31
32
  variant: 'default',
32
33
  },
33
34
  });
34
- const Text = React.forwardRef(({ className, variant, size, style, ...props }, ref) => {
35
- const resolved = cn(textVariants({ variant, size }), className);
35
+ const VARIANT_ROLES = {
36
+ default: 'body',
37
+ heading: 'headline',
38
+ title: 'title',
39
+ subtitle: 'emphasis',
40
+ body: 'body',
41
+ caption: 'caption',
42
+ label: 'label',
43
+ code: 'label',
44
+ };
45
+ const SIZE_ROLES = {
46
+ xs: 'caption',
47
+ sm: 'label',
48
+ base: 'body',
49
+ lg: 'emphasis',
50
+ xl: 'title',
51
+ '2xl': 'headline',
52
+ '3xl': 'headline',
53
+ };
54
+ const Text = React.forwardRef(({ className, variant, size, style, accessibilityRole, ...props }, ref) => {
55
+ const effectiveVariant = variant ?? 'default';
56
+ const resolved = cn(textVariants({ variant: effectiveVariant, size }), className);
36
57
  const font = useResolveFontFamily(resolved);
37
- return (_jsx(RNText, { ref: ref, className: font ? font.className : resolved, style: font ? [font.style, style] : style, ...props }));
58
+ const semanticStyle = useTypography(size ? SIZE_ROLES[size] : VARIANT_ROLES[effectiveVariant]);
59
+ return (_jsx(RNText, { ref: ref, className: font ? font.className : resolved, accessibilityRole: accessibilityRole ?? (effectiveVariant === 'heading' ? 'header' : undefined), style: [variant || size ? semanticStyle : undefined, font?.style, style], ...props }));
38
60
  });
39
61
  Text.displayName = 'Text';
40
62
  export { Text, textVariants };
@@ -21,6 +21,7 @@ declare const textareaVariants: import("tailwind-variants").TVReturnType<{
21
21
  };
22
22
  }, undefined>>;
23
23
  export interface TextareaProps extends Omit<TextInputProps, 'style'>, VariantProps<typeof textareaVariants> {
24
+ 'aria-invalid'?: boolean;
24
25
  className?: string;
25
26
  }
26
27
  declare const Textarea: ForwardRefComponent<TextInputInstance, TextareaProps>;
@@ -8,6 +8,8 @@ import { useThemeColors } from '../../lib/theme-colors';
8
8
  import { useInteractionTokens } from '../../lib/interaction-tokens';
9
9
  import { useVisualTokens } from '../../lib/visual-tokens';
10
10
  import { typographyStyle } from '../../lib/recipes';
11
+ import { webAutofillField } from '../../lib/web-autofill';
12
+ import { useFormFieldState } from '../form-field/form-field';
11
13
  const textareaVariants = tv({
12
14
  base: 'w-full border-border bg-muted text-foreground',
13
15
  variants: {
@@ -26,10 +28,12 @@ const TEXTAREA_TEXT_ROLE = {
26
28
  sm: 'caption',
27
29
  lg: 'body',
28
30
  };
29
- const Textarea = React.forwardRef(({ className, size = 'default', placeholderTextColor, ...props }, ref) => {
31
+ const Textarea = React.forwardRef(({ className, size = 'default', placeholderTextColor, editable, 'aria-invalid': ariaInvalid, ...props }, ref) => {
30
32
  const colors = useThemeColors();
31
33
  const interaction = useInteractionTokens();
32
34
  const visual = useVisualTokens();
35
+ const field = useFormFieldState();
36
+ const effectiveEditable = editable ?? !field.disabled;
33
37
  const minHeight = size === 'sm'
34
38
  ? visual.textareaMinHeightSm
35
39
  : size === 'lg'
@@ -42,9 +46,9 @@ const Textarea = React.forwardRef(({ className, size = 'default', placeholderTex
42
46
  borderRadius: visual.radiusLg,
43
47
  paddingHorizontal: visual.controlPaddingXDefault,
44
48
  paddingVertical: visual.controlPaddingYDefault,
45
- ...(props.editable === false ? { opacity: interaction.disabledOpacity } : null),
49
+ ...(!effectiveEditable ? { opacity: interaction.disabledOpacity } : null),
46
50
  };
47
- return (_jsx(TextInput, { ref: ref, className: cn(textareaVariants({ size }), focusField, className), style: style, multiline: true, textAlignVertical: "top", placeholderTextColor: placeholderTextColor ?? colors.placeholder, ...props }));
51
+ return (_jsx(TextInput, { ref: ref, className: cn(textareaVariants({ size }), field.invalid && 'border-destructive', focusField, webAutofillField, className), style: style, multiline: true, textAlignVertical: "top", placeholderTextColor: placeholderTextColor ?? colors.placeholder, editable: effectiveEditable, "aria-invalid": ariaInvalid ?? field.invalid, ...props }));
48
52
  });
49
53
  Textarea.displayName = 'Textarea';
50
54
  export { Textarea, textareaVariants };
@@ -86,10 +86,14 @@ function Toast({ toast: toastData, onDismiss, className, style, ...props }) {
86
86
  paddingVertical: visual.controlPaddingYSm,
87
87
  }, children: _jsx(Text, { className: cn('font-medium', textColor), style: typographyStyle(visual, 'label'), children: action.label }) })), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Dismiss", onPress: onDismiss, className: "p-1", children: _jsx(Text, { className: cn(textColor), style: typographyStyle(visual, 'emphasis'), children: "\u00D7" }) })] })] }));
88
88
  }
89
+ function ToastContainerItem({ toast, dismiss, }) {
90
+ const handleDismiss = useCallback(() => dismiss(toast.id), [dismiss, toast.id]);
91
+ return (_jsx(View, { className: "mb-2", children: _jsx(Toast, { toast: toast, onDismiss: handleDismiss }) }));
92
+ }
89
93
  export function ToastContainer({ position = 'top', className, style, ...props }) {
90
94
  const { toasts, dismiss } = useToast();
91
95
  const visual = useVisualTokens();
92
96
  const positionClass = position === 'top' ? 'top-0' : 'bottom-0';
93
- return (_jsx(View, { className: cn('absolute left-0 right-0 z-50 py-2', positionClass, className), style: [{ paddingHorizontal: visual.surfacePaddingSm }, style], pointerEvents: "box-none", ...props, children: toasts.map((toast) => (_jsx(View, { className: "mb-2", children: _jsx(Toast, { toast: toast, onDismiss: () => dismiss(toast.id) }) }, toast.id))) }));
97
+ return (_jsx(View, { className: cn('absolute left-0 right-0 z-50 py-2', positionClass, className), style: [{ paddingHorizontal: visual.surfacePaddingSm }, style], pointerEvents: "box-none", ...props, children: toasts.map((toast) => (_jsx(ToastContainerItem, { toast: toast, dismiss: dismiss }, toast.id))) }));
94
98
  }
95
99
  export { Toast, toastVariants };
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export { controlRecipe, fieldRecipe, surfaceRecipe, surfacePadding, surfaceRadiu
16
16
  export { WHILEUI_PRESET_SOFT, WHILEUI_PRESET_ATELIER, WHILEUI_THEME_PRESETS, themePresetToCssVariables, themePresetToCss, type ThemePreset, } from './lib/theme-presets';
17
17
  export { deriveThemeColors, THEME_BASE_TOKEN_KEYS, type ThemeBaseColors } from './lib/theme-derive';
18
18
  export { Text, textVariants, type TextProps } from './components/text';
19
+ export { Surface, type SurfaceLevel, type SurfaceProps } from './components/surface';
19
20
  export { View, type ViewProps } from './components/view';
20
21
  export { Pressable, type PressableProps } from './components/pressable';
21
22
  export { Stack, stackVariants, type StackProps } from './components/stack';
@@ -25,7 +26,7 @@ export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter,
25
26
  export { Input, inputVariants, type InputProps } from './components/input';
26
27
  export { NumericInput, numericInputVariants, numericInputTextVariants, type NumericInputProps, } from './components/numeric-input';
27
28
  export { OTPInput, otpCellVariants, type OTPInputProps } from './components/otp-input';
28
- export { FormField, FormLabel, FormControl, FormHint, FormMessage, formFieldVariants, formControlVariants, type FormFieldProps, type FormLabelProps, type FormControlProps, type FormHintProps, type FormMessageProps, } from './components/form-field';
29
+ export { FormField, FormLabel, FormControl, FormHint, FormMessage, useFormFieldState, formFieldVariants, formControlVariants, type FormFieldProps, type FormLabelProps, type FormControlProps, type FormHintProps, type FormMessageProps, type FormFieldState, } from './components/form-field';
29
30
  export { LabeledField, LabeledFieldControl, type LabeledFieldProps, type LabeledFieldControlProps, } from './components/labeled-field';
30
31
  export { Badge, BadgeText, badgeVariants, badgeTextVariants, type BadgeProps, type BadgeTextProps, } from './components/badge';
31
32
  export { FAB, FABGroup, fabVariants, type FabProps, type FabGroupProps } from './components/fab';
@@ -39,7 +40,7 @@ export { Spinner, spinnerVariants, type SpinnerProps } from './components/spinne
39
40
  export { Textarea, textareaVariants, type TextareaProps } from './components/textarea';
40
41
  export { Skeleton, skeletonVariants, type SkeletonProps } from './components/skeleton';
41
42
  export { AspectRatio, type AspectRatioProps } from './components/aspect-ratio';
42
- export { Avatar, AvatarImage, AvatarFallback, avatarVariants, type AvatarProps, type AvatarImageProps, type AvatarFallbackProps, } from './components/avatar';
43
+ export { Avatar, AvatarImage, AvatarFallback, avatarVariants, type AvatarProps, type AvatarImageProps, type AvatarImageStatus, type AvatarFallbackProps, } from './components/avatar';
43
44
  export { Accordion, AccordionItem, AccordionTrigger, AccordionContent, type AccordionProps, type AccordionItemProps, type AccordionTriggerProps, type AccordionContentProps, } from './components/accordion';
44
45
  export { Collapsible, CollapsibleTrigger, CollapsibleContent, type CollapsibleProps, type CollapsibleTriggerProps, type CollapsibleContentProps, } from './components/collapsible';
45
46
  export { Container, containerVariants, type ContainerProps } from './components/container';
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export { controlRecipe, fieldRecipe, surfaceRecipe, surfacePadding, surfaceRadiu
16
16
  export { WHILEUI_PRESET_SOFT, WHILEUI_PRESET_ATELIER, WHILEUI_THEME_PRESETS, themePresetToCssVariables, themePresetToCss, } from './lib/theme-presets';
17
17
  export { deriveThemeColors, THEME_BASE_TOKEN_KEYS } from './lib/theme-derive';
18
18
  export { Text, textVariants } from './components/text';
19
+ export { Surface } from './components/surface';
19
20
  export { View } from './components/view';
20
21
  export { Pressable } from './components/pressable';
21
22
  export { Stack, stackVariants } from './components/stack';
@@ -25,7 +26,7 @@ export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter,
25
26
  export { Input, inputVariants } from './components/input';
26
27
  export { NumericInput, numericInputVariants, numericInputTextVariants, } from './components/numeric-input';
27
28
  export { OTPInput, otpCellVariants } from './components/otp-input';
28
- export { FormField, FormLabel, FormControl, FormHint, FormMessage, formFieldVariants, formControlVariants, } from './components/form-field';
29
+ export { FormField, FormLabel, FormControl, FormHint, FormMessage, useFormFieldState, formFieldVariants, formControlVariants, } from './components/form-field';
29
30
  export { LabeledField, LabeledFieldControl, } from './components/labeled-field';
30
31
  export { Badge, BadgeText, badgeVariants, badgeTextVariants, } from './components/badge';
31
32
  export { FAB, FABGroup, fabVariants } from './components/fab';
@@ -23,7 +23,7 @@ export declare function applyThemeMode(mode: ThemeMode): void;
23
23
  export declare function resolveThemeMode(adapter?: ThemeBridgeAdapter, fallback?: ThemeMode): Promise<ThemeMode>;
24
24
  export declare function syncThemeMode(mode: ThemeMode, adapter?: ThemeBridgeAdapter): Promise<ThemeMode>;
25
25
  export declare function useThemeBridge({ initialMode, adapter, }?: UseThemeBridgeOptions): UseThemeBridgeResult;
26
- export declare function ThemeBridge({ mode, initialMode, adapter }: ThemeBridgeProps): import("react").FunctionComponentElement<Pick<ThemeBridgeProps, "initialMode" | "adapter">> | import("react").FunctionComponentElement<{
26
+ export declare function ThemeBridge({ mode, initialMode, adapter }: ThemeBridgeProps): import("react").FunctionComponentElement<Pick<ThemeBridgeProps, "adapter" | "initialMode">> | import("react").FunctionComponentElement<{
27
27
  mode: ThemeMode;
28
28
  adapter?: ThemeBridgeAdapter;
29
29
  }>;
@@ -1,6 +1,37 @@
1
- import { createElement, useCallback, useEffect, useMemo, useState } from 'react';
1
+ import { createElement, useCallback, useEffect, useMemo, useReducer } from 'react';
2
2
  import { Uniwind, useUniwind } from 'uniwind';
3
3
  const modeCycle = ['light', 'dark', 'system'];
4
+ function themeBridgeReducer(state, action) {
5
+ if (action.type === 'cycle') {
6
+ return {
7
+ ...state,
8
+ status: 'ready',
9
+ mode: modeCycle[(modeCycle.indexOf(state.mode) + 1) % modeCycle.length],
10
+ };
11
+ }
12
+ if (action.type === 'select') {
13
+ return { ...state, status: 'ready', mode: action.mode };
14
+ }
15
+ if (action.type === 'hydrate') {
16
+ if (state.adapter === action.adapter &&
17
+ state.initialMode === action.initialMode &&
18
+ state.status === (action.adapter ? 'hydrating' : 'ready')) {
19
+ return state;
20
+ }
21
+ return {
22
+ status: action.adapter ? 'hydrating' : 'ready',
23
+ mode: state.mode,
24
+ adapter: action.adapter,
25
+ initialMode: action.initialMode,
26
+ };
27
+ }
28
+ if (state.status !== 'hydrating' ||
29
+ state.adapter !== action.adapter ||
30
+ state.initialMode !== action.initialMode) {
31
+ return state;
32
+ }
33
+ return { ...state, status: 'ready', mode: action.mode };
34
+ }
4
35
  export function applyThemeMode(mode) {
5
36
  Uniwind.setTheme(mode);
6
37
  }
@@ -23,16 +54,21 @@ export async function syncThemeMode(mode, adapter) {
23
54
  }
24
55
  export function useThemeBridge({ initialMode = 'system', adapter, } = {}) {
25
56
  const { theme } = useUniwind();
26
- const [mode, setMode] = useState(initialMode);
27
- const [hydrated, setHydrated] = useState(!adapter);
57
+ const [state, dispatch] = useReducer(themeBridgeReducer, {
58
+ status: adapter ? 'hydrating' : 'ready',
59
+ mode: initialMode,
60
+ adapter,
61
+ initialMode,
62
+ });
28
63
  useEffect(() => {
29
64
  let mounted = true;
65
+ dispatch({ type: 'hydrate', adapter, initialMode });
30
66
  if (!adapter) {
31
67
  return;
32
68
  }
33
69
  // `loadThemeMode` is the consumer's storage. If it rejects — a corrupt store, a
34
70
  // keychain prompt the user dismissed — the app must still render in the initial
35
- // mode; leaving `hydrated` false would strand anything gated on it forever.
71
+ // mode rather than remaining in the hydrating phase forever.
36
72
  void (async () => {
37
73
  let next;
38
74
  try {
@@ -44,35 +80,33 @@ export function useThemeBridge({ initialMode = 'system', adapter, } = {}) {
44
80
  if (!mounted) {
45
81
  return;
46
82
  }
47
- setMode(next);
48
- setHydrated(true);
83
+ dispatch({ type: 'hydrated', adapter, initialMode, mode: next });
49
84
  })();
50
85
  return () => {
51
86
  mounted = false;
52
87
  };
53
88
  }, [adapter, initialMode]);
54
89
  useEffect(() => {
55
- if (!hydrated) {
90
+ if (state.status !== 'ready' ||
91
+ state.adapter !== adapter ||
92
+ state.initialMode !== initialMode) {
56
93
  return;
57
94
  }
58
- applyThemeMode(mode);
95
+ applyThemeMode(state.mode);
59
96
  if (adapter) {
60
- void adapter.saveThemeMode(mode);
97
+ void adapter.saveThemeMode(state.mode);
61
98
  }
62
- }, [adapter, hydrated, mode]);
63
- const cycleMode = useCallback(() => {
64
- setMode((currentMode) => {
65
- const currentIndex = modeCycle.indexOf(currentMode);
66
- const nextIndex = (currentIndex + 1) % modeCycle.length;
67
- return modeCycle[nextIndex];
68
- });
99
+ }, [adapter, initialMode, state]);
100
+ const setMode = useCallback((mode) => {
101
+ dispatch({ type: 'select', mode });
69
102
  }, []);
103
+ const cycleMode = useCallback(() => dispatch({ type: 'cycle' }), []);
70
104
  return useMemo(() => ({
71
- mode,
105
+ mode: state.mode,
72
106
  resolvedTheme: theme,
73
107
  setMode,
74
108
  cycleMode,
75
- }), [cycleMode, mode, theme]);
109
+ }), [cycleMode, setMode, state.mode, theme]);
76
110
  }
77
111
  function ControlledThemeBridge({ mode, adapter, }) {
78
112
  useEffect(() => {
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Browser autofill paints its own field background and text colours. The large inset
3
+ * shadow covers that paint without changing the native style contract; the other two
4
+ * declarations restore the active theme's text and caret.
5
+ *
6
+ * Apply only to fields whose own surface is `bg-muted`. Transparent/unstyled inputs
7
+ * must keep inheriting the surface chosen by their composition.
8
+ */
9
+ export declare const webAutofillField = "web:autofill:shadow-[inset_0_0_0_1000px_var(--color-muted)] web:autofill:[-webkit-text-fill-color:var(--color-foreground)] web:autofill:caret-foreground";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Browser autofill paints its own field background and text colours. The large inset
3
+ * shadow covers that paint without changing the native style contract; the other two
4
+ * declarations restore the active theme's text and caret.
5
+ *
6
+ * Apply only to fields whose own surface is `bg-muted`. Transparent/unstyled inputs
7
+ * must keep inheriting the surface chosen by their composition.
8
+ */
9
+ export const webAutofillField = 'web:autofill:shadow-[inset_0_0_0_1000px_var(--color-muted)] web:autofill:[-webkit-text-fill-color:var(--color-foreground)] web:autofill:caret-foreground';
@@ -0,0 +1 @@
1
+ export { Markdown, type MarkdownProps } from './components/markdown';
@@ -0,0 +1 @@
1
+ export { Markdown } from './components/markdown';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thewhileloop/whileui",
3
- "version": "4.0.0",
3
+ "version": "4.1.1",
4
4
  "description": "WhileUI Native — Copy-paste components for React Native. You own the code.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -40,6 +40,14 @@
40
40
  "types": "./dist/tokens.d.ts",
41
41
  "import": "./dist/tokens.js"
42
42
  },
43
+ "./code": {
44
+ "types": "./dist/code.d.ts",
45
+ "import": "./dist/code.js"
46
+ },
47
+ "./markdown": {
48
+ "types": "./dist/markdown.d.ts",
49
+ "import": "./dist/markdown.js"
50
+ },
43
51
  "./package.json": "./package.json"
44
52
  },
45
53
  "files": [
@@ -78,11 +86,15 @@
78
86
  "react-native-screens": ">=4.30.0",
79
87
  "tailwindcss": ">=4.0.0",
80
88
  "uniwind": ">=1.12.0",
81
- "react-native-worklets": ">=0.13.0"
89
+ "react-native-worklets": ">=0.13.0",
90
+ "markdown-it": ">=14.1.0"
82
91
  },
83
92
  "peerDependenciesMeta": {
84
93
  "expo-blur": {
85
94
  "optional": true
95
+ },
96
+ "markdown-it": {
97
+ "optional": true
86
98
  }
87
99
  },
88
100
  "dependencies": {
@@ -97,10 +109,12 @@
97
109
  "@testing-library/react-native": "^14.1.0",
98
110
  "@types/culori": "^4.0.1",
99
111
  "@types/jest": "^30.0.0",
112
+ "@types/markdown-it": "^14.1.2",
100
113
  "@types/react": "~19.3.0",
101
114
  "expo-image": "~58.0.15",
102
115
  "jest": "^30.5.2",
103
116
  "jest-expo": "~58.0.11",
117
+ "markdown-it": "^14.1.0",
104
118
  "react-native-screens": "~4.30.0",
105
119
  "test-renderer": "^1.3.1",
106
120
  "typescript": "~6.0.3"