panelui-native 0.6.0 → 0.7.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.
Files changed (133) hide show
  1. package/README.md +1 -1
  2. package/lib/module/components/accordion/index.js +7 -5
  3. package/lib/module/components/accordion/index.js.map +1 -1
  4. package/lib/module/components/alert/index.js +3 -6
  5. package/lib/module/components/alert/index.js.map +1 -1
  6. package/lib/module/components/bottom-sheet/index.js +67 -3
  7. package/lib/module/components/bottom-sheet/index.js.map +1 -1
  8. package/lib/module/components/button/index.js +36 -1
  9. package/lib/module/components/button/index.js.map +1 -1
  10. package/lib/module/components/empty-state/index.js +4 -5
  11. package/lib/module/components/empty-state/index.js.map +1 -1
  12. package/lib/module/components/inline-select/index.js +171 -46
  13. package/lib/module/components/inline-select/index.js.map +1 -1
  14. package/lib/module/components/input/index.js +28 -5
  15. package/lib/module/components/input/index.js.map +1 -1
  16. package/lib/module/components/input-group/index.js +0 -1
  17. package/lib/module/components/input-group/index.js.map +1 -1
  18. package/lib/module/components/item/index.js +359 -0
  19. package/lib/module/components/item/index.js.map +1 -0
  20. package/lib/module/components/label/index.js +5 -3
  21. package/lib/module/components/label/index.js.map +1 -1
  22. package/lib/module/components/message/index.js +318 -0
  23. package/lib/module/components/message/index.js.map +1 -0
  24. package/lib/module/components/scroll-fade/index.js +119 -71
  25. package/lib/module/components/scroll-fade/index.js.map +1 -1
  26. package/lib/module/components/select/index.js +35 -6
  27. package/lib/module/components/select/index.js.map +1 -1
  28. package/lib/module/components/shimmer/index.js +111 -64
  29. package/lib/module/components/shimmer/index.js.map +1 -1
  30. package/lib/module/components/surface/index.js +3 -2
  31. package/lib/module/components/surface/index.js.map +1 -1
  32. package/lib/module/components/switch/index.js +20 -1
  33. package/lib/module/components/switch/index.js.map +1 -1
  34. package/lib/module/components/toast/index.js +7 -8
  35. package/lib/module/components/toast/index.js.map +1 -1
  36. package/lib/module/components/typography/index.js +3 -3
  37. package/lib/module/hooks/index.js +1 -0
  38. package/lib/module/hooks/index.js.map +1 -1
  39. package/lib/module/hooks/use-breakpoint.js +2 -2
  40. package/lib/module/hooks/use-copy-to-clipboard.js +0 -2
  41. package/lib/module/hooks/use-copy-to-clipboard.js.map +1 -1
  42. package/lib/module/hooks/use-keyboard-avoidance.js +120 -0
  43. package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -0
  44. package/lib/module/icons/index.js +4 -4
  45. package/lib/module/index.js +6 -0
  46. package/lib/module/index.js.map +1 -1
  47. package/lib/module/native/index.js +53 -0
  48. package/lib/module/native/index.js.map +1 -0
  49. package/lib/module/primitives/keyboard-avoider.js +40 -0
  50. package/lib/module/primitives/keyboard-avoider.js.map +1 -0
  51. package/lib/module/providers/panel-ui-provider.js +24 -4
  52. package/lib/module/providers/panel-ui-provider.js.map +1 -1
  53. package/lib/module/theme/use-theme.js +1 -1
  54. package/lib/typescript/src/components/accordion/index.d.ts +7 -5
  55. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
  56. package/lib/typescript/src/components/alert/index.d.ts +3 -6
  57. package/lib/typescript/src/components/alert/index.d.ts.map +1 -1
  58. package/lib/typescript/src/components/bottom-sheet/index.d.ts +21 -1
  59. package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
  60. package/lib/typescript/src/components/button/index.d.ts +11 -0
  61. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  62. package/lib/typescript/src/components/empty-state/index.d.ts +4 -5
  63. package/lib/typescript/src/components/empty-state/index.d.ts.map +1 -1
  64. package/lib/typescript/src/components/inline-select/index.d.ts +29 -6
  65. package/lib/typescript/src/components/inline-select/index.d.ts.map +1 -1
  66. package/lib/typescript/src/components/input/index.d.ts +13 -0
  67. package/lib/typescript/src/components/input/index.d.ts.map +1 -1
  68. package/lib/typescript/src/components/input-group/index.d.ts +0 -1
  69. package/lib/typescript/src/components/input-group/index.d.ts.map +1 -1
  70. package/lib/typescript/src/components/item/index.d.ts +286 -0
  71. package/lib/typescript/src/components/item/index.d.ts.map +1 -0
  72. package/lib/typescript/src/components/label/index.d.ts +5 -3
  73. package/lib/typescript/src/components/label/index.d.ts.map +1 -1
  74. package/lib/typescript/src/components/message/index.d.ts +170 -0
  75. package/lib/typescript/src/components/message/index.d.ts.map +1 -0
  76. package/lib/typescript/src/components/scroll-fade/index.d.ts +18 -9
  77. package/lib/typescript/src/components/scroll-fade/index.d.ts.map +1 -1
  78. package/lib/typescript/src/components/select/index.d.ts +16 -1
  79. package/lib/typescript/src/components/select/index.d.ts.map +1 -1
  80. package/lib/typescript/src/components/shimmer/index.d.ts +38 -20
  81. package/lib/typescript/src/components/shimmer/index.d.ts.map +1 -1
  82. package/lib/typescript/src/components/surface/index.d.ts.map +1 -1
  83. package/lib/typescript/src/components/switch/index.d.ts +10 -0
  84. package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
  85. package/lib/typescript/src/components/toast/index.d.ts +4 -4
  86. package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
  87. package/lib/typescript/src/hooks/index.d.ts +1 -0
  88. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  89. package/lib/typescript/src/hooks/use-breakpoint.d.ts +2 -2
  90. package/lib/typescript/src/hooks/use-copy-to-clipboard.d.ts +0 -2
  91. package/lib/typescript/src/hooks/use-copy-to-clipboard.d.ts.map +1 -1
  92. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts +20 -0
  93. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -0
  94. package/lib/typescript/src/icons/index.d.ts +4 -4
  95. package/lib/typescript/src/index.d.ts +4 -0
  96. package/lib/typescript/src/index.d.ts.map +1 -1
  97. package/lib/typescript/src/native/index.d.ts +35 -0
  98. package/lib/typescript/src/native/index.d.ts.map +1 -0
  99. package/lib/typescript/src/primitives/keyboard-avoider.d.ts +22 -0
  100. package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -0
  101. package/lib/typescript/src/providers/panel-ui-provider.d.ts +1 -1
  102. package/lib/typescript/src/providers/panel-ui-provider.d.ts.map +1 -1
  103. package/lib/typescript/src/theme/use-theme.d.ts +1 -1
  104. package/package.json +12 -3
  105. package/src/components/accordion/index.tsx +7 -5
  106. package/src/components/alert/index.tsx +3 -6
  107. package/src/components/bottom-sheet/index.tsx +82 -2
  108. package/src/components/button/index.tsx +52 -0
  109. package/src/components/empty-state/index.tsx +4 -5
  110. package/src/components/inline-select/index.tsx +191 -44
  111. package/src/components/input/index.tsx +39 -3
  112. package/src/components/input-group/index.tsx +0 -1
  113. package/src/components/item/index.tsx +387 -0
  114. package/src/components/label/index.tsx +5 -3
  115. package/src/components/message/index.tsx +312 -0
  116. package/src/components/scroll-fade/index.tsx +163 -51
  117. package/src/components/select/index.tsx +54 -9
  118. package/src/components/shimmer/index.tsx +151 -58
  119. package/src/components/surface/index.tsx +3 -2
  120. package/src/components/switch/index.tsx +27 -1
  121. package/src/components/toast/index.tsx +7 -8
  122. package/src/components/typography/index.tsx +3 -3
  123. package/src/hooks/index.ts +5 -0
  124. package/src/hooks/use-breakpoint.ts +2 -2
  125. package/src/hooks/use-copy-to-clipboard.ts +0 -2
  126. package/src/hooks/use-keyboard-avoidance.ts +140 -0
  127. package/src/icons/index.tsx +4 -4
  128. package/src/index.ts +32 -0
  129. package/src/native/index.ts +79 -0
  130. package/src/primitives/keyboard-avoider.tsx +49 -0
  131. package/src/providers/panel-ui-provider.tsx +30 -9
  132. package/src/theme/use-theme.ts +1 -1
  133. package/theme.css +5 -3
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Optional bridge to the platform's own UI toolkit.
3
+ *
4
+ * A handful of controls are better served by the real thing than by a faithful
5
+ * re-implementation: a switch, a picker, a sheet and a button are muscle
6
+ * memory, and users notice when the animation curve or the haptic is a
7
+ * near-miss. Passing `native` to those components hands rendering to SwiftUI
8
+ * on iOS and Jetpack Compose on Android.
9
+ *
10
+ * It is optional on purpose. The package is resolved lazily and every caller
11
+ * falls back to the styled implementation when it is missing, so nobody who
12
+ * never writes `native` has to install anything.
13
+ *
14
+ * ```sh
15
+ * npx expo install @expo/ui
16
+ * ```
17
+ *
18
+ * **Theme tokens do not apply in native mode.** The platform draws the control
19
+ * with its own colours, metrics and typography — that is the entire point, and
20
+ * it means `className` and the variant props are ignored on those components.
21
+ */
22
+ import { Platform } from 'react-native';
23
+ import type { ComponentType, ReactNode } from 'react';
24
+
25
+ interface NativeUIModule {
26
+ Host: ComponentType<{
27
+ children?: ReactNode;
28
+ matchContents?: boolean;
29
+ style?: unknown;
30
+ [key: string]: unknown;
31
+ }>;
32
+ /**
33
+ * Hosts React Native views inside the native tree. Anything of ours that
34
+ * goes inside a native container has to be wrapped in this or the native
35
+ * layout does not measure it — children spill outside their container.
36
+ */
37
+ RNHostView: ComponentType<{
38
+ children?: ReactNode;
39
+ matchContents?: boolean;
40
+ style?: unknown;
41
+ }>;
42
+ Button: ComponentType<Record<string, unknown>>;
43
+ Switch: ComponentType<Record<string, unknown>>;
44
+ Picker: ComponentType<Record<string, unknown>> & {
45
+ Item: ComponentType<Record<string, unknown>>;
46
+ };
47
+ BottomSheet: ComponentType<Record<string, unknown>>;
48
+ }
49
+
50
+ let resolved = false;
51
+ let module: NativeUIModule | null = null;
52
+
53
+ /**
54
+ * The native UI module, or null when it is not installed or the platform has
55
+ * no toolkit behind it. Resolved once and cached — a failed require is not
56
+ * retried on every render.
57
+ */
58
+ export function getNativeUI(): NativeUIModule | null {
59
+ if (resolved) return module;
60
+ resolved = true;
61
+
62
+ // Web has no SwiftUI and no Compose; @expo/ui renders plain views there,
63
+ // which loses the styling without gaining anything.
64
+ if (Platform.OS === 'web') return null;
65
+
66
+ try {
67
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
68
+ module = require('@expo/ui') as NativeUIModule;
69
+ } catch {
70
+ module = null;
71
+ }
72
+
73
+ return module;
74
+ }
75
+
76
+ /** Whether `native` will actually render a platform control. */
77
+ export function hasNativeUI(): boolean {
78
+ return getNativeUI() !== null;
79
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * KeyboardAvoider — a view that lifts itself just clear of the keyboard.
3
+ *
4
+ * A thin wrapper over `useKeyboardAvoidance` for the common case of "keep this
5
+ * box visible", so a form does not have to wire the ref, layout handler and
6
+ * animated style by hand.
7
+ */
8
+ import type { ReactNode } from 'react';
9
+ import type { ViewProps } from 'react-native';
10
+ import Animated from 'react-native-reanimated';
11
+ import { useKeyboardAvoidance } from '../hooks/use-keyboard-avoidance';
12
+
13
+ export interface KeyboardAvoiderProps extends ViewProps {
14
+ className?: string;
15
+ /** Set false to leave the content where it is. */
16
+ enabled?: boolean;
17
+ /** Gap to keep between the content's bottom edge and the keyboard. */
18
+ offset?: number;
19
+ children?: ReactNode;
20
+ }
21
+
22
+ export function KeyboardAvoider({
23
+ className,
24
+ enabled = true,
25
+ offset = 16,
26
+ children,
27
+ style,
28
+ onLayout,
29
+ ...props
30
+ }: KeyboardAvoiderProps) {
31
+ const avoidance = useKeyboardAvoidance({ enabled, offset });
32
+
33
+ return (
34
+ <Animated.View
35
+ {...props}
36
+ ref={avoidance.ref}
37
+ onLayout={(event) => {
38
+ avoidance.onLayout(event);
39
+ onLayout?.(event);
40
+ }}
41
+ className={className}
42
+ style={[style, avoidance.animatedStyle]}
43
+ >
44
+ {children}
45
+ </Animated.View>
46
+ );
47
+ }
48
+
49
+ KeyboardAvoider.displayName = 'KeyboardAvoider';
@@ -1,10 +1,27 @@
1
- import type { ReactNode } from 'react';
1
+ import { Fragment, type ComponentType, type ReactNode } from 'react';
2
2
  import { StyleSheet, View } from 'react-native';
3
3
  import { GestureHandlerRootView } from 'react-native-gesture-handler';
4
4
  import { PortalHost, PortalProvider } from '../primitives/portal';
5
5
  import { ToastViewport } from '../components/toast';
6
6
  import { cn } from '../utils/cn';
7
7
 
8
+ /**
9
+ * `react-native-keyboard-controller` needs its provider at the root, and
10
+ * forgetting it is a silent failure — the hooks return zeroes and keyboard
11
+ * avoidance simply does nothing. Mount it here when the package is installed
12
+ * so `avoidKeyboard` works without any extra setup, and fall back to a
13
+ * pass-through when it is not.
14
+ */
15
+ const KeyboardProvider: ComponentType<{ children?: ReactNode }> = (() => {
16
+ try {
17
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
18
+ const controller = require('react-native-keyboard-controller');
19
+ return controller?.KeyboardProvider ?? Fragment;
20
+ } catch {
21
+ return Fragment;
22
+ }
23
+ })();
24
+
8
25
  export interface PanelUIProviderProps {
9
26
  children: ReactNode;
10
27
  /**
@@ -38,14 +55,18 @@ export function PanelUIProvider({
38
55
  }: PanelUIProviderProps) {
39
56
  return (
40
57
  <GestureHandlerRootView style={styles.root}>
41
- <View className={cn('flex-1', background && 'bg-background', className)}>
42
- <PortalProvider>
43
- {children}
44
- {/* Sits before PortalHost so it can portal into it. */}
45
- <ToastViewport />
46
- <PortalHost />
47
- </PortalProvider>
48
- </View>
58
+ {/* Outermost of ours, so every field below it can avoid the keyboard.
59
+ A no-op Fragment when the controller is not installed. */}
60
+ <KeyboardProvider>
61
+ <View className={cn('flex-1', background && 'bg-background', className)}>
62
+ <PortalProvider>
63
+ {children}
64
+ {/* Sits before PortalHost so it can portal into it. */}
65
+ <ToastViewport />
66
+ <PortalHost />
67
+ </PortalProvider>
68
+ </View>
69
+ </KeyboardProvider>
49
70
  </GestureHandlerRootView>
50
71
  );
