@symbiote-native/blur 0.0.0-stage → 0.1.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 +217 -2
- package/build/angular/blur-target-view/index.android.d.ts +7 -0
- package/build/angular/blur-target-view/index.android.js +87 -0
- package/build/angular/blur-target-view/index.d.ts +1 -0
- package/build/angular/blur-target-view/index.ios.d.ts +6 -0
- package/build/angular/blur-target-view/index.ios.js +76 -0
- package/build/angular/blur-target-view/index.js +2 -0
- package/build/angular/blur-target-view/shared.d.ts +9 -0
- package/build/angular/blur-target-view/shared.js +64 -0
- package/build/angular/blur-view.d.ts +23 -0
- package/build/angular/blur-view.js +138 -0
- package/build/angular/index.d.ts +3 -0
- package/build/angular/index.js +4 -0
- package/build/core/blur.d.ts +53 -0
- package/build/core/blur.js +104 -0
- package/build/core/index.d.ts +1 -0
- package/build/core/index.js +1 -0
- package/build/react/blur.d.ts +18 -0
- package/build/react/blur.js +18 -0
- package/build/react/index.d.ts +3 -0
- package/build/react/index.js +3 -0
- package/build/solid/blur.d.ts +19 -0
- package/build/solid/blur.js +17 -0
- package/build/solid/index.d.ts +3 -0
- package/build/solid/index.js +3 -0
- package/build/svelte/blur-props.d.ts +13 -0
- package/build/svelte/blur-props.js +1 -0
- package/build/svelte/blur-target-view.svelte +14 -0
- package/build/svelte/blur-target-view.svelte.d.ts +4 -0
- package/build/svelte/blur-view.svelte +21 -0
- package/build/svelte/blur-view.svelte.d.ts +4 -0
- package/build/svelte/index.d.ts +4 -0
- package/build/svelte/index.js +4 -0
- package/build/vue/blur.d.ts +12 -0
- package/build/vue/blur.js +50 -0
- package/build/vue/index.d.ts +3 -0
- package/build/vue/index.js +3 -0
- package/build-ngc/angular/blur-target-view/index.android.d.ts +10 -0
- package/build-ngc/angular/blur-target-view/index.android.js +46 -0
- package/build-ngc/angular/blur-target-view/index.android.js.map +1 -0
- package/build-ngc/angular/blur-target-view/index.d.ts +1 -0
- package/build-ngc/angular/blur-target-view/index.ios.d.ts +9 -0
- package/build-ngc/angular/blur-target-view/index.ios.js +27 -0
- package/build-ngc/angular/blur-target-view/index.ios.js.map +1 -0
- package/build-ngc/angular/blur-target-view/index.js +3 -0
- package/build-ngc/angular/blur-target-view/index.js.map +1 -0
- package/build-ngc/angular/blur-target-view/shared.d.ts +12 -0
- package/build-ngc/angular/blur-target-view/shared.js +20 -0
- package/build-ngc/angular/blur-target-view/shared.js.map +1 -0
- package/build-ngc/angular/blur-view.d.ts +26 -0
- package/build-ngc/angular/blur-view.js +81 -0
- package/build-ngc/angular/blur-view.js.map +1 -0
- package/build-ngc/angular/index.d.ts +3 -0
- package/build-ngc/angular/index.js +5 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/core/blur.d.ts +53 -0
- package/build-ngc/core/blur.js +105 -0
- package/build-ngc/core/blur.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 +12 -0
- package/package.json +145 -3
- package/src/angular/blur-target-view/index.android.ts +46 -0
- package/src/angular/blur-target-view/index.ios.ts +25 -0
- package/src/angular/blur-target-view/index.ts +2 -0
- package/src/angular/blur-target-view/shared.ts +22 -0
- package/src/angular/blur-view.ts +87 -0
- package/src/angular/index.ts +13 -0
- package/src/core/blur.ts +214 -0
- package/src/core/index.ts +15 -0
- package/src/react/blur.ts +49 -0
- package/src/react/index.ts +14 -0
- package/src/solid/blur.ts +60 -0
- package/src/solid/index.ts +14 -0
- package/src/svelte/blur-props.ts +18 -0
- package/src/svelte/blur-target-view.svelte +14 -0
- package/src/svelte/blur-view.svelte +21 -0
- package/src/svelte/index.ts +15 -0
- package/src/svelte/svelte-ambient.d.ts +6 -0
- package/src/svelte/svelte-compile.test-helper.ts +6 -0
- package/src/vue/blur.ts +82 -0
- package/src/vue/index.ts +14 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChangeDetectionStrategy,
|
|
3
|
+
Component,
|
|
4
|
+
ElementRef,
|
|
5
|
+
ViewChild,
|
|
6
|
+
} from '@angular/core';
|
|
7
|
+
import { SymbioteHostPropsDirective, View } from '@symbiote-native/angular';
|
|
8
|
+
import { BlurTargetViewBase } from './shared';
|
|
9
|
+
|
|
10
|
+
/** Angular twin of `expo-blur`'s `BlurTargetView`, a plain View on iOS */
|
|
11
|
+
@Component({
|
|
12
|
+
selector: 'BlurTargetView',
|
|
13
|
+
standalone: true,
|
|
14
|
+
imports: [SymbioteHostPropsDirective, View],
|
|
15
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
16
|
+
template: `<view #host [symbioteHostProps]="hostProps"><ng-content /></view>`,
|
|
17
|
+
})
|
|
18
|
+
export class BlurTargetView extends BlurTargetViewBase {
|
|
19
|
+
@ViewChild('host', { read: ElementRef, static: true })
|
|
20
|
+
private readonly hostRef!: ElementRef<unknown>;
|
|
21
|
+
|
|
22
|
+
get nativeElement(): unknown {
|
|
23
|
+
return this.hostRef.nativeElement;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Directive, Input } from '@angular/core';
|
|
2
|
+
import { NativeViewBase } from '@symbiote-native/angular';
|
|
3
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
4
|
+
import { renderBlurTargetView } from '../../core';
|
|
5
|
+
|
|
6
|
+
// Платформы различаются только тегом в шаблоне, остальное общее
|
|
7
|
+
@Directive()
|
|
8
|
+
export abstract class BlurTargetViewBase extends NativeViewBase {
|
|
9
|
+
/** Нужен свойству `blurTarget` у `BlurView`, чтобы найти host-узел */
|
|
10
|
+
abstract readonly nativeElement: unknown;
|
|
11
|
+
|
|
12
|
+
protected readonly propNames =
|
|
13
|
+
[] as const satisfies readonly (keyof BlurTargetViewBase)[];
|
|
14
|
+
|
|
15
|
+
protected override renderView(props: object): IDescriptor {
|
|
16
|
+
return renderBlurTargetView(props);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get hostProps(): Record<string, unknown> {
|
|
20
|
+
return this.descriptor?.props ?? {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChangeDetectionStrategy,
|
|
3
|
+
Component,
|
|
4
|
+
Input,
|
|
5
|
+
type AfterViewInit,
|
|
6
|
+
type OnChanges,
|
|
7
|
+
type OnDestroy,
|
|
8
|
+
type SimpleChanges,
|
|
9
|
+
} from '@angular/core';
|
|
10
|
+
import {
|
|
11
|
+
DescriptorHost,
|
|
12
|
+
NativeViewBase,
|
|
13
|
+
hostNodeOf,
|
|
14
|
+
} from '@symbiote-native/angular';
|
|
15
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
16
|
+
import { renderBlurView, warnBlurProps, watchBlurTarget } from '../core';
|
|
17
|
+
import type { IBlurViewProps } from '../core';
|
|
18
|
+
|
|
19
|
+
/** Angular twin of `expo-blur`'s `BlurView`, the projected content paints over the blur */
|
|
20
|
+
@Component({
|
|
21
|
+
selector: 'BlurView',
|
|
22
|
+
standalone: true,
|
|
23
|
+
imports: [DescriptorHost],
|
|
24
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
25
|
+
template: `@if (descriptor; as node) {
|
|
26
|
+
<symbiote-descriptor-host [node]="node"
|
|
27
|
+
><ng-content
|
|
28
|
+
/></symbiote-descriptor-host>
|
|
29
|
+
}`,
|
|
30
|
+
})
|
|
31
|
+
export class BlurView
|
|
32
|
+
extends NativeViewBase
|
|
33
|
+
implements AfterViewInit, OnChanges, OnDestroy
|
|
34
|
+
{
|
|
35
|
+
@Input() tint?: IBlurViewProps['tint'];
|
|
36
|
+
@Input() intensity?: IBlurViewProps['intensity'];
|
|
37
|
+
@Input() blurReductionFactor?: IBlurViewProps['blurReductionFactor'];
|
|
38
|
+
@Input() experimentalBlurMethod?: IBlurViewProps['experimentalBlurMethod'];
|
|
39
|
+
@Input() blurMethod?: IBlurViewProps['blurMethod'];
|
|
40
|
+
/** Template ref на `BlurTargetView`, его содержимое это фон для размытия */
|
|
41
|
+
@Input() blurTarget?: unknown;
|
|
42
|
+
|
|
43
|
+
protected override readonly propNames = [
|
|
44
|
+
'tint',
|
|
45
|
+
'intensity',
|
|
46
|
+
'blurReductionFactor',
|
|
47
|
+
'experimentalBlurMethod',
|
|
48
|
+
'blurMethod',
|
|
49
|
+
] as const satisfies readonly (keyof BlurView)[];
|
|
50
|
+
|
|
51
|
+
private blurTargetId: number | undefined;
|
|
52
|
+
private cancelWatch = (): void => {};
|
|
53
|
+
private isViewReady = false;
|
|
54
|
+
|
|
55
|
+
protected override renderView(props: object): IDescriptor {
|
|
56
|
+
return renderBlurView(props, this.blurTargetId);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Цель ставится при создании представления соседа, поэтому ждём `ngAfterViewInit`
|
|
60
|
+
ngAfterViewInit(): void {
|
|
61
|
+
this.isViewReady = true;
|
|
62
|
+
this.watchTarget();
|
|
63
|
+
warnBlurProps(
|
|
64
|
+
Object.fromEntries(
|
|
65
|
+
this.propNames.map(name => [name, Reflect.get(this, name)]),
|
|
66
|
+
),
|
|
67
|
+
this.blurTarget !== undefined,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override ngOnChanges(changes: SimpleChanges): void {
|
|
72
|
+
super.ngOnChanges(changes);
|
|
73
|
+
if (this.isViewReady && 'blurTarget' in changes) this.watchTarget();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected override disposeView(): void {
|
|
77
|
+
this.cancelWatch();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private watchTarget(): void {
|
|
81
|
+
this.cancelWatch();
|
|
82
|
+
this.cancelWatch = watchBlurTarget(hostNodeOf(this.blurTarget), id => {
|
|
83
|
+
this.blurTargetId = id;
|
|
84
|
+
this.changeDetector.markForCheck();
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// @symbiote-native/blur/angular: компоненты `BlurView` и `BlurTargetView` поверх общего ядра
|
|
2
|
+
|
|
3
|
+
export { BlurView } from './blur-view';
|
|
4
|
+
export { BlurTargetView } from './blur-target-view';
|
|
5
|
+
export {
|
|
6
|
+
BLUR_MODULE_NAME,
|
|
7
|
+
blurTargetViewName,
|
|
8
|
+
blurViewName,
|
|
9
|
+
type IBlurMethod,
|
|
10
|
+
type IBlurTint,
|
|
11
|
+
type IBlurViewProps,
|
|
12
|
+
type IBlurTargetViewProps,
|
|
13
|
+
} from '../core';
|
package/src/core/blur.ts
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// Ядро `BlurView` и `BlurTargetView`, порт `BlurView.tsx` из expo-blur
|
|
2
|
+
import { Platform, requireNativeViewManager } from 'expo-modules-core';
|
|
3
|
+
import { el } from '@symbiote-native/components';
|
|
4
|
+
import type {
|
|
5
|
+
IAccessibilityProps,
|
|
6
|
+
IAriaProps,
|
|
7
|
+
IDescriptor,
|
|
8
|
+
IResponderProps,
|
|
9
|
+
} from '@symbiote-native/components';
|
|
10
|
+
import {
|
|
11
|
+
defineExpoNativeViews,
|
|
12
|
+
getNativeTag,
|
|
13
|
+
isSymbioteNode,
|
|
14
|
+
whenCommitted,
|
|
15
|
+
} from '@symbiote-native/engine';
|
|
16
|
+
import type {
|
|
17
|
+
IStyleProp,
|
|
18
|
+
ISymbioteEvent,
|
|
19
|
+
IViewStyle,
|
|
20
|
+
} from '@symbiote-native/engine';
|
|
21
|
+
|
|
22
|
+
export const BLUR_MODULE_NAME = 'ExpoBlur';
|
|
23
|
+
const BLUR_VIEW_NAME = 'ExpoBlurView';
|
|
24
|
+
const BLUR_TARGET_VIEW_NAME = 'ExpoBlurTargetView';
|
|
25
|
+
|
|
26
|
+
const BLUR_METHODS = [
|
|
27
|
+
'none',
|
|
28
|
+
'dimezisBlurView',
|
|
29
|
+
'dimezisBlurViewSdk31Plus',
|
|
30
|
+
] as const;
|
|
31
|
+
|
|
32
|
+
/** Метод размытия на Android: `none` это полупрозрачный view, остальные нативный BlurView */
|
|
33
|
+
export type IBlurMethod = (typeof BLUR_METHODS)[number];
|
|
34
|
+
|
|
35
|
+
const DEFAULT_BLUR_METHOD: IBlurMethod = BLUR_METHODS[0];
|
|
36
|
+
|
|
37
|
+
export type IBlurTint =
|
|
38
|
+
| 'light'
|
|
39
|
+
| 'dark'
|
|
40
|
+
| 'default'
|
|
41
|
+
| 'extraLight'
|
|
42
|
+
| 'regular'
|
|
43
|
+
| 'prominent'
|
|
44
|
+
| 'systemUltraThinMaterial'
|
|
45
|
+
| 'systemThinMaterial'
|
|
46
|
+
| 'systemMaterial'
|
|
47
|
+
| 'systemThickMaterial'
|
|
48
|
+
| 'systemChromeMaterial'
|
|
49
|
+
| 'systemUltraThinMaterialLight'
|
|
50
|
+
| 'systemThinMaterialLight'
|
|
51
|
+
| 'systemMaterialLight'
|
|
52
|
+
| 'systemThickMaterialLight'
|
|
53
|
+
| 'systemChromeMaterialLight'
|
|
54
|
+
| 'systemUltraThinMaterialDark'
|
|
55
|
+
| 'systemThinMaterialDark'
|
|
56
|
+
| 'systemMaterialDark'
|
|
57
|
+
| 'systemThickMaterialDark'
|
|
58
|
+
| 'systemChromeMaterialDark';
|
|
59
|
+
|
|
60
|
+
type IViewSurface = IAccessibilityProps &
|
|
61
|
+
IAriaProps &
|
|
62
|
+
IResponderProps & {
|
|
63
|
+
style?: IStyleProp<IViewStyle>;
|
|
64
|
+
testID?: string;
|
|
65
|
+
nativeID?: string;
|
|
66
|
+
onLayout?: (event: ISymbioteEvent) => void;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// `blurTarget` не здесь: у каждого адаптера свой тип ref
|
|
70
|
+
export type IBlurViewProps = IViewSurface & {
|
|
71
|
+
/** @default 'default' */
|
|
72
|
+
tint?: IBlurTint;
|
|
73
|
+
/**
|
|
74
|
+
* Сила размытия от 1 до 100
|
|
75
|
+
* @default 50
|
|
76
|
+
*/
|
|
77
|
+
intensity?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Делитель силы размытия на Android
|
|
80
|
+
* @default 4
|
|
81
|
+
* @platform android
|
|
82
|
+
*/
|
|
83
|
+
blurReductionFactor?: number;
|
|
84
|
+
/**
|
|
85
|
+
* @deprecated Use `blurMethod` instead
|
|
86
|
+
* @platform android
|
|
87
|
+
*/
|
|
88
|
+
experimentalBlurMethod?: IBlurMethod;
|
|
89
|
+
/**
|
|
90
|
+
* @default 'none'
|
|
91
|
+
* @platform android
|
|
92
|
+
*/
|
|
93
|
+
blurMethod?: IBlurMethod;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export type IBlurTargetViewProps = IViewSurface;
|
|
97
|
+
|
|
98
|
+
// Эти ключи разбираются здесь, остальное уходит на View как есть
|
|
99
|
+
const BLUR_KEYS: ReadonlySet<string> = new Set<keyof IBlurViewProps>([
|
|
100
|
+
'tint',
|
|
101
|
+
'intensity',
|
|
102
|
+
'blurReductionFactor',
|
|
103
|
+
'experimentalBlurMethod',
|
|
104
|
+
'blurMethod',
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
const ABSOLUTE_FILL = {
|
|
108
|
+
position: 'absolute',
|
|
109
|
+
left: 0,
|
|
110
|
+
right: 0,
|
|
111
|
+
top: 0,
|
|
112
|
+
bottom: 0,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const CONTAINER_STYLE = { backgroundColor: 'transparent' };
|
|
116
|
+
|
|
117
|
+
const DEPRECATED_METHOD_WARNING =
|
|
118
|
+
'The `experimentalBlurMethod` prop has been depracated. Please use the `blurMethod` prop instead.';
|
|
119
|
+
|
|
120
|
+
// Регистрация идёт при рендере: побочный эффект барреля теряется в release
|
|
121
|
+
const views = defineExpoNativeViews(
|
|
122
|
+
requireNativeViewManager,
|
|
123
|
+
BLUR_MODULE_NAME,
|
|
124
|
+
{
|
|
125
|
+
blur: BLUR_VIEW_NAME,
|
|
126
|
+
target: BLUR_TARGET_VIEW_NAME,
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
export const blurViewName = views.blur.name;
|
|
131
|
+
export const blurTargetViewName = views.target.name;
|
|
132
|
+
export const ensureBlurRegistered = views.blur.ensureRegistered;
|
|
133
|
+
export const ensureBlurTargetRegistered = views.target.ensureRegistered;
|
|
134
|
+
|
|
135
|
+
function isBlurMethod(value: unknown): value is IBlurMethod {
|
|
136
|
+
return BLUR_METHODS.some(method => method === value);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function blurMethodOf(props: object): IBlurMethod {
|
|
140
|
+
const provided: unknown = Reflect.get(props, 'blurMethod');
|
|
141
|
+
const deprecated: unknown = Reflect.get(props, 'experimentalBlurMethod');
|
|
142
|
+
if (isBlurMethod(provided)) return provided;
|
|
143
|
+
return isBlurMethod(deprecated) ? deprecated : DEFAULT_BLUR_METHOD;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Предупреждения из `componentDidMount` upstream, зовутся один раз при монтировании */
|
|
147
|
+
export function warnBlurProps(props: object, hasBlurTarget: boolean): void {
|
|
148
|
+
const method = blurMethodOf(props);
|
|
149
|
+
const isAndroidTarget = Platform.select({ android: true, default: false });
|
|
150
|
+
if (isAndroidTarget && method !== DEFAULT_BLUR_METHOD && !hasBlurTarget) {
|
|
151
|
+
console.warn(
|
|
152
|
+
`You have selected the "${method}" blur method, but the \`blurTarget\` prop has not been configured. The blur view will fallback to "none" blur method to avoid errors. You can learn more about the new BlurView API at: https://docs.expo.dev/versions/latest/sdk/blur-view/`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
if (Reflect.get(props, 'experimentalBlurMethod') != null) {
|
|
156
|
+
console.warn(DEPRECATED_METHOD_WARNING);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Отдаёт нативный тег цели размытия после её коммита, у не-узла отдаёт `undefined`
|
|
162
|
+
* Адаптер сам приводит свой ref к host-узлу, возвращённая функция отменяет ожидание
|
|
163
|
+
*/
|
|
164
|
+
export function watchBlurTarget(
|
|
165
|
+
target: unknown,
|
|
166
|
+
onId: (id: number | undefined) => void,
|
|
167
|
+
): () => void {
|
|
168
|
+
if (!isSymbioteNode(target)) {
|
|
169
|
+
onId(undefined);
|
|
170
|
+
return () => {};
|
|
171
|
+
}
|
|
172
|
+
return whenCommitted(target, () => onId(getNativeTag(target)));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// `object`, а не тип пропсов: Vue и Angular отдают нетипизированный набор атрибутов
|
|
176
|
+
export function renderBlurView(
|
|
177
|
+
props: object,
|
|
178
|
+
blurTargetId: number | null | undefined,
|
|
179
|
+
): IDescriptor {
|
|
180
|
+
const hostProps = Object.fromEntries(
|
|
181
|
+
Object.entries(props).filter(([key]) => !BLUR_KEYS.has(key)),
|
|
182
|
+
);
|
|
183
|
+
const style = [CONTAINER_STYLE, Reflect.get(props, 'style')];
|
|
184
|
+
if (!ensureBlurRegistered()) {
|
|
185
|
+
console.warn('BlurView is not available on this platform');
|
|
186
|
+
return el('view', { ...hostProps, style });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const tint: unknown = Reflect.get(props, 'tint');
|
|
190
|
+
const intensity: unknown = Reflect.get(props, 'intensity');
|
|
191
|
+
const reduction: unknown = Reflect.get(props, 'blurReductionFactor');
|
|
192
|
+
const native = el(blurViewName(), {
|
|
193
|
+
...(blurTargetId === undefined ? {} : { blurTargetId }),
|
|
194
|
+
tint: tint ?? 'default',
|
|
195
|
+
intensity: intensity ?? 50,
|
|
196
|
+
blurReductionFactor: reduction ?? 4,
|
|
197
|
+
blurMethod: blurMethodOf(props),
|
|
198
|
+
style: ABSOLUTE_FILL,
|
|
199
|
+
});
|
|
200
|
+
return el('view', { ...hostProps, style }, [native]);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Нативная цель размытия есть только на Android, на iOS это обычный View
|
|
204
|
+
export function renderBlurTargetView(props: object): IDescriptor {
|
|
205
|
+
const hostProps = { ...props };
|
|
206
|
+
if (!Platform.select({ android: true, default: false })) {
|
|
207
|
+
return el('view', hostProps);
|
|
208
|
+
}
|
|
209
|
+
if (!ensureBlurTargetRegistered()) {
|
|
210
|
+
console.warn('BlurTargetView is not available on this platform');
|
|
211
|
+
return el('view', hostProps);
|
|
212
|
+
}
|
|
213
|
+
return el(blurTargetViewName(), hostProps);
|
|
214
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
BLUR_MODULE_NAME,
|
|
3
|
+
blurTargetViewName,
|
|
4
|
+
blurViewName,
|
|
5
|
+
ensureBlurRegistered,
|
|
6
|
+
ensureBlurTargetRegistered,
|
|
7
|
+
renderBlurTargetView,
|
|
8
|
+
renderBlurView,
|
|
9
|
+
warnBlurProps,
|
|
10
|
+
watchBlurTarget,
|
|
11
|
+
type IBlurMethod,
|
|
12
|
+
type IBlurTargetViewProps,
|
|
13
|
+
type IBlurTint,
|
|
14
|
+
type IBlurViewProps,
|
|
15
|
+
} from './blur';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createElement, useEffect, useLayoutEffect, useState } from 'react';
|
|
2
|
+
import type { ReactElement, ReactNode, RefObject } from 'react';
|
|
3
|
+
import { descriptorToReactWithChildren } from '@symbiote-native/react';
|
|
4
|
+
import type { IHostInstance, IViewProps } from '@symbiote-native/react';
|
|
5
|
+
import {
|
|
6
|
+
renderBlurTargetView,
|
|
7
|
+
renderBlurView,
|
|
8
|
+
warnBlurProps,
|
|
9
|
+
watchBlurTarget,
|
|
10
|
+
} from '../core';
|
|
11
|
+
import type { IBlurTargetViewProps, IBlurViewProps } from '../core';
|
|
12
|
+
|
|
13
|
+
// Поверхность View как у `ViewProps` в upstream, дети и `className` свои у React
|
|
14
|
+
export type IBlurViewReactProps = IBlurViewProps &
|
|
15
|
+
Omit<IViewProps, keyof IBlurViewProps | 'children'> & {
|
|
16
|
+
/** Ref на `BlurTargetView`, его содержимое это фон для размытия */
|
|
17
|
+
blurTarget?: RefObject<IHostInstance | null>;
|
|
18
|
+
children?: ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type IBlurTargetViewReactProps = IBlurTargetViewProps &
|
|
23
|
+
Omit<IViewProps, keyof IBlurTargetViewProps | 'children' | 'ref'> & {
|
|
24
|
+
ref?: RefObject<IHostInstance | null>;
|
|
25
|
+
children?: ReactNode;
|
|
26
|
+
className?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** React twin of `expo-blur`'s `BlurView`, children paint over the blur */
|
|
30
|
+
export function BlurView(props: IBlurViewReactProps): ReactElement {
|
|
31
|
+
const { blurTarget, children, ...rest } = props;
|
|
32
|
+
const [blurTargetId, setBlurTargetId] = useState<number | undefined>();
|
|
33
|
+
|
|
34
|
+
// Без списка зависимостей, как `componentDidUpdate` upstream: ref цели ставится в коммите
|
|
35
|
+
useLayoutEffect(() => watchBlurTarget(blurTarget?.current, setBlurTargetId));
|
|
36
|
+
useEffect(() => warnBlurProps(rest, blurTarget !== undefined), []);
|
|
37
|
+
|
|
38
|
+
return descriptorToReactWithChildren(
|
|
39
|
+
renderBlurView(rest, blurTargetId),
|
|
40
|
+
children,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** React twin of `expo-blur`'s `BlurTargetView`, native on Android and a plain View on iOS */
|
|
45
|
+
export function BlurTargetView(props: IBlurTargetViewReactProps): ReactElement {
|
|
46
|
+
const { children, ...rest } = props;
|
|
47
|
+
const descriptor = renderBlurTargetView(rest);
|
|
48
|
+
return createElement(descriptor.type, descriptor.props, children);
|
|
49
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @symbiote-native/blur/react: компоненты `BlurView` и `BlurTargetView` поверх общего ядра
|
|
2
|
+
|
|
3
|
+
export { BlurTargetView, BlurView } from './blur';
|
|
4
|
+
export type {
|
|
5
|
+
IBlurTargetViewReactProps as IBlurTargetViewProps,
|
|
6
|
+
IBlurViewReactProps as IBlurViewProps,
|
|
7
|
+
} from './blur';
|
|
8
|
+
export {
|
|
9
|
+
BLUR_MODULE_NAME,
|
|
10
|
+
blurTargetViewName,
|
|
11
|
+
blurViewName,
|
|
12
|
+
type IBlurMethod,
|
|
13
|
+
type IBlurTint,
|
|
14
|
+
} from '../core';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createEffect,
|
|
3
|
+
createSignal,
|
|
4
|
+
onCleanup,
|
|
5
|
+
onMount,
|
|
6
|
+
splitProps,
|
|
7
|
+
} from 'solid-js';
|
|
8
|
+
import type { JSX } from 'solid-js';
|
|
9
|
+
import {
|
|
10
|
+
defineDescriptorComponent,
|
|
11
|
+
descriptorToSolid,
|
|
12
|
+
} from '@symbiote-native/solid';
|
|
13
|
+
import type { IHostInstance, IViewProps } from '@symbiote-native/solid';
|
|
14
|
+
import type { IClassNameValue } from '@symbiote-native/engine';
|
|
15
|
+
import {
|
|
16
|
+
renderBlurTargetView,
|
|
17
|
+
renderBlurView,
|
|
18
|
+
warnBlurProps,
|
|
19
|
+
watchBlurTarget,
|
|
20
|
+
} from '../core';
|
|
21
|
+
import type { IBlurTargetViewProps, IBlurViewProps } from '../core';
|
|
22
|
+
|
|
23
|
+
// Поверхность View как у `ViewProps` в upstream, дети и `class` свои у Solid
|
|
24
|
+
export type IBlurViewSolidProps = IBlurViewProps &
|
|
25
|
+
Omit<IViewProps, keyof IBlurViewProps | 'children' | 'ref'> & {
|
|
26
|
+
/** Host-узел `BlurTargetView`, его содержимое это фон для размытия */
|
|
27
|
+
blurTarget?: IHostInstance;
|
|
28
|
+
children?: JSX.Element;
|
|
29
|
+
class?: IClassNameValue;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type IBlurTargetViewSolidProps = IBlurTargetViewProps &
|
|
33
|
+
Omit<IViewProps, keyof IBlurTargetViewProps | 'children'> & {
|
|
34
|
+
children?: JSX.Element;
|
|
35
|
+
class?: IClassNameValue;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Solid twin of `expo-blur`'s `BlurView`, children paint over the blur */
|
|
39
|
+
export function BlurView(
|
|
40
|
+
props: IBlurViewSolidProps,
|
|
41
|
+
): ReturnType<typeof descriptorToSolid> {
|
|
42
|
+
const [local, rest] = splitProps(props, ['children', 'blurTarget']);
|
|
43
|
+
const [blurTargetId, setBlurTargetId] = createSignal<number | undefined>();
|
|
44
|
+
|
|
45
|
+
// Цель приходит сигналом после коммита, поэтому следим за ней, а не читаем один раз
|
|
46
|
+
createEffect(() => {
|
|
47
|
+
const cancel = watchBlurTarget(local.blurTarget, setBlurTargetId);
|
|
48
|
+
onCleanup(cancel);
|
|
49
|
+
});
|
|
50
|
+
onMount(() => warnBlurProps({ ...rest }, local.blurTarget !== undefined));
|
|
51
|
+
|
|
52
|
+
return descriptorToSolid(
|
|
53
|
+
() => renderBlurView({ ...rest }, blurTargetId()),
|
|
54
|
+
() => local.children,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Solid twin of `expo-blur`'s `BlurTargetView`, native on Android and a plain View on iOS */
|
|
59
|
+
export const BlurTargetView =
|
|
60
|
+
defineDescriptorComponent<IBlurTargetViewSolidProps>(renderBlurTargetView);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @symbiote-native/blur/solid: компоненты `BlurView` и `BlurTargetView` поверх общего ядра
|
|
2
|
+
|
|
3
|
+
export { BlurTargetView, BlurView } from './blur';
|
|
4
|
+
export type {
|
|
5
|
+
IBlurTargetViewSolidProps as IBlurTargetViewProps,
|
|
6
|
+
IBlurViewSolidProps as IBlurViewProps,
|
|
7
|
+
} from './blur';
|
|
8
|
+
export {
|
|
9
|
+
BLUR_MODULE_NAME,
|
|
10
|
+
blurTargetViewName,
|
|
11
|
+
blurViewName,
|
|
12
|
+
type IBlurMethod,
|
|
13
|
+
type IBlurTint,
|
|
14
|
+
} from '../core';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { IViewProps } from '@symbiote-native/svelte';
|
|
3
|
+
import type { IBlurTargetViewProps, IBlurViewProps } from '../core';
|
|
4
|
+
|
|
5
|
+
// Поверхность View как у `ViewProps` в upstream, дети идут сниппетом
|
|
6
|
+
export type IBlurViewSvelteProps = IBlurViewProps &
|
|
7
|
+
Omit<IViewProps, keyof IBlurViewProps | 'children'> & {
|
|
8
|
+
/** Значение `bind:ref` от `BlurTargetView`, его содержимое это фон для размытия */
|
|
9
|
+
blurTarget?: unknown;
|
|
10
|
+
children?: Snippet;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type IBlurTargetViewSvelteProps = IBlurTargetViewProps &
|
|
14
|
+
Omit<IViewProps, keyof IBlurTargetViewProps | 'children'> & {
|
|
15
|
+
/** Host-ref, отдаётся через `bind:ref` и передаётся в `blurTarget` у `BlurView` */
|
|
16
|
+
ref?: unknown;
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import DescriptorHost from '@symbiote-native/svelte/descriptor-host';
|
|
3
|
+
import { renderBlurTargetView } from '../core';
|
|
4
|
+
import type { IBlurTargetViewSvelteProps } from './blur-props';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
children,
|
|
8
|
+
ref = $bindable(),
|
|
9
|
+
...rest
|
|
10
|
+
}: IBlurTargetViewSvelteProps = $props();
|
|
11
|
+
const descriptor = $derived(renderBlurTargetView({ ...rest }));
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<DescriptorHost {descriptor} bind:ref {children} />
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import DescriptorHost from '@symbiote-native/svelte/descriptor-host';
|
|
3
|
+
import { hostInstance } from '@symbiote-native/svelte/native-view-bridge';
|
|
4
|
+
import { renderBlurView, warnBlurProps, watchBlurTarget } from '../core';
|
|
5
|
+
import type { IBlurViewSvelteProps } from './blur-props';
|
|
6
|
+
|
|
7
|
+
const { children, blurTarget, ...rest }: IBlurViewSvelteProps = $props();
|
|
8
|
+
let blurTargetId = $state<number | undefined>();
|
|
9
|
+
|
|
10
|
+
// Цель приходит после монтирования и мутирует, поэтому эффект следит за ней
|
|
11
|
+
$effect(() =>
|
|
12
|
+
watchBlurTarget(hostInstance(blurTarget), id => {
|
|
13
|
+
blurTargetId = id;
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
16
|
+
$effect(() => warnBlurProps({ ...rest }, blurTarget !== undefined));
|
|
17
|
+
|
|
18
|
+
const descriptor = $derived(renderBlurView({ ...rest }, blurTargetId));
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<DescriptorHost {descriptor} {children} />
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @symbiote-native/blur/svelte: компоненты `BlurView` и `BlurTargetView` поверх общего ядра
|
|
2
|
+
|
|
3
|
+
export { default as BlurTargetView } from './blur-target-view.svelte';
|
|
4
|
+
export { default as BlurView } from './blur-view.svelte';
|
|
5
|
+
export type {
|
|
6
|
+
IBlurTargetViewSvelteProps as IBlurTargetViewProps,
|
|
7
|
+
IBlurViewSvelteProps as IBlurViewProps,
|
|
8
|
+
} from './blur-props';
|
|
9
|
+
export {
|
|
10
|
+
BLUR_MODULE_NAME,
|
|
11
|
+
blurTargetViewName,
|
|
12
|
+
blurViewName,
|
|
13
|
+
type IBlurMethod,
|
|
14
|
+
type IBlurTint,
|
|
15
|
+
} 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" />
|