@symbiote-native/glass-effect 0.0.0-stage → 0.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.
- package/LICENSE +21 -0
- package/README.md +46 -2
- package/build/angular/glass/index.android.d.ts +7 -0
- package/build/angular/glass/index.android.js +93 -0
- package/build/angular/glass/index.d.ts +1 -0
- package/build/angular/glass/index.ios.d.ts +9 -0
- package/build/angular/glass/index.ios.js +112 -0
- package/build/angular/glass/index.js +2 -0
- package/build/angular/glass/shared.d.ts +16 -0
- package/build/angular/glass/shared.js +121 -0
- package/build/angular/index.d.ts +2 -0
- package/build/angular/index.js +3 -0
- package/build/core/glass-effect.d.ts +62 -0
- package/build/core/glass-effect.js +71 -0
- package/build/core/index.d.ts +1 -0
- package/build/core/index.js +1 -0
- package/build/react/glass-effect.d.ts +17 -0
- package/build/react/glass-effect.js +14 -0
- package/build/react/index.d.ts +3 -0
- package/build/react/index.js +3 -0
- package/build/solid/glass-effect.d.ts +16 -0
- package/build/solid/glass-effect.js +6 -0
- package/build/solid/index.d.ts +3 -0
- package/build/solid/index.js +3 -0
- package/build/svelte/glass-container.svelte +14 -0
- package/build/svelte/glass-container.svelte.d.ts +4 -0
- package/build/svelte/glass-props.d.ts +13 -0
- package/build/svelte/glass-props.js +1 -0
- package/build/svelte/glass-view.svelte +10 -0
- package/build/svelte/glass-view.svelte.d.ts +4 -0
- package/build/svelte/index.d.ts +4 -0
- package/build/svelte/index.js +4 -0
- package/build/vue/glass-effect.d.ts +9 -0
- package/build/vue/glass-effect.js +20 -0
- package/build/vue/index.d.ts +3 -0
- package/build/vue/index.js +3 -0
- package/build-ngc/angular/glass/index.android.d.ts +12 -0
- package/build-ngc/angular/glass/index.android.js +43 -0
- package/build-ngc/angular/glass/index.android.js.map +1 -0
- package/build-ngc/angular/glass/index.d.ts +1 -0
- package/build-ngc/angular/glass/index.ios.d.ts +14 -0
- package/build-ngc/angular/glass/index.ios.js +66 -0
- package/build-ngc/angular/glass/index.ios.js.map +1 -0
- package/build-ngc/angular/glass/index.js +3 -0
- package/build-ngc/angular/glass/index.js.map +1 -0
- package/build-ngc/angular/glass/shared.d.ts +21 -0
- package/build-ngc/angular/glass/shared.js +50 -0
- package/build-ngc/angular/glass/shared.js.map +1 -0
- package/build-ngc/angular/index.d.ts +2 -0
- package/build-ngc/angular/index.js +4 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/core/glass-effect.d.ts +62 -0
- package/build-ngc/core/glass-effect.js +72 -0
- package/build-ngc/core/glass-effect.js.map +1 -0
- package/build-ngc/core/index.d.ts +1 -0
- package/build-ngc/core/index.js +2 -0
- package/build-ngc/core/index.js.map +1 -0
- package/native-link.json +5 -0
- package/package.json +145 -3
- package/src/angular/glass/index.android.ts +27 -0
- package/src/angular/glass/index.ios.ts +57 -0
- package/src/angular/glass/index.ts +2 -0
- package/src/angular/glass/shared.ts +38 -0
- package/src/angular/index.ts +15 -0
- package/src/core/glass-effect.ts +160 -0
- package/src/core/index.ts +16 -0
- package/src/react/glass-effect.ts +34 -0
- package/src/react/index.ts +17 -0
- package/src/solid/glass-effect.ts +27 -0
- package/src/solid/index.ts +17 -0
- package/src/svelte/glass-container.svelte +14 -0
- package/src/svelte/glass-props.ts +18 -0
- package/src/svelte/glass-view.svelte +10 -0
- package/src/svelte/index.ts +18 -0
- package/src/svelte/svelte-ambient.d.ts +6 -0
- package/src/svelte/svelte-compile.test-helper.ts +6 -0
- package/src/vue/glass-effect.ts +39 -0
- package/src/vue/index.ts +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,148 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/glass-effect",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "expo-glass-effect wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Liquid Glass native views for iOS 26 and a plain View elsewhere.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/OneEyed1366/symbiote-native.git",
|
|
9
|
+
"directory": "packages/glass-effect"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/OneEyed1366/symbiote-native/tree/master/packages/glass-effect#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/OneEyed1366/symbiote-native/issues"
|
|
14
|
+
},
|
|
15
|
+
"author": "Andrey Prokopenko <psevdoproger@gmail.com>",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react-native",
|
|
18
|
+
"symbiote-native",
|
|
19
|
+
"expo-glass-effect",
|
|
20
|
+
"react",
|
|
21
|
+
"vue",
|
|
22
|
+
"svelte",
|
|
23
|
+
"solid",
|
|
24
|
+
"angular",
|
|
25
|
+
"liquid-glass",
|
|
26
|
+
"glass-effect"
|
|
27
|
+
],
|
|
28
|
+
"type": "module",
|
|
29
|
+
"main": "./build/core/index.js",
|
|
30
|
+
"module": "./build/core/index.js",
|
|
31
|
+
"types": "./build/core/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./build/core/index.d.ts",
|
|
35
|
+
"default": "./build/core/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./vue": {
|
|
38
|
+
"types": "./build/vue/index.d.ts",
|
|
39
|
+
"default": "./build/vue/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./react": {
|
|
42
|
+
"types": "./build/react/index.d.ts",
|
|
43
|
+
"default": "./build/react/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./svelte": "./src/svelte/index.ts",
|
|
46
|
+
"./solid": {
|
|
47
|
+
"types": "./build/solid/index.d.ts",
|
|
48
|
+
"default": "./build/solid/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./angular": {
|
|
51
|
+
"types": "./build-ngc/angular/index.d.ts",
|
|
52
|
+
"react-native": "./build-ngc/angular/index.js",
|
|
53
|
+
"default": "./src/angular/index.ts"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"files": [
|
|
57
|
+
"src",
|
|
58
|
+
"build",
|
|
59
|
+
"build-ngc",
|
|
60
|
+
"native-link.json",
|
|
61
|
+
"!src/**/*.test.*",
|
|
62
|
+
"!src/**/*.spec.*",
|
|
63
|
+
"!src/**/*.detox.*"
|
|
64
|
+
],
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"expo-glass-effect": "57.0.4",
|
|
70
|
+
"expo-modules-core": "57.0.20",
|
|
71
|
+
"@symbiote-native/components": "3.1.4"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"@angular/core": ">=20",
|
|
75
|
+
"@vue/runtime-core": "^3.5.13",
|
|
76
|
+
"react": ">=19.0.0",
|
|
77
|
+
"react-native": ">=0.86",
|
|
78
|
+
"solid-js": ">=1.9.0",
|
|
79
|
+
"svelte": ">=5.56.0",
|
|
80
|
+
"vue": ">=3.5.0",
|
|
81
|
+
"@symbiote-native/angular": "^3.2.0",
|
|
82
|
+
"@symbiote-native/engine": "^1.5.0",
|
|
83
|
+
"@symbiote-native/react": "^3.2.0",
|
|
84
|
+
"@symbiote-native/svelte": "^3.1.0",
|
|
85
|
+
"@symbiote-native/solid": "^3.1.0",
|
|
86
|
+
"@symbiote-native/vue": "^3.2.0"
|
|
87
|
+
},
|
|
88
|
+
"peerDependenciesMeta": {
|
|
89
|
+
"@symbiote-native/angular": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
92
|
+
"@symbiote-native/react": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"@symbiote-native/solid": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"@symbiote-native/svelte": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"@symbiote-native/vue": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"@angular/core": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"@vue/runtime-core": {
|
|
108
|
+
"optional": true
|
|
109
|
+
},
|
|
110
|
+
"react": {
|
|
111
|
+
"optional": true
|
|
112
|
+
},
|
|
113
|
+
"solid-js": {
|
|
114
|
+
"optional": true
|
|
115
|
+
},
|
|
116
|
+
"svelte": {
|
|
117
|
+
"optional": true
|
|
118
|
+
},
|
|
119
|
+
"vue": {
|
|
120
|
+
"optional": true
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"devDependencies": {
|
|
124
|
+
"@angular/compiler": "~22.0.8",
|
|
125
|
+
"@angular/compiler-cli": "~22.0.8",
|
|
126
|
+
"@angular/core": "~22.0.8",
|
|
127
|
+
"@types/node": "^26.0.0",
|
|
128
|
+
"@types/react": "^19.2.0",
|
|
129
|
+
"@vue/runtime-core": "^3.5.13",
|
|
130
|
+
"react": "19.2.3",
|
|
131
|
+
"solid-js": "^1.9.14",
|
|
132
|
+
"svelte": "^5.56.0",
|
|
133
|
+
"typescript": "~6.0.0",
|
|
134
|
+
"@symbiote-native/angular": "3.2.0",
|
|
135
|
+
"@symbiote-native/svelte": "3.1.0",
|
|
136
|
+
"@symbiote-native/solid": "3.1.0",
|
|
137
|
+
"@symbiote-native/engine": "1.5.0",
|
|
138
|
+
"@symbiote-native/react": "3.2.0",
|
|
139
|
+
"@symbiote-native/test-utils": "0.4.6",
|
|
140
|
+
"@symbiote-native/vue": "3.2.0"
|
|
141
|
+
},
|
|
142
|
+
"scripts": {
|
|
143
|
+
"typecheck": "tsc --build",
|
|
144
|
+
"clean": "rm -rf build-ngc",
|
|
145
|
+
"ng:build": "pnpm run clean && ngc -p tsconfig.angular.json",
|
|
146
|
+
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
147
|
+
}
|
|
6
148
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
import { DescriptorHost } from '@symbiote-native/angular';
|
|
3
|
+
import { GlassContainerBase, GlassViewBase } from './shared';
|
|
4
|
+
|
|
5
|
+
/** Angular twin of `expo-glass-effect`'s `GlassView`, a plain View off iOS */
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'GlassView',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [DescriptorHost],
|
|
10
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
11
|
+
template: `@if (descriptor; as node) {
|
|
12
|
+
<symbiote-descriptor-host [node]="node"><ng-content /></symbiote-descriptor-host>
|
|
13
|
+
}`,
|
|
14
|
+
})
|
|
15
|
+
export class GlassView extends GlassViewBase {}
|
|
16
|
+
|
|
17
|
+
/** Angular twin of `expo-glass-effect`'s `GlassContainer`, a plain View off iOS */
|
|
18
|
+
@Component({
|
|
19
|
+
selector: 'GlassContainer',
|
|
20
|
+
standalone: true,
|
|
21
|
+
imports: [DescriptorHost],
|
|
22
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
23
|
+
template: `@if (descriptor; as node) {
|
|
24
|
+
<symbiote-descriptor-host [node]="node"><ng-content /></symbiote-descriptor-host>
|
|
25
|
+
}`,
|
|
26
|
+
})
|
|
27
|
+
export class GlassContainer extends GlassContainerBase {}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChangeDetectionStrategy,
|
|
3
|
+
Component,
|
|
4
|
+
NO_ERRORS_SCHEMA,
|
|
5
|
+
} from '@angular/core';
|
|
6
|
+
import { SymbioteHostPropsDirective } from '@symbiote-native/angular';
|
|
7
|
+
import { warnIfViewNameIsDynamic } from '@symbiote-native/engine';
|
|
8
|
+
import { GLASS_EFFECT_MODULE_NAME } from '../../core';
|
|
9
|
+
import { GlassContainerBase, GlassViewBase } from './shared';
|
|
10
|
+
|
|
11
|
+
const VIEW_TAG = 'ViewManagerAdapter_ExpoGlassEffect_GlassView';
|
|
12
|
+
const CONTAINER_TAG = 'ViewManagerAdapter_ExpoGlassEffect_GlassContainer';
|
|
13
|
+
|
|
14
|
+
/** Angular twin of `expo-glass-effect`'s `GlassView`, content goes inside the native view */
|
|
15
|
+
@Component({
|
|
16
|
+
selector: 'GlassView',
|
|
17
|
+
standalone: true,
|
|
18
|
+
imports: [SymbioteHostPropsDirective],
|
|
19
|
+
schemas: [NO_ERRORS_SCHEMA],
|
|
20
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
21
|
+
// Имя тега это нативное имя view, его нельзя собрать динамически
|
|
22
|
+
template: `@if (descriptor; as node) {
|
|
23
|
+
<ViewManagerAdapter_ExpoGlassEffect_GlassView [symbioteHostProps]="node.props">
|
|
24
|
+
<ng-content />
|
|
25
|
+
</ViewManagerAdapter_ExpoGlassEffect_GlassView>
|
|
26
|
+
}`,
|
|
27
|
+
})
|
|
28
|
+
export class GlassView extends GlassViewBase {
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
warnIfViewNameIsDynamic(VIEW_TAG, GLASS_EFFECT_MODULE_NAME, 'GlassView');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Angular twin of `expo-glass-effect`'s `GlassContainer`, merges the glass views it holds */
|
|
36
|
+
@Component({
|
|
37
|
+
selector: 'GlassContainer',
|
|
38
|
+
standalone: true,
|
|
39
|
+
imports: [SymbioteHostPropsDirective],
|
|
40
|
+
schemas: [NO_ERRORS_SCHEMA],
|
|
41
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
42
|
+
template: `@if (descriptor; as node) {
|
|
43
|
+
<ViewManagerAdapter_ExpoGlassEffect_GlassContainer [symbioteHostProps]="node.props">
|
|
44
|
+
<ng-content />
|
|
45
|
+
</ViewManagerAdapter_ExpoGlassEffect_GlassContainer>
|
|
46
|
+
}`,
|
|
47
|
+
})
|
|
48
|
+
export class GlassContainer extends GlassContainerBase {
|
|
49
|
+
constructor() {
|
|
50
|
+
super();
|
|
51
|
+
warnIfViewNameIsDynamic(
|
|
52
|
+
CONTAINER_TAG,
|
|
53
|
+
GLASS_EFFECT_MODULE_NAME,
|
|
54
|
+
'GlassContainer',
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Directive, Input } from '@angular/core';
|
|
2
|
+
import { NativeViewBase } from '@symbiote-native/angular';
|
|
3
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
4
|
+
import { renderGlassContainer, renderGlassView } from '../../core';
|
|
5
|
+
import type { IGlassContainerProps, IGlassViewProps } from '../../core';
|
|
6
|
+
|
|
7
|
+
// Inputs и сборка дескриптора общие, платформы различаются только шаблоном
|
|
8
|
+
@Directive()
|
|
9
|
+
export abstract class GlassViewBase extends NativeViewBase {
|
|
10
|
+
@Input() glassEffectStyle?: IGlassViewProps['glassEffectStyle'];
|
|
11
|
+
@Input() tintColor?: IGlassViewProps['tintColor'];
|
|
12
|
+
@Input() isInteractive?: IGlassViewProps['isInteractive'];
|
|
13
|
+
@Input() colorScheme?: IGlassViewProps['colorScheme'];
|
|
14
|
+
|
|
15
|
+
protected override readonly propNames = [
|
|
16
|
+
'glassEffectStyle',
|
|
17
|
+
'tintColor',
|
|
18
|
+
'isInteractive',
|
|
19
|
+
'colorScheme',
|
|
20
|
+
] as const satisfies readonly (keyof GlassViewBase)[];
|
|
21
|
+
|
|
22
|
+
protected override renderView(props: object): IDescriptor {
|
|
23
|
+
return renderGlassView(props);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Directive()
|
|
28
|
+
export abstract class GlassContainerBase extends NativeViewBase {
|
|
29
|
+
@Input() spacing?: IGlassContainerProps['spacing'];
|
|
30
|
+
|
|
31
|
+
protected override readonly propNames = [
|
|
32
|
+
'spacing',
|
|
33
|
+
] as const satisfies readonly (keyof GlassContainerBase)[];
|
|
34
|
+
|
|
35
|
+
protected override renderView(props: object): IDescriptor {
|
|
36
|
+
return renderGlassContainer(props);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @symbiote-native/glass-effect/angular: компоненты `GlassView` и `GlassContainer` поверх общего ядра
|
|
2
|
+
|
|
3
|
+
export { GlassContainer, GlassView } from './glass';
|
|
4
|
+
export {
|
|
5
|
+
GLASS_EFFECT_MODULE_NAME,
|
|
6
|
+
glassContainerName,
|
|
7
|
+
glassViewName,
|
|
8
|
+
isGlassEffectAPIAvailable,
|
|
9
|
+
isLiquidGlassAvailable,
|
|
10
|
+
type IGlassColorScheme,
|
|
11
|
+
type IGlassContainerProps,
|
|
12
|
+
type IGlassEffectStyleConfig,
|
|
13
|
+
type IGlassStyle,
|
|
14
|
+
type IGlassViewProps,
|
|
15
|
+
} from '../core';
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Ядро `GlassView` и `GlassContainer`, порт expo-glass-effect, нативное только на iOS
|
|
2
|
+
import {
|
|
3
|
+
Platform,
|
|
4
|
+
requireNativeModule,
|
|
5
|
+
requireNativeViewManager,
|
|
6
|
+
} from 'expo-modules-core';
|
|
7
|
+
import { el } from '@symbiote-native/components';
|
|
8
|
+
import type {
|
|
9
|
+
IAccessibilityProps,
|
|
10
|
+
IAriaProps,
|
|
11
|
+
IDescriptor,
|
|
12
|
+
IResponderProps,
|
|
13
|
+
} from '@symbiote-native/components';
|
|
14
|
+
import { defineExpoNativeViews } from '@symbiote-native/engine';
|
|
15
|
+
import type {
|
|
16
|
+
IColorValue,
|
|
17
|
+
IStyleProp,
|
|
18
|
+
ISymbioteEvent,
|
|
19
|
+
IViewStyle,
|
|
20
|
+
} from '@symbiote-native/engine';
|
|
21
|
+
|
|
22
|
+
export const GLASS_EFFECT_MODULE_NAME = 'ExpoGlassEffect';
|
|
23
|
+
const GLASS_VIEW_NAME = 'GlassView';
|
|
24
|
+
const GLASS_CONTAINER_NAME = 'GlassContainer';
|
|
25
|
+
|
|
26
|
+
export type IGlassStyle = 'clear' | 'regular' | 'none';
|
|
27
|
+
|
|
28
|
+
export type IGlassEffectStyleConfig = {
|
|
29
|
+
/** The glass effect style to apply */
|
|
30
|
+
style: IGlassStyle;
|
|
31
|
+
/**
|
|
32
|
+
* Whether to animate the style change
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
animate?: boolean;
|
|
36
|
+
/** Duration of the animation in seconds, the system default when omitted */
|
|
37
|
+
animationDuration?: number;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type IGlassColorScheme = 'auto' | 'light' | 'dark';
|
|
41
|
+
|
|
42
|
+
type IViewSurface = IAccessibilityProps &
|
|
43
|
+
IAriaProps &
|
|
44
|
+
IResponderProps & {
|
|
45
|
+
style?: IStyleProp<IViewStyle>;
|
|
46
|
+
testID?: string;
|
|
47
|
+
nativeID?: string;
|
|
48
|
+
onLayout?: (event: ISymbioteEvent) => void;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type IGlassViewProps = IViewSurface & {
|
|
52
|
+
/**
|
|
53
|
+
* A style name or a config object that controls the animation
|
|
54
|
+
* @default 'regular'
|
|
55
|
+
*/
|
|
56
|
+
glassEffectStyle?: IGlassStyle | IGlassEffectStyleConfig;
|
|
57
|
+
tintColor?: IColorValue;
|
|
58
|
+
/**
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
isInteractive?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Overrides the system appearance when the app has its own theme toggle
|
|
64
|
+
* @default 'auto'
|
|
65
|
+
*/
|
|
66
|
+
colorScheme?: IGlassColorScheme;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export type IGlassContainerProps = IViewSurface & {
|
|
70
|
+
/** The distance at which glass elements start affecting each other */
|
|
71
|
+
spacing?: number;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Эти ключи имеют смысл только у нативного view, у обычного View их быть не должно
|
|
75
|
+
const GLASS_VIEW_KEYS: ReadonlySet<string> = new Set<keyof IGlassViewProps>([
|
|
76
|
+
'glassEffectStyle',
|
|
77
|
+
'tintColor',
|
|
78
|
+
'isInteractive',
|
|
79
|
+
'colorScheme',
|
|
80
|
+
]);
|
|
81
|
+
const GLASS_CONTAINER_KEYS: ReadonlySet<string> = new Set<
|
|
82
|
+
keyof IGlassContainerProps
|
|
83
|
+
>(['spacing']);
|
|
84
|
+
|
|
85
|
+
// Регистрация идёт при рендере: побочный эффект барреля теряется в release
|
|
86
|
+
const views = defineExpoNativeViews(
|
|
87
|
+
requireNativeViewManager,
|
|
88
|
+
GLASS_EFFECT_MODULE_NAME,
|
|
89
|
+
{ glass: GLASS_VIEW_NAME, container: GLASS_CONTAINER_NAME },
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
export const glassViewName = views.glass.name;
|
|
93
|
+
export const glassContainerName = views.container.name;
|
|
94
|
+
export const ensureGlassViewRegistered = views.glass.ensureRegistered;
|
|
95
|
+
export const ensureGlassContainerRegistered = views.container.ensureRegistered;
|
|
96
|
+
|
|
97
|
+
function runsOnIos(): boolean {
|
|
98
|
+
return Platform.select({ ios: true, default: false });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function withoutKeys(
|
|
102
|
+
props: object,
|
|
103
|
+
keys: ReadonlySet<string>,
|
|
104
|
+
): Record<string, unknown> {
|
|
105
|
+
return Object.fromEntries(
|
|
106
|
+
Object.entries(props).filter(([key]) => !keys.has(key)),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// `object`, а не тип пропсов: Vue и Angular отдают нетипизированный набор атрибутов
|
|
111
|
+
export function renderGlassView(props: object): IDescriptor {
|
|
112
|
+
if (!runsOnIos()) return el('view', withoutKeys(props, GLASS_VIEW_KEYS));
|
|
113
|
+
if (!ensureGlassViewRegistered()) {
|
|
114
|
+
console.warn('GlassView is not available on this platform');
|
|
115
|
+
return el('view', withoutKeys(props, GLASS_VIEW_KEYS));
|
|
116
|
+
}
|
|
117
|
+
return el(glassViewName(), { ...props });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function renderGlassContainer(props: object): IDescriptor {
|
|
121
|
+
if (!runsOnIos()) {
|
|
122
|
+
return el('view', withoutKeys(props, GLASS_CONTAINER_KEYS));
|
|
123
|
+
}
|
|
124
|
+
if (!ensureGlassContainerRegistered()) {
|
|
125
|
+
console.warn('GlassContainer is not available on this platform');
|
|
126
|
+
return el('view', withoutKeys(props, GLASS_CONTAINER_KEYS));
|
|
127
|
+
}
|
|
128
|
+
return el(glassContainerName(), { ...props });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let isLiquidGlass: boolean | undefined;
|
|
132
|
+
let isGlassApi: boolean | undefined;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Whether the app renders with the Liquid Glass design, component availability only
|
|
136
|
+
* Accessibility settings can still limit the effect, see `AccessibilityInfo`
|
|
137
|
+
* @platform ios
|
|
138
|
+
*/
|
|
139
|
+
export function isLiquidGlassAvailable(): boolean {
|
|
140
|
+
if (!runsOnIos()) return false;
|
|
141
|
+
isLiquidGlass ??= !!Reflect.get(
|
|
142
|
+
requireNativeModule(GLASS_EFFECT_MODULE_NAME),
|
|
143
|
+
'isLiquidGlassAvailable',
|
|
144
|
+
);
|
|
145
|
+
return isLiquidGlass;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Whether the Liquid Glass API exists at runtime, some iOS 26 betas lack it and crash
|
|
150
|
+
* Check before using `GlassView` and `GlassContainer`
|
|
151
|
+
* @platform ios
|
|
152
|
+
*/
|
|
153
|
+
export function isGlassEffectAPIAvailable(): boolean {
|
|
154
|
+
if (!runsOnIos()) return false;
|
|
155
|
+
isGlassApi ??= !!Reflect.get(
|
|
156
|
+
requireNativeModule(GLASS_EFFECT_MODULE_NAME),
|
|
157
|
+
'isGlassEffectAPIAvailable',
|
|
158
|
+
);
|
|
159
|
+
return isGlassApi;
|
|
160
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
GLASS_EFFECT_MODULE_NAME,
|
|
3
|
+
ensureGlassContainerRegistered,
|
|
4
|
+
ensureGlassViewRegistered,
|
|
5
|
+
glassContainerName,
|
|
6
|
+
glassViewName,
|
|
7
|
+
isGlassEffectAPIAvailable,
|
|
8
|
+
isLiquidGlassAvailable,
|
|
9
|
+
renderGlassContainer,
|
|
10
|
+
renderGlassView,
|
|
11
|
+
type IGlassColorScheme,
|
|
12
|
+
type IGlassContainerProps,
|
|
13
|
+
type IGlassEffectStyleConfig,
|
|
14
|
+
type IGlassStyle,
|
|
15
|
+
type IGlassViewProps,
|
|
16
|
+
} from './glass-effect';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createElement } from 'react';
|
|
2
|
+
import type { ReactElement, ReactNode, RefObject } from 'react';
|
|
3
|
+
import type { IHostInstance, IViewProps } from '@symbiote-native/react';
|
|
4
|
+
import { renderGlassContainer, renderGlassView } from '../core';
|
|
5
|
+
import type { IGlassContainerProps, IGlassViewProps } from '../core';
|
|
6
|
+
|
|
7
|
+
// Поверхность View как у `ViewProps` в upstream, дети и `className` свои у React
|
|
8
|
+
export type IGlassViewReactProps = IGlassViewProps &
|
|
9
|
+
Omit<IViewProps, keyof IGlassViewProps | 'children' | 'ref'> & {
|
|
10
|
+
ref?: RefObject<IHostInstance | null>;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type IGlassContainerReactProps = IGlassContainerProps &
|
|
16
|
+
Omit<IViewProps, keyof IGlassContainerProps | 'children' | 'ref'> & {
|
|
17
|
+
ref?: RefObject<IHostInstance | null>;
|
|
18
|
+
children?: ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** React twin of `expo-glass-effect`'s `GlassView`, native on iOS and a plain View elsewhere */
|
|
23
|
+
export function GlassView(props: IGlassViewReactProps): ReactElement {
|
|
24
|
+
const { children, ...rest } = props;
|
|
25
|
+
const descriptor = renderGlassView(rest);
|
|
26
|
+
return createElement(descriptor.type, descriptor.props, children);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** React twin of `expo-glass-effect`'s `GlassContainer`, merges the glass views it holds */
|
|
30
|
+
export function GlassContainer(props: IGlassContainerReactProps): ReactElement {
|
|
31
|
+
const { children, ...rest } = props;
|
|
32
|
+
const descriptor = renderGlassContainer(rest);
|
|
33
|
+
return createElement(descriptor.type, descriptor.props, children);
|
|
34
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// @symbiote-native/glass-effect/react: компоненты `GlassView` и `GlassContainer` поверх общего ядра
|
|
2
|
+
|
|
3
|
+
export { GlassContainer, GlassView } from './glass-effect';
|
|
4
|
+
export type {
|
|
5
|
+
IGlassContainerReactProps as IGlassContainerProps,
|
|
6
|
+
IGlassViewReactProps as IGlassViewProps,
|
|
7
|
+
} from './glass-effect';
|
|
8
|
+
export {
|
|
9
|
+
GLASS_EFFECT_MODULE_NAME,
|
|
10
|
+
glassContainerName,
|
|
11
|
+
glassViewName,
|
|
12
|
+
isGlassEffectAPIAvailable,
|
|
13
|
+
isLiquidGlassAvailable,
|
|
14
|
+
type IGlassColorScheme,
|
|
15
|
+
type IGlassEffectStyleConfig,
|
|
16
|
+
type IGlassStyle,
|
|
17
|
+
} from '../core';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { JSX } from 'solid-js';
|
|
2
|
+
import { defineDescriptorComponent } from '@symbiote-native/solid';
|
|
3
|
+
import type { IViewProps } from '@symbiote-native/solid';
|
|
4
|
+
import type { IClassNameValue } from '@symbiote-native/engine';
|
|
5
|
+
import { renderGlassContainer, renderGlassView } from '../core';
|
|
6
|
+
import type { IGlassContainerProps, IGlassViewProps } from '../core';
|
|
7
|
+
|
|
8
|
+
// Поверхность View как у `ViewProps` в upstream, дети и `class` свои у Solid
|
|
9
|
+
export type IGlassViewSolidProps = IGlassViewProps &
|
|
10
|
+
Omit<IViewProps, keyof IGlassViewProps | 'children'> & {
|
|
11
|
+
children?: JSX.Element;
|
|
12
|
+
class?: IClassNameValue;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type IGlassContainerSolidProps = IGlassContainerProps &
|
|
16
|
+
Omit<IViewProps, keyof IGlassContainerProps | 'children'> & {
|
|
17
|
+
children?: JSX.Element;
|
|
18
|
+
class?: IClassNameValue;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Solid twin of `expo-glass-effect`'s `GlassView`, native on iOS and a plain View elsewhere */
|
|
22
|
+
export const GlassView =
|
|
23
|
+
defineDescriptorComponent<IGlassViewSolidProps>(renderGlassView);
|
|
24
|
+
|
|
25
|
+
/** Solid twin of `expo-glass-effect`'s `GlassContainer`, merges the glass views it holds */
|
|
26
|
+
export const GlassContainer =
|
|
27
|
+
defineDescriptorComponent<IGlassContainerSolidProps>(renderGlassContainer);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// @symbiote-native/glass-effect/solid: компоненты `GlassView` и `GlassContainer` поверх общего ядра
|
|
2
|
+
|
|
3
|
+
export { GlassContainer, GlassView } from './glass-effect';
|
|
4
|
+
export type {
|
|
5
|
+
IGlassContainerSolidProps as IGlassContainerProps,
|
|
6
|
+
IGlassViewSolidProps as IGlassViewProps,
|
|
7
|
+
} from './glass-effect';
|
|
8
|
+
export {
|
|
9
|
+
GLASS_EFFECT_MODULE_NAME,
|
|
10
|
+
glassContainerName,
|
|
11
|
+
glassViewName,
|
|
12
|
+
isGlassEffectAPIAvailable,
|
|
13
|
+
isLiquidGlassAvailable,
|
|
14
|
+
type IGlassColorScheme,
|
|
15
|
+
type IGlassEffectStyleConfig,
|
|
16
|
+
type IGlassStyle,
|
|
17
|
+
} from '../core';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import DescriptorHost from '@symbiote-native/svelte/descriptor-host';
|
|
3
|
+
import { renderGlassContainer } from '../core';
|
|
4
|
+
import type { IGlassContainerSvelteProps } from './glass-props';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
children,
|
|
8
|
+
ref = $bindable(),
|
|
9
|
+
...rest
|
|
10
|
+
}: IGlassContainerSvelteProps = $props();
|
|
11
|
+
const descriptor = $derived(renderGlassContainer({ ...rest }));
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<DescriptorHost {descriptor} bind:ref {children} />
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { IViewProps } from '@symbiote-native/svelte';
|
|
3
|
+
import type { IGlassContainerProps, IGlassViewProps } from '../core';
|
|
4
|
+
|
|
5
|
+
// Поверхность View как у `ViewProps` в upstream, дети идут сниппетом
|
|
6
|
+
export type IGlassViewSvelteProps = IGlassViewProps &
|
|
7
|
+
Omit<IViewProps, keyof IGlassViewProps | 'children'> & {
|
|
8
|
+
/** Host-ref через `bind:ref` */
|
|
9
|
+
ref?: unknown;
|
|
10
|
+
children?: Snippet;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type IGlassContainerSvelteProps = IGlassContainerProps &
|
|
14
|
+
Omit<IViewProps, keyof IGlassContainerProps | 'children'> & {
|
|
15
|
+
/** Host-ref через `bind:ref` */
|
|
16
|
+
ref?: unknown;
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import DescriptorHost from '@symbiote-native/svelte/descriptor-host';
|
|
3
|
+
import { renderGlassView } from '../core';
|
|
4
|
+
import type { IGlassViewSvelteProps } from './glass-props';
|
|
5
|
+
|
|
6
|
+
let { children, ref = $bindable(), ...rest }: IGlassViewSvelteProps = $props();
|
|
7
|
+
const descriptor = $derived(renderGlassView({ ...rest }));
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<DescriptorHost {descriptor} bind:ref {children} />
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @symbiote-native/glass-effect/svelte: компоненты `GlassView` и `GlassContainer` поверх общего ядра
|
|
2
|
+
|
|
3
|
+
export { default as GlassContainer } from './glass-container.svelte';
|
|
4
|
+
export { default as GlassView } from './glass-view.svelte';
|
|
5
|
+
export type {
|
|
6
|
+
IGlassContainerSvelteProps as IGlassContainerProps,
|
|
7
|
+
IGlassViewSvelteProps as IGlassViewProps,
|
|
8
|
+
} from './glass-props';
|
|
9
|
+
export {
|
|
10
|
+
GLASS_EFFECT_MODULE_NAME,
|
|
11
|
+
glassContainerName,
|
|
12
|
+
glassViewName,
|
|
13
|
+
isGlassEffectAPIAvailable,
|
|
14
|
+
isLiquidGlassAvailable,
|
|
15
|
+
type IGlassColorScheme,
|
|
16
|
+
type IGlassEffectStyleConfig,
|
|
17
|
+
type IGlassStyle,
|
|
18
|
+
} from '../core';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Pulls in svelte's ambient global declarations ($state/$effect/...) for this package's tsc
|
|
2
|
+
// program. adapters/svelte gets these for free because render.ts does a real value import from
|
|
3
|
+
// 'svelte' (any file in a program importing a module loads its ambient globals for the whole
|
|
4
|
+
// program); this package has no such import, so a triple-slash reference does the same job
|
|
5
|
+
// explicitly rather than relying on an incidental side-effect.
|
|
6
|
+
/// <reference types="svelte" />
|