react-native-platform-components 0.6.1 → 0.8.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 +259 -44
- package/android/src/main/java/com/platformcomponents/PCLiquidGlassView.kt +84 -0
- package/android/src/main/java/com/platformcomponents/PCLiquidGlassViewManager.kt +52 -0
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +241 -0
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +105 -0
- package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +2 -0
- package/ios/PCDatePickerView.swift +16 -13
- package/ios/PCLiquidGlass.h +10 -0
- package/ios/PCLiquidGlass.mm +140 -0
- package/ios/PCLiquidGlass.swift +354 -0
- package/ios/PCSegmentedControl.h +10 -0
- package/ios/PCSegmentedControl.mm +194 -0
- package/ios/PCSegmentedControl.swift +200 -0
- package/ios/PCSelectionMenu.swift +1 -1
- package/lib/commonjs/LiquidGlass.js +72 -0
- package/lib/commonjs/LiquidGlass.js.map +1 -0
- package/lib/commonjs/LiquidGlassNativeComponent.ts +110 -0
- package/lib/commonjs/SegmentedControl.js +93 -0
- package/lib/commonjs/SegmentedControl.js.map +1 -0
- package/lib/commonjs/SegmentedControlNativeComponent.ts +79 -0
- package/lib/commonjs/index.js +22 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/LiquidGlass.js +64 -0
- package/lib/module/LiquidGlass.js.map +1 -0
- package/lib/module/LiquidGlassNativeComponent.ts +110 -0
- package/lib/module/SegmentedControl.js +87 -0
- package/lib/module/SegmentedControl.js.map +1 -0
- package/lib/module/SegmentedControlNativeComponent.ts +79 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/LiquidGlass.d.ts +96 -0
- package/lib/typescript/commonjs/src/LiquidGlass.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts +93 -0
- package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/SegmentedControl.d.ts +62 -0
- package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +63 -0
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +2 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/LiquidGlass.d.ts +96 -0
- package/lib/typescript/module/src/LiquidGlass.d.ts.map +1 -0
- package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts +93 -0
- package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/SegmentedControl.d.ts +62 -0
- package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -0
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +63 -0
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +2 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +13 -4
- package/react-native.config.js +1 -0
- package/shared/PCSegmentedControlComponentDescriptors-custom.h +22 -0
- package/shared/PCSegmentedControlShadowNode-custom.cpp +54 -0
- package/shared/PCSegmentedControlShadowNode-custom.h +56 -0
- package/shared/PCSegmentedControlState-custom.h +62 -0
- package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +1 -0
- package/src/LiquidGlass.tsx +169 -0
- package/src/LiquidGlassNativeComponent.ts +110 -0
- package/src/SegmentedControl.tsx +178 -0
- package/src/SegmentedControlNativeComponent.ts +79 -0
- package/src/index.tsx +2 -0
package/README.md
CHANGED
|
@@ -3,55 +3,68 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/react-native-platform-components)
|
|
4
4
|
[](https://www.npmjs.com/package/react-native-platform-components)
|
|
5
5
|
|
|
6
|
+
High-quality **native UI components for React Native**, implemented with platform-first APIs and exposed through clean, typed JavaScript interfaces.
|
|
7
|
+
|
|
8
|
+
This library focuses on **true native behavior**, not JavaScript re-implementations.
|
|
9
|
+
|
|
6
10
|
<table>
|
|
7
11
|
<tr>
|
|
8
|
-
<td
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<td
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<li>Feel <strong>100% native</strong> on each platform</li>
|
|
47
|
-
<li>Support modern platform design systems (Material 3 on Android, system pickers on iOS)</li>
|
|
48
|
-
<li>Offer <strong>headless</strong> and <strong>inline</strong> modes for maximum layout control</li>
|
|
49
|
-
<li>Integrate cleanly with <strong>React Native Codegen / Fabric</strong></li>
|
|
50
|
-
</ul>
|
|
51
|
-
</td>
|
|
12
|
+
<td align="center"><strong>iOS DatePicker</strong></td>
|
|
13
|
+
<td align="center"><strong>Android DatePicker</strong></td>
|
|
14
|
+
</tr>
|
|
15
|
+
<tr>
|
|
16
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-datepicker.gif" height="550" /></td>
|
|
17
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-datepicker.gif" height="550" /></td>
|
|
18
|
+
</tr>
|
|
19
|
+
<tr>
|
|
20
|
+
<td align="center"><strong>iOS ContextMenu</strong></td>
|
|
21
|
+
<td align="center"><strong>Android ContextMenu</strong></td>
|
|
22
|
+
</tr>
|
|
23
|
+
<tr>
|
|
24
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-contextmenu.gif" height="550" /></td>
|
|
25
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-contextmenu.gif" height="550" /></td>
|
|
26
|
+
</tr>
|
|
27
|
+
<tr>
|
|
28
|
+
<td align="center"><strong>iOS SelectionMenu</strong></td>
|
|
29
|
+
<td align="center"><strong>Android SelectionMenu</strong></td>
|
|
30
|
+
</tr>
|
|
31
|
+
<tr>
|
|
32
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-selectionmenu.gif" height="550" /></td>
|
|
33
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-selectionmenu.gif" height="550" /></td>
|
|
34
|
+
</tr>
|
|
35
|
+
<tr>
|
|
36
|
+
<td align="center"><strong>iOS SegmentedControl</strong></td>
|
|
37
|
+
<td align="center"><strong>Android SegmentedControl</strong></td>
|
|
38
|
+
</tr>
|
|
39
|
+
<tr>
|
|
40
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-segmentedcontrol.gif" height="550" /></td>
|
|
41
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-segmentedcontrol.gif" height="550" /></td>
|
|
42
|
+
</tr>
|
|
43
|
+
<tr>
|
|
44
|
+
<td align="center"><strong>iOS LiquidGlass</strong></td>
|
|
45
|
+
<td align="center"><strong>Android LiquidGlass</strong></td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<td><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-liquidglass.gif" height="550" /></td>
|
|
49
|
+
<td align="center"><em>iOS 26+ only</em><br/><br/>On Android, renders as a<br/>regular View with optional<br/>fallback background color.</td>
|
|
52
50
|
</tr>
|
|
53
51
|
</table>
|
|
54
52
|
|
|
53
|
+
### Components
|
|
54
|
+
|
|
55
|
+
- **DatePicker** – native date & time pickers with modal and embedded presentations
|
|
56
|
+
- **ContextMenu** – native context menus with long-press activation (UIContextMenuInteraction on iOS, PopupMenu on Android)
|
|
57
|
+
- **SelectionMenu** – native selection menus (Material on Android, system menus on iOS)
|
|
58
|
+
- **SegmentedControl** – native segmented controls (UISegmentedControl on iOS, MaterialButtonToggleGroup on Android)
|
|
59
|
+
- **LiquidGlass** – iOS 26+ glass morphism effects (UIGlassEffect on iOS, fallback View on Android)
|
|
60
|
+
|
|
61
|
+
### Goals
|
|
62
|
+
|
|
63
|
+
- Feel **100% native** on each platform
|
|
64
|
+
- Support modern platform design systems (Material 3 on Android, system pickers on iOS)
|
|
65
|
+
- Offer **headless** and **inline** modes for maximum layout control
|
|
66
|
+
- Integrate cleanly with **React Native Codegen / Fabric**
|
|
67
|
+
|
|
55
68
|
---
|
|
56
69
|
|
|
57
70
|
## Installation
|
|
@@ -325,6 +338,101 @@ export function Example() {
|
|
|
325
338
|
|
|
326
339
|
---
|
|
327
340
|
|
|
341
|
+
### SegmentedControl
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
import { SegmentedControl } from 'react-native-platform-components';
|
|
345
|
+
|
|
346
|
+
const segments = [
|
|
347
|
+
{ label: 'Day', value: 'day' },
|
|
348
|
+
{ label: 'Week', value: 'week' },
|
|
349
|
+
{ label: 'Month', value: 'month' },
|
|
350
|
+
];
|
|
351
|
+
|
|
352
|
+
export function Example() {
|
|
353
|
+
const [selected, setSelected] = React.useState('day');
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<SegmentedControl
|
|
357
|
+
segments={segments}
|
|
358
|
+
selectedValue={selected}
|
|
359
|
+
onSelect={(value) => setSelected(value)}
|
|
360
|
+
/>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### SegmentedControl (With Icons)
|
|
366
|
+
|
|
367
|
+
```tsx
|
|
368
|
+
import { SegmentedControl } from 'react-native-platform-components';
|
|
369
|
+
import { Platform } from 'react-native';
|
|
370
|
+
|
|
371
|
+
const segments = [
|
|
372
|
+
{
|
|
373
|
+
label: 'List',
|
|
374
|
+
value: 'list',
|
|
375
|
+
icon: Platform.OS === 'ios' ? 'list.bullet' : 'list_bullet',
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
label: 'Grid',
|
|
379
|
+
value: 'grid',
|
|
380
|
+
icon: Platform.OS === 'ios' ? 'square.grid.2x2' : 'grid_view',
|
|
381
|
+
},
|
|
382
|
+
];
|
|
383
|
+
|
|
384
|
+
export function Example() {
|
|
385
|
+
const [selected, setSelected] = React.useState('list');
|
|
386
|
+
|
|
387
|
+
return (
|
|
388
|
+
<SegmentedControl
|
|
389
|
+
segments={segments}
|
|
390
|
+
selectedValue={selected}
|
|
391
|
+
onSelect={(value) => setSelected(value)}
|
|
392
|
+
ios={{ apportionsSegmentWidthsByContent: true }}
|
|
393
|
+
/>
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
### LiquidGlass
|
|
401
|
+
|
|
402
|
+
```tsx
|
|
403
|
+
import { LiquidGlass, isLiquidGlassSupported } from 'react-native-platform-components';
|
|
404
|
+
import { View, Text, Image } from 'react-native';
|
|
405
|
+
|
|
406
|
+
export function Example() {
|
|
407
|
+
return (
|
|
408
|
+
<View style={{ flex: 1 }}>
|
|
409
|
+
{/* Background content */}
|
|
410
|
+
<Image source={{ uri: 'https://example.com/photo.jpg' }} style={{ flex: 1 }} />
|
|
411
|
+
|
|
412
|
+
{/* Glass effect overlay */}
|
|
413
|
+
<LiquidGlass
|
|
414
|
+
style={{ position: 'absolute', top: 50, left: 20, right: 20, padding: 20 }}
|
|
415
|
+
cornerRadius={20}
|
|
416
|
+
ios={{
|
|
417
|
+
effect: 'regular',
|
|
418
|
+
interactive: true,
|
|
419
|
+
colorScheme: 'system',
|
|
420
|
+
}}
|
|
421
|
+
android={{
|
|
422
|
+
fallbackBackgroundColor: '#FFFFFF80',
|
|
423
|
+
}}
|
|
424
|
+
>
|
|
425
|
+
<Text style={{ fontSize: 18, fontWeight: '600' }}>
|
|
426
|
+
{isLiquidGlassSupported ? 'Glass Effect!' : 'Fallback View'}
|
|
427
|
+
</Text>
|
|
428
|
+
</LiquidGlass>
|
|
429
|
+
</View>
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
328
436
|
## Components
|
|
329
437
|
|
|
330
438
|
## DatePicker
|
|
@@ -450,6 +558,111 @@ Native selection menu with **modal** and **embedded** modes.
|
|
|
450
558
|
|
|
451
559
|
---
|
|
452
560
|
|
|
561
|
+
## SegmentedControl
|
|
562
|
+
|
|
563
|
+
Native segmented control using **UISegmentedControl** on iOS and **MaterialButtonToggleGroup** on Android.
|
|
564
|
+
|
|
565
|
+
### Props
|
|
566
|
+
|
|
567
|
+
| Prop | Type | Description |
|
|
568
|
+
|------|------|-------------|
|
|
569
|
+
| `segments` | `SegmentedControlSegment[]` | Array of segments to display |
|
|
570
|
+
| `selectedValue` | `string \| null` | Currently selected segment's `value` |
|
|
571
|
+
| `disabled` | `boolean` | Disables the entire control |
|
|
572
|
+
| `onSelect` | `(value: string, index: number) => void` | Called when user selects a segment |
|
|
573
|
+
|
|
574
|
+
### SegmentedControlSegment
|
|
575
|
+
|
|
576
|
+
| Property | Type | Description |
|
|
577
|
+
|----------|------|-------------|
|
|
578
|
+
| `label` | `string` | Display text for the segment |
|
|
579
|
+
| `value` | `string` | Unique value returned in callbacks |
|
|
580
|
+
| `disabled` | `boolean` | Disables this specific segment |
|
|
581
|
+
| `icon` | `string` | Icon name (SF Symbol on iOS, drawable on Android) |
|
|
582
|
+
|
|
583
|
+
### iOS Props (`ios`)
|
|
584
|
+
|
|
585
|
+
| Prop | Type | Description |
|
|
586
|
+
|------|------|-------------|
|
|
587
|
+
| `momentary` | `boolean` | If true, segments don't show selected state |
|
|
588
|
+
| `apportionsSegmentWidthsByContent` | `boolean` | If true, segment widths are proportional to content |
|
|
589
|
+
| `selectedSegmentTintColor` | `string` | Tint color for selected segment (hex string) |
|
|
590
|
+
|
|
591
|
+
### Android Props (`android`)
|
|
592
|
+
|
|
593
|
+
| Prop | Type | Description |
|
|
594
|
+
|------|------|-------------|
|
|
595
|
+
| `selectionRequired` | `boolean` | If true, one segment must always be selected |
|
|
596
|
+
|
|
597
|
+
### Icon Support
|
|
598
|
+
|
|
599
|
+
Icons work the same as ContextMenu:
|
|
600
|
+
- **iOS**: Use SF Symbol names (e.g., `'list.bullet'`, `'square.grid.2x2'`)
|
|
601
|
+
- **Android**: Use drawable resource names (e.g., `'list_bullet'`, `'grid_view'`)
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## LiquidGlass
|
|
606
|
+
|
|
607
|
+
Native glass morphism effect using **UIGlassEffect** on iOS 26+. On Android and older iOS versions, renders as a regular View with optional fallback styling.
|
|
608
|
+
|
|
609
|
+
> **Note:** LiquidGlass requires **iOS 26+** (Xcode 16+). On older iOS versions and Android, the component renders children without the glass effect. Use `isLiquidGlassSupported` to check availability and provide fallback UI.
|
|
610
|
+
|
|
611
|
+
### Props
|
|
612
|
+
|
|
613
|
+
| Prop | Type | Description |
|
|
614
|
+
|------|------|-------------|
|
|
615
|
+
| `cornerRadius` | `number` | Corner radius for the glass effect (default: `0`) |
|
|
616
|
+
| `children` | `ReactNode` | Content to render inside the glass container |
|
|
617
|
+
|
|
618
|
+
### iOS Props (`ios`)
|
|
619
|
+
|
|
620
|
+
| Prop | Type | Description |
|
|
621
|
+
|------|------|-------------|
|
|
622
|
+
| `effect` | `'clear' \| 'regular' \| 'none'` | Glass effect intensity (default: `'regular'`) |
|
|
623
|
+
| `interactive` | `boolean` | Enable touch interaction feedback (default: `false`) |
|
|
624
|
+
| `tintColor` | `string` | Overlay tint color (hex string) |
|
|
625
|
+
| `colorScheme` | `'light' \| 'dark' \| 'system'` | Appearance mode (default: `'system'`) |
|
|
626
|
+
| `shadowRadius` | `number` | Shadow/glow radius (default: `20`) |
|
|
627
|
+
| `isHighlighted` | `boolean` | Manual highlight state control |
|
|
628
|
+
|
|
629
|
+
### Android Props (`android`)
|
|
630
|
+
|
|
631
|
+
| Prop | Type | Description |
|
|
632
|
+
|------|------|-------------|
|
|
633
|
+
| `fallbackBackgroundColor` | `string` | Background color when glass effect unavailable |
|
|
634
|
+
|
|
635
|
+
### Constants
|
|
636
|
+
|
|
637
|
+
| Export | Type | Description |
|
|
638
|
+
|--------|------|-------------|
|
|
639
|
+
| `isLiquidGlassSupported` | `boolean` | `true` on iOS 26+, `false` otherwise |
|
|
640
|
+
|
|
641
|
+
### Effect Modes
|
|
642
|
+
|
|
643
|
+
- **`'regular'`** (default): Standard glass blur intensity with full glass morphism effect
|
|
644
|
+
- **`'clear'`**: More transparent, subtle glass effect
|
|
645
|
+
- **`'none'`**: No glass effect (useful for animating materialization/dematerialization)
|
|
646
|
+
|
|
647
|
+
### Platform Behavior
|
|
648
|
+
|
|
649
|
+
| Platform | iOS 26+ | iOS < 26 | Android |
|
|
650
|
+
|----------|---------|----------|---------|
|
|
651
|
+
| Glass Effect | Full glass morphism | No effect | No effect |
|
|
652
|
+
| Corner Radius | Applied | Applied | Applied |
|
|
653
|
+
| Tint Color | Supported | Ignored | Ignored |
|
|
654
|
+
| Interactive | Supported | Ignored | Ignored |
|
|
655
|
+
| Fallback BG | N/A | Transparent | Configurable |
|
|
656
|
+
|
|
657
|
+
### Usage Tips
|
|
658
|
+
|
|
659
|
+
1. **Check support first**: Use `isLiquidGlassSupported` to conditionally render fallback UI
|
|
660
|
+
2. **Background content**: Glass effects work best over images or colorful backgrounds
|
|
661
|
+
3. **Interactive mode**: Only applies on mount; cannot be toggled after initial render
|
|
662
|
+
4. **Android fallback**: Set `android.fallbackBackgroundColor` for a semi-transparent background
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
453
666
|
## Design Philosophy
|
|
454
667
|
|
|
455
668
|
- **Native first** — no JS re-implementation of pickers
|
|
@@ -554,6 +767,8 @@ const actions = [
|
|
|
554
767
|
|
|
555
768
|
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
|
|
556
769
|
|
|
770
|
+
**Have a component request?** If there's a native UI component you'd like to see added, [open an issue](https://github.com/JarX-Concepts/react-native-platform-components/issues/new) describing the component and its native APIs on iOS and Android.
|
|
771
|
+
|
|
557
772
|
## License
|
|
558
773
|
|
|
559
774
|
MIT
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
package com.platformcomponents
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Color
|
|
5
|
+
import android.graphics.drawable.GradientDrawable
|
|
6
|
+
import android.view.View
|
|
7
|
+
import android.widget.FrameLayout
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Android stub implementation for LiquidGlass.
|
|
11
|
+
*
|
|
12
|
+
* LiquidGlass is an iOS 26+ only feature. On Android, this component renders
|
|
13
|
+
* as a regular FrameLayout with optional fallback styling (background color, corner radius).
|
|
14
|
+
*/
|
|
15
|
+
class PCLiquidGlassView(context: Context) : FrameLayout(context) {
|
|
16
|
+
|
|
17
|
+
companion object {
|
|
18
|
+
private const val TAG = "PCLiquidGlass"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// --- Props ---
|
|
22
|
+
var cornerRadius: Float = 0f
|
|
23
|
+
set(value) {
|
|
24
|
+
field = value
|
|
25
|
+
updateBackground()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var fallbackBackgroundColor: String? = null
|
|
29
|
+
set(value) {
|
|
30
|
+
field = value
|
|
31
|
+
updateBackground()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
init {
|
|
35
|
+
// Ensure children can be rendered
|
|
36
|
+
clipChildren = false
|
|
37
|
+
clipToPadding = false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private fun updateBackground() {
|
|
41
|
+
val bgColor = fallbackBackgroundColor?.let { parseColor(it) }
|
|
42
|
+
|
|
43
|
+
if (cornerRadius > 0 || bgColor != null) {
|
|
44
|
+
val drawable = GradientDrawable().apply {
|
|
45
|
+
shape = GradientDrawable.RECTANGLE
|
|
46
|
+
cornerRadii = FloatArray(8) { cornerRadius * resources.displayMetrics.density }
|
|
47
|
+
setColor(bgColor ?: Color.TRANSPARENT)
|
|
48
|
+
}
|
|
49
|
+
background = drawable
|
|
50
|
+
clipToOutline = cornerRadius > 0
|
|
51
|
+
outlineProvider = android.view.ViewOutlineProvider.BACKGROUND
|
|
52
|
+
} else {
|
|
53
|
+
background = null
|
|
54
|
+
clipToOutline = false
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private fun parseColor(colorString: String): Int? {
|
|
59
|
+
return try {
|
|
60
|
+
var sanitized = colorString.trim()
|
|
61
|
+
if (!sanitized.startsWith("#")) {
|
|
62
|
+
sanitized = "#$sanitized"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Handle #RRGGBBAA format (web/CSS style) by converting to #AARRGGBB (Android style)
|
|
66
|
+
if (sanitized.length == 9) {
|
|
67
|
+
val rrggbb = sanitized.substring(1, 7)
|
|
68
|
+
val aa = sanitized.substring(7, 9)
|
|
69
|
+
sanitized = "#$aa$rrggbb"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
Color.parseColor(sanitized)
|
|
73
|
+
} catch (e: Exception) {
|
|
74
|
+
null
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ---- Measurement ----
|
|
79
|
+
|
|
80
|
+
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
|
81
|
+
// Standard FrameLayout measurement
|
|
82
|
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
package com.platformcomponents
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableMap
|
|
4
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
5
|
+
import com.facebook.react.uimanager.ViewGroupManager
|
|
6
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
7
|
+
import com.facebook.react.viewmanagers.PCLiquidGlassManagerDelegate
|
|
8
|
+
import com.facebook.react.viewmanagers.PCLiquidGlassManagerInterface
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Android ViewManager for LiquidGlass.
|
|
12
|
+
*
|
|
13
|
+
* LiquidGlass is iOS-only, so this manager provides a stub implementation
|
|
14
|
+
* that renders a basic FrameLayout with optional fallback styling.
|
|
15
|
+
* Uses ViewGroupManager since LiquidGlass can contain children.
|
|
16
|
+
*/
|
|
17
|
+
class PCLiquidGlassViewManager :
|
|
18
|
+
ViewGroupManager<PCLiquidGlassView>(),
|
|
19
|
+
PCLiquidGlassManagerInterface<PCLiquidGlassView> {
|
|
20
|
+
|
|
21
|
+
companion object {
|
|
22
|
+
private const val TAG = "PCLiquidGlass"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private val delegate: ViewManagerDelegate<PCLiquidGlassView> =
|
|
26
|
+
PCLiquidGlassManagerDelegate(this)
|
|
27
|
+
|
|
28
|
+
override fun getName(): String = "PCLiquidGlass"
|
|
29
|
+
|
|
30
|
+
override fun getDelegate(): ViewManagerDelegate<PCLiquidGlassView> = delegate
|
|
31
|
+
|
|
32
|
+
override fun createViewInstance(reactContext: ThemedReactContext): PCLiquidGlassView {
|
|
33
|
+
return PCLiquidGlassView(reactContext)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override fun setCornerRadius(view: PCLiquidGlassView, value: Float) {
|
|
37
|
+
view.cornerRadius = value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override fun setIos(view: PCLiquidGlassView, value: ReadableMap?) {
|
|
41
|
+
// iOS props are ignored on Android
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
override fun setAndroid(view: PCLiquidGlassView, value: ReadableMap?) {
|
|
45
|
+
val fallbackColor = value?.let {
|
|
46
|
+
if (it.hasKey("fallbackBackgroundColor") && !it.isNull("fallbackBackgroundColor")) {
|
|
47
|
+
it.getString("fallbackBackgroundColor")
|
|
48
|
+
} else null
|
|
49
|
+
}
|
|
50
|
+
view.fallbackBackgroundColor = fallbackColor
|
|
51
|
+
}
|
|
52
|
+
}
|