51
72
  }
@@ -29,7 +29,7 @@ export interface PanelThemeFamily {
29
29
  /**
30
30
  * The theme families PanelUI ships. Each sets its own palette *and* its own
31
31
  * radius scale, so switching family changes the shape of the UI as well as
32
- * its colour — Panel is the Coss default, Moon is sharp and monochrome,
32
+ * its colour — Panel is the default, Moon is sharp and monochrome,
33
33
  * Grass is soft and green.
34
34
  *
35
35
  * Everything beyond `panel` must be registered in your metro config, or
package/theme.css CHANGED
@@ -1,7 +1,9 @@
1
1
  /*
2
- * PanelUI theme — Coss UI design tokens, translated for React Native.
3
- * Source of truth: cosscom/coss packages/ui/src/styles/globals.css
4
- * (color-mix()/--alpha() expressions precomputed to static values.)
2
+ * PanelUI theme — the semantic design tokens, translated for React Native.
3
+ *
4
+ * Every colour is a static rgba/hex value: native cannot evaluate
5
+ * color-mix() or --alpha() at runtime, so those expressions are precomputed
6
+ * here rather than shipped as-is.
5
7
  *
6
8
  * Structured the way Uniwind expects themed tokens (see uniwind's own
7
9
  * test.css / expo-example): utility names declared in @theme, per-theme