@symbiote-native/clipboard 3.0.2 → 3.0.3
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 +62 -28
- package/build/angular/clipboard-paste-button/index.d.ts +15 -0
- package/build/angular/clipboard-paste-button/index.js +119 -0
- package/build/core/clipboard-paste-button.d.ts +29 -0
- package/build/core/clipboard-paste-button.js +50 -0
- package/build/core/clipboard.d.ts +2 -0
- package/build/core/clipboard.js +6 -1
- package/build/core/index.d.ts +3 -2
- package/build/core/index.js +2 -1
- package/build/core/native-module.d.ts +1 -0
- package/build/core/types.d.ts +11 -0
- package/build/core/types.js +1 -4
- package/build/react/clipboard-paste-button.d.ts +4 -0
- package/build/react/clipboard-paste-button.js +7 -0
- package/build/react/index.d.ts +1 -0
- package/build/react/index.js +1 -0
- package/build/solid/clipboard-paste-button.d.ts +3 -0
- package/build/solid/clipboard-paste-button.js +10 -0
- package/build/solid/index.d.ts +1 -0
- package/build/solid/index.js +1 -0
- package/build/svelte/clipboard-paste-button.svelte +17 -0
- package/build/svelte/clipboard-paste-button.svelte.d.ts +4 -0
- package/build/svelte/index.d.ts +1 -0
- package/build/svelte/index.js +1 -0
- package/build/vue/clipboard-paste-button.d.ts +3 -0
- package/build/vue/clipboard-paste-button.js +15 -0
- package/build/vue/index.d.ts +1 -0
- package/build/vue/index.js +1 -0
- package/build-ngc/angular/clipboard-paste-button/index.d.ts +18 -0
- package/build-ngc/angular/clipboard-paste-button/index.js +58 -0
- package/build-ngc/angular/clipboard-paste-button/index.js.map +1 -0
- package/build-ngc/core/clipboard-paste-button.d.ts +29 -0
- package/build-ngc/core/clipboard-paste-button.js +51 -0
- package/build-ngc/core/clipboard-paste-button.js.map +1 -0
- package/build-ngc/core/clipboard.d.ts +2 -0
- package/build-ngc/core/clipboard.js +6 -1
- package/build-ngc/core/clipboard.js.map +1 -1
- package/build-ngc/core/index.d.ts +3 -2
- package/build-ngc/core/index.js +2 -1
- package/build-ngc/core/index.js.map +1 -1
- package/build-ngc/core/native-module.d.ts +1 -0
- package/build-ngc/core/native-module.js.map +1 -1
- package/build-ngc/core/types.d.ts +11 -0
- package/build-ngc/core/types.js +1 -4
- package/build-ngc/core/types.js.map +1 -1
- package/package.json +17 -19
- package/src/angular/clipboard-paste-button/index.ts +40 -0
- package/src/core/clipboard-paste-button.ts +113 -0
- package/src/core/clipboard.ts +7 -1
- package/src/core/index.ts +14 -0
- package/src/core/native-module.ts +2 -0
- package/src/core/types.ts +19 -4
- package/src/react/clipboard-paste-button.ts +12 -0
- package/src/react/index.ts +1 -0
- package/src/solid/clipboard-paste-button.ts +15 -0
- package/src/solid/index.ts +1 -0
- package/src/svelte/clipboard-paste-button.svelte +17 -0
- package/src/svelte/index.ts +1 -0
- package/src/svelte/svelte-compile.test-helper.ts +6 -0
- package/src/vue/clipboard-paste-button.ts +16 -0
- package/src/vue/index.ts +1 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NativeViewBase } from '@symbiote-native/angular';
|
|
2
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
3
|
+
import type { IClipboardPasteButtonProps } from '../../core/clipboard-paste-button';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/** Angular twin of `expo-clipboard`'s `ClipboardPasteButton` (`UIPasteControl`), iOS only */
|
|
6
|
+
export declare class ClipboardPasteButton extends NativeViewBase {
|
|
7
|
+
onPress: IClipboardPasteButtonProps['onPress'];
|
|
8
|
+
backgroundColor?: IClipboardPasteButtonProps['backgroundColor'];
|
|
9
|
+
foregroundColor?: IClipboardPasteButtonProps['foregroundColor'];
|
|
10
|
+
cornerStyle?: IClipboardPasteButtonProps['cornerStyle'];
|
|
11
|
+
displayMode?: IClipboardPasteButtonProps['displayMode'];
|
|
12
|
+
imageOptions?: IClipboardPasteButtonProps['imageOptions'];
|
|
13
|
+
acceptedContentTypes?: IClipboardPasteButtonProps['acceptedContentTypes'];
|
|
14
|
+
protected readonly propNames: readonly ["onPress", "backgroundColor", "foregroundColor", "cornerStyle", "displayMode", "imageOptions", "acceptedContentTypes"];
|
|
15
|
+
protected renderView(props: object): IDescriptor | null;
|
|
16
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ClipboardPasteButton, never>;
|
|
17
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ClipboardPasteButton, "ClipboardPasteButton", never, { "onPress": { "alias": "onPress"; "required": true; }; "backgroundColor": { "alias": "backgroundColor"; "required": false; }; "foregroundColor": { "alias": "foregroundColor"; "required": false; }; "cornerStyle": { "alias": "cornerStyle"; "required": false; }; "displayMode": { "alias": "displayMode"; "required": false; }; "imageOptions": { "alias": "imageOptions"; "required": false; }; "acceptedContentTypes": { "alias": "acceptedContentTypes"; "required": false; }; }, {}, never, never, true, never>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
import { DescriptorOutlet, NativeViewBase } from '@symbiote-native/angular';
|
|
3
|
+
import { renderClipboardPasteButton } from '../../core/clipboard-paste-button';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/** Angular twin of `expo-clipboard`'s `ClipboardPasteButton` (`UIPasteControl`), iOS only */
|
|
6
|
+
export class ClipboardPasteButton extends NativeViewBase {
|
|
7
|
+
onPress;
|
|
8
|
+
backgroundColor;
|
|
9
|
+
foregroundColor;
|
|
10
|
+
cornerStyle;
|
|
11
|
+
displayMode;
|
|
12
|
+
imageOptions;
|
|
13
|
+
acceptedContentTypes;
|
|
14
|
+
propNames = [
|
|
15
|
+
'onPress',
|
|
16
|
+
'backgroundColor',
|
|
17
|
+
'foregroundColor',
|
|
18
|
+
'cornerStyle',
|
|
19
|
+
'displayMode',
|
|
20
|
+
'imageOptions',
|
|
21
|
+
'acceptedContentTypes',
|
|
22
|
+
];
|
|
23
|
+
renderView(props) {
|
|
24
|
+
return renderClipboardPasteButton(props);
|
|
25
|
+
}
|
|
26
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ClipboardPasteButton, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
27
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: ClipboardPasteButton, isStandalone: true, selector: "ClipboardPasteButton", inputs: { onPress: "onPress", backgroundColor: "backgroundColor", foregroundColor: "foregroundColor", cornerStyle: "cornerStyle", displayMode: "displayMode", imageOptions: "imageOptions", acceptedContentTypes: "acceptedContentTypes" }, usesInheritance: true, ngImport: i0, template: `@if (descriptor; as node) {
|
|
28
|
+
<symbiote-descriptor-outlet [node]="node" />
|
|
29
|
+
}`, isInline: true, dependencies: [{ kind: "component", type: DescriptorOutlet, selector: "symbiote-descriptor-outlet", inputs: ["node"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
30
|
+
}
|
|
31
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ClipboardPasteButton, decorators: [{
|
|
32
|
+
type: Component,
|
|
33
|
+
args: [{
|
|
34
|
+
selector: 'ClipboardPasteButton',
|
|
35
|
+
standalone: true,
|
|
36
|
+
imports: [DescriptorOutlet],
|
|
37
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
38
|
+
template: `@if (descriptor; as node) {
|
|
39
|
+
<symbiote-descriptor-outlet [node]="node" />
|
|
40
|
+
}`,
|
|
41
|
+
}]
|
|
42
|
+
}], propDecorators: { onPress: [{
|
|
43
|
+
type: Input,
|
|
44
|
+
args: [{ required: true }]
|
|
45
|
+
}], backgroundColor: [{
|
|
46
|
+
type: Input
|
|
47
|
+
}], foregroundColor: [{
|
|
48
|
+
type: Input
|
|
49
|
+
}], cornerStyle: [{
|
|
50
|
+
type: Input
|
|
51
|
+
}], displayMode: [{
|
|
52
|
+
type: Input
|
|
53
|
+
}], imageOptions: [{
|
|
54
|
+
type: Input
|
|
55
|
+
}], acceptedContentTypes: [{
|
|
56
|
+
type: Input
|
|
57
|
+
}] } });
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/angular/clipboard-paste-button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;;AAG/E,6FAA6F;AAU7F,MAAM,OAAO,oBAAqB,SAAQ,cAAc;IAC3B,OAAO,CAAyC;IAClE,eAAe,CAAiD;IAChE,eAAe,CAAiD;IAChE,WAAW,CAA6C;IACxD,WAAW,CAA6C;IACxD,YAAY,CAA8C;IAEnE,oBAAoB,CAAsD;IAE9C,SAAS,GAAG;QACtC,SAAS;QACT,iBAAiB;QACjB,iBAAiB;QACjB,aAAa;QACb,aAAa;QACb,cAAc;QACd,sBAAsB;KACoC,CAAC;IAE1C,UAAU,CAAC,KAAa;QACzC,OAAO,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;uGAtBU,oBAAoB;2FAApB,oBAAoB,mVAJrB;;IAER,4DAJQ,gBAAgB;;2FAMf,oBAAoB;kBAThC,SAAS;mBAAC;oBACT,QAAQ,EAAE,sBAAsB;oBAChC,UAAU,EAAE,IAAI;oBAChB,OAAO,EAAE,CAAC,gBAAgB,CAAC;oBAC3B,eAAe,EAAE,uBAAuB,CAAC,MAAM;oBAC/C,QAAQ,EAAE;;IAER;iBACH;;sBAEE,KAAK;uBAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;;sBACxB,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IAccessibilityProps, IAriaProps, IDescriptor, IResponderProps } from '@symbiote-native/components';
|
|
2
|
+
import type { IStyleProp, ISymbioteEvent, IViewStyle } from '@symbiote-native/engine';
|
|
3
|
+
import type { IAcceptedContentType, ICornerStyle, IDisplayMode, IGetImageOptions, IPasteEventPayload } from './types';
|
|
4
|
+
export declare const CLIPBOARD_PASTE_BUTTON_MODULE_NAME = "ExpoClipboard";
|
|
5
|
+
export type IClipboardPasteButtonProps = IAccessibilityProps & IAriaProps & IResponderProps & {
|
|
6
|
+
/** Called with the pasted text or image, inspect `type` to tell them apart */
|
|
7
|
+
onPress: (data: IPasteEventPayload) => void;
|
|
8
|
+
/** Leaving it out lets the color follow the system theme */
|
|
9
|
+
backgroundColor?: string | null;
|
|
10
|
+
/** @default 'white' */
|
|
11
|
+
foregroundColor?: string | null;
|
|
12
|
+
/** @default 'capsule' */
|
|
13
|
+
cornerStyle?: ICornerStyle | null;
|
|
14
|
+
/** @default 'iconAndLabel' */
|
|
15
|
+
displayMode?: IDisplayMode | null;
|
|
16
|
+
/** Needs a width and a height, or the button does not appear */
|
|
17
|
+
style?: IStyleProp<Omit<IViewStyle, 'backgroundColor' | 'borderRadius' | 'color'>>;
|
|
18
|
+
imageOptions?: IGetImageOptions | null;
|
|
19
|
+
/** Do not combine `plain-text` with `html`, all text would be treated as `html` */
|
|
20
|
+
acceptedContentTypes?: IAcceptedContentType[];
|
|
21
|
+
testID?: string;
|
|
22
|
+
nativeID?: string;
|
|
23
|
+
onLayout?: (event: ISymbioteEvent) => void;
|
|
24
|
+
};
|
|
25
|
+
export declare function clipboardPasteButtonViewName(): string;
|
|
26
|
+
export declare function ensureClipboardPasteButtonRegistered(): boolean;
|
|
27
|
+
/** Reads the native paste event, `null` when its payload has neither a text nor an image shape */
|
|
28
|
+
export declare function toPasteEventPayload(event: ISymbioteEvent): IPasteEventPayload | null;
|
|
29
|
+
export declare function renderClipboardPasteButton(props: object): IDescriptor | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Platform, requireNativeViewManager } from 'expo-modules-core';
|
|
2
|
+
import { el } from '@symbiote-native/components';
|
|
3
|
+
import { expoViewManagerName, tryRegisterNativeView, } from '@symbiote-native/engine';
|
|
4
|
+
export const CLIPBOARD_PASTE_BUTTON_MODULE_NAME = 'ExpoClipboard';
|
|
5
|
+
const PASTE_EVENT_PROP = 'onPastePressed';
|
|
6
|
+
const PASTE_TYPE = { text: 'text', image: 'image' };
|
|
7
|
+
export function clipboardPasteButtonViewName() {
|
|
8
|
+
return expoViewManagerName(CLIPBOARD_PASTE_BUTTON_MODULE_NAME);
|
|
9
|
+
}
|
|
10
|
+
// Registers the view config in React Native's registry, which the engine derives the view's events
|
|
11
|
+
// and prop processors from. Called at render, not at import: a registration that only a barrel's
|
|
12
|
+
// load-time side effect performs is dropped by Metro's `inlineRequires` in release
|
|
13
|
+
export function ensureClipboardPasteButtonRegistered() {
|
|
14
|
+
if (!Platform.select({ ios: true, default: false }))
|
|
15
|
+
return false;
|
|
16
|
+
return tryRegisterNativeView(() => requireNativeViewManager(CLIPBOARD_PASTE_BUTTON_MODULE_NAME));
|
|
17
|
+
}
|
|
18
|
+
function isImageSize(value) {
|
|
19
|
+
return (typeof value === 'object' &&
|
|
20
|
+
value !== null &&
|
|
21
|
+
typeof Reflect.get(value, 'width') === 'number' &&
|
|
22
|
+
typeof Reflect.get(value, 'height') === 'number');
|
|
23
|
+
}
|
|
24
|
+
/** Reads the native paste event, `null` when its payload has neither a text nor an image shape */
|
|
25
|
+
export function toPasteEventPayload(event) {
|
|
26
|
+
const { type, text, data, size } = event.nativeEvent;
|
|
27
|
+
if (type === PASTE_TYPE.text && typeof text === 'string')
|
|
28
|
+
return { type, text };
|
|
29
|
+
if (type === PASTE_TYPE.image &&
|
|
30
|
+
typeof data === 'string' &&
|
|
31
|
+
isImageSize(size)) {
|
|
32
|
+
return { type, data, size };
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
// `object`, not the props type: Vue and Angular hand over an untyped attribute bag
|
|
37
|
+
export function renderClipboardPasteButton(props) {
|
|
38
|
+
if (!ensureClipboardPasteButtonRegistered())
|
|
39
|
+
return null;
|
|
40
|
+
const onPress = Reflect.get(props, 'onPress');
|
|
41
|
+
const viewProps = Object.fromEntries(Object.entries(props).filter(([key]) => key !== 'onPress'));
|
|
42
|
+
return el(clipboardPasteButtonViewName(), {
|
|
43
|
+
...viewProps,
|
|
44
|
+
[PASTE_EVENT_PROP]: (event) => {
|
|
45
|
+
const payload = toPasteEventPayload(event);
|
|
46
|
+
if (payload && typeof onPress === 'function')
|
|
47
|
+
onPress(payload);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=clipboard-paste-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard-paste-button.js","sourceRoot":"","sources":["../../src/core/clipboard-paste-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAC;AAOjD,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,yBAAyB,CAAC;AAejC,MAAM,CAAC,MAAM,kCAAkC,GAAG,eAAe,CAAC;AAElE,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAE1C,MAAM,UAAU,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAW,CAAC;AA4B7D,MAAM,UAAU,4BAA4B;IAC1C,OAAO,mBAAmB,CAAC,kCAAkC,CAAC,CAAC;AACjE,CAAC;AAED,mGAAmG;AACnG,iGAAiG;AACjG,mFAAmF;AACnF,MAAM,UAAU,oCAAoC;IAClD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,OAAO,qBAAqB,CAAC,GAAG,EAAE,CAChC,wBAAwB,CAAC,kCAAkC,CAAC,CAC7D,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,QAAQ;QAC/C,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,QAAQ,CACjD,CAAC;AACJ,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,mBAAmB,CACjC,KAAqB;IAErB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC;IACrD,IAAI,IAAI,KAAK,UAAU,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QACtD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,IACE,IAAI,KAAK,UAAU,CAAC,KAAK;QACzB,OAAO,IAAI,KAAK,QAAQ;QACxB,WAAW,CAAC,IAAI,CAAC,EACjB,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,0BAA0B,CAAC,KAAa;IACtD,IAAI,CAAC,oCAAoC,EAAE;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,OAAO,GAAY,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAClC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAC3D,CAAC;IACF,OAAO,EAAE,CAAC,4BAA4B,EAAE,EAAE;QACxC,GAAG,SAAS;QACZ,CAAC,gBAAgB,CAAC,EAAE,CAAC,KAAqB,EAAQ,EAAE;YAClD,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC3C,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,UAAU;gBAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACjE,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -79,6 +79,8 @@ export declare function hasImageAsync(): Promise<boolean>;
|
|
|
79
79
|
* content types whenever the clipboard changes.
|
|
80
80
|
*/
|
|
81
81
|
export declare function addClipboardListener(listener: (event: IClipboardEvent) => void): EventSubscription;
|
|
82
|
+
/** Whether `ClipboardPasteButton` can render, needs iOS 16 or newer */
|
|
83
|
+
export declare const isPasteButtonAvailable: boolean;
|
|
82
84
|
/**
|
|
83
85
|
* Removes the listener added by `addClipboardListener`.
|
|
84
86
|
* @deprecated use `subscription.remove()` instead.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UnavailabilityError } from 'expo-modules-core';
|
|
1
|
+
import { Platform, UnavailabilityError } from 'expo-modules-core';
|
|
2
2
|
import { CLIPBOARD_CHANGED_EVENT_NAME, expoClipboard } from './native-module';
|
|
3
3
|
// Matches the module name upstream's own Clipboard.ts passes to every UnavailabilityError.
|
|
4
4
|
const NATIVE_MODULE_NAME = 'Clipboard';
|
|
@@ -133,6 +133,11 @@ export async function hasImageAsync() {
|
|
|
133
133
|
export function addClipboardListener(listener) {
|
|
134
134
|
return expoClipboard.addListener(CLIPBOARD_CHANGED_EVENT_NAME, listener);
|
|
135
135
|
}
|
|
136
|
+
/** Whether `ClipboardPasteButton` can render, needs iOS 16 or newer */
|
|
137
|
+
export const isPasteButtonAvailable = Platform.select({
|
|
138
|
+
ios: expoClipboard.isPasteButtonAvailable ?? false,
|
|
139
|
+
default: false,
|
|
140
|
+
});
|
|
136
141
|
/**
|
|
137
142
|
* Removes the listener added by `addClipboardListener`.
|
|
138
143
|
* @deprecated use `subscription.remove()` instead.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/core/clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/core/clipboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { getStringAsync, setStringAsync, hasStringAsync, getUrlAsync, setUrlAsync, hasUrlAsync, getImageAsync, setImageAsync, hasImageAsync, addClipboardListener, removeClipboardListener, } from './clipboard';
|
|
2
|
-
export {
|
|
1
|
+
export { getStringAsync, setStringAsync, hasStringAsync, getUrlAsync, setUrlAsync, hasUrlAsync, getImageAsync, setImageAsync, hasImageAsync, addClipboardListener, removeClipboardListener, isPasteButtonAvailable, } from './clipboard';
|
|
2
|
+
export { clipboardPasteButtonViewName, ensureClipboardPasteButtonRegistered, renderClipboardPasteButton, toPasteEventPayload, type IClipboardPasteButtonProps, } from './clipboard-paste-button';
|
|
3
|
+
export { ContentType, StringFormat, type IGetStringOptions, type ISetStringOptions, type IGetImageOptions, type IClipboardImage, type IClipboardEvent, type IAcceptedContentType, type ICornerStyle, type IDisplayMode, type ITextPasteEvent, type IImagePasteEvent, type IPasteEventPayload, } from './types';
|
|
3
4
|
export type { EventSubscription } from 'expo-modules-core';
|
package/build-ngc/core/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { getStringAsync, setStringAsync, hasStringAsync, getUrlAsync, setUrlAsync, hasUrlAsync, getImageAsync, setImageAsync, hasImageAsync, addClipboardListener, removeClipboardListener, } from './clipboard';
|
|
1
|
+
export { getStringAsync, setStringAsync, hasStringAsync, getUrlAsync, setUrlAsync, hasUrlAsync, getImageAsync, setImageAsync, hasImageAsync, addClipboardListener, removeClipboardListener, isPasteButtonAvailable, } from './clipboard';
|
|
2
|
+
export { clipboardPasteButtonViewName, ensureClipboardPasteButtonRegistered, renderClipboardPasteButton, toPasteEventPayload, } from './clipboard-paste-button';
|
|
2
3
|
export { ContentType, StringFormat, } from './types';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,4BAA4B,EAC5B,oCAAoC,EACpC,0BAA0B,EAC1B,mBAAmB,GAEpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,WAAW,EACX,YAAY,GAYb,MAAM,SAAS,CAAC"}
|
|
@@ -13,5 +13,6 @@ export type INativeClipboardModule = {
|
|
|
13
13
|
getImageAsync?(options: IGetImageOptions): Promise<IClipboardImage | null>;
|
|
14
14
|
setImageAsync?(base64Image: string): Promise<void>;
|
|
15
15
|
hasImageAsync?(): Promise<boolean>;
|
|
16
|
+
isPasteButtonAvailable?: boolean;
|
|
16
17
|
};
|
|
17
18
|
export declare const expoClipboard: INativeClipboardModule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAUxD,MAAM,0BAA0B,GAAG,eAAe,CAAC;AAEnD,4FAA4F;AAC5F,8FAA8F;AAC9F,mBAAmB;AACnB,MAAM,CAAC,MAAM,4BAA4B,GAAG,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAUxD,MAAM,0BAA0B,GAAG,eAAe,CAAC;AAEnD,4FAA4F;AAC5F,8FAA8F;AAC9F,mBAAmB;AACnB,MAAM,CAAC,MAAM,4BAA4B,GAAG,oBAAoB,CAAC;AA0BjE,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAC9C,0BAA0B,CAC3B,CAAC"}
|
|
@@ -65,3 +65,14 @@ export type IClipboardEvent = {
|
|
|
65
65
|
*/
|
|
66
66
|
contentTypes: ContentType[];
|
|
67
67
|
};
|
|
68
|
+
export type IAcceptedContentType = 'plain-text' | 'image' | 'url' | 'html';
|
|
69
|
+
export type ICornerStyle = 'dynamic' | 'fixed' | 'capsule' | 'large' | 'medium' | 'small';
|
|
70
|
+
export type IDisplayMode = 'iconAndLabel' | 'iconOnly' | 'labelOnly';
|
|
71
|
+
export type ITextPasteEvent = {
|
|
72
|
+
text: string;
|
|
73
|
+
type: 'text';
|
|
74
|
+
};
|
|
75
|
+
export type IImagePasteEvent = {
|
|
76
|
+
type: 'image';
|
|
77
|
+
} & IClipboardImage;
|
|
78
|
+
export type IPasteEventPayload = ITextPasteEvent | IImagePasteEvent;
|
package/build-ngc/core/types.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
// Ported from expo-clipboard's own Clipboard.types.ts. ContentType and StringFormat are enums —
|
|
2
2
|
// kept unprefixed, matching this repo's convention for enums (see AuthenticationType /
|
|
3
3
|
// SecurityLevel in @symbiote-native/local-auth); the plain option/result shapes get this repo's
|
|
4
|
-
// `I`-prefix convention for exported types
|
|
5
|
-
// (PasteEventPayload, TextPasteEvent, ImagePasteEvent, AcceptedContentType, CornerStyleType,
|
|
6
|
-
// DisplayModeType) are intentionally not ported — that native paste-button view is out of scope
|
|
7
|
-
// for this pass (see the package README).
|
|
4
|
+
// `I`-prefix convention for exported types
|
|
8
5
|
/**
|
|
9
6
|
* Type used to define what type of data is stored in the clipboard.
|
|
10
7
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,uFAAuF;AACvF,gGAAgG;AAChG
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,uFAAuF;AACvF,gGAAgG;AAChG,2CAA2C;AAE3C;;GAEG;AACH,MAAM,CAAN,IAAY,WAQX;AARD,WAAY,WAAW;IACrB,wCAAyB,CAAA;IACzB,4BAAa,CAAA;IACb,8BAAe,CAAA;IACf;;OAEG;IACH,0BAAW,CAAA;AACb,CAAC,EARW,WAAW,KAAX,WAAW,QAQtB;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,wCAAwB,CAAA;IACxB,6BAAa,CAAA;AACf,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/clipboard",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "expo-clipboard wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Reads and writes clipboard text, URLs, and images, plus a clipboard-change listener.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -42,10 +42,7 @@
|
|
|
42
42
|
"types": "./build/react/index.d.ts",
|
|
43
43
|
"default": "./build/react/index.js"
|
|
44
44
|
},
|
|
45
|
-
"./svelte":
|
|
46
|
-
"types": "./build/svelte/index.d.ts",
|
|
47
|
-
"default": "./build/svelte/index.js"
|
|
48
|
-
},
|
|
45
|
+
"./svelte": "./src/svelte/index.ts",
|
|
49
46
|
"./solid": {
|
|
50
47
|
"types": "./build/solid/index.d.ts",
|
|
51
48
|
"default": "./build/solid/index.js"
|
|
@@ -70,7 +67,8 @@
|
|
|
70
67
|
},
|
|
71
68
|
"dependencies": {
|
|
72
69
|
"expo-clipboard": "57.0.1",
|
|
73
|
-
"expo-modules-core": "57.0.
|
|
70
|
+
"expo-modules-core": "57.0.20",
|
|
71
|
+
"@symbiote-native/components": "3.1.4"
|
|
74
72
|
},
|
|
75
73
|
"peerDependencies": {
|
|
76
74
|
"@angular/core": ">=20",
|
|
@@ -80,12 +78,12 @@
|
|
|
80
78
|
"solid-js": ">=1.9.0",
|
|
81
79
|
"svelte": ">=5.56.0",
|
|
82
80
|
"vue": ">=3.5.0",
|
|
83
|
-
"@symbiote-native/angular": "^3.
|
|
84
|
-
"@symbiote-native/engine": "^1.
|
|
85
|
-
"@symbiote-native/react": "^3.0
|
|
86
|
-
"@symbiote-native/solid": "^3.0
|
|
87
|
-
"@symbiote-native/svelte": "^3.0
|
|
88
|
-
"@symbiote-native/vue": "^3.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/solid": "^3.1.0",
|
|
85
|
+
"@symbiote-native/svelte": "^3.1.0",
|
|
86
|
+
"@symbiote-native/vue": "^3.2.0"
|
|
89
87
|
},
|
|
90
88
|
"peerDependenciesMeta": {
|
|
91
89
|
"@symbiote-native/angular": {
|
|
@@ -133,13 +131,13 @@
|
|
|
133
131
|
"solid-js": "^1.9.14",
|
|
134
132
|
"svelte": "^5.56.0",
|
|
135
133
|
"typescript": "~6.0.0",
|
|
136
|
-
"@symbiote-native/angular": "3.
|
|
137
|
-
"@symbiote-native/engine": "1.
|
|
138
|
-
"@symbiote-native/react": "3.0
|
|
139
|
-
"@symbiote-native/solid": "3.0
|
|
140
|
-
"@symbiote-native/svelte": "3.0
|
|
141
|
-
"@symbiote-native/test-utils": "0.4.
|
|
142
|
-
"@symbiote-native/vue": "3.0
|
|
134
|
+
"@symbiote-native/angular": "3.2.0",
|
|
135
|
+
"@symbiote-native/engine": "1.5.0",
|
|
136
|
+
"@symbiote-native/react": "3.2.0",
|
|
137
|
+
"@symbiote-native/solid": "3.1.0",
|
|
138
|
+
"@symbiote-native/svelte": "3.1.0",
|
|
139
|
+
"@symbiote-native/test-utils": "0.4.6",
|
|
140
|
+
"@symbiote-native/vue": "3.2.0"
|
|
143
141
|
},
|
|
144
142
|
"scripts": {
|
|
145
143
|
"typecheck": "tsc --build",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
import { DescriptorOutlet, NativeViewBase } from '@symbiote-native/angular';
|
|
3
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
4
|
+
import { renderClipboardPasteButton } from '../../core/clipboard-paste-button';
|
|
5
|
+
import type { IClipboardPasteButtonProps } from '../../core/clipboard-paste-button';
|
|
6
|
+
|
|
7
|
+
/** Angular twin of `expo-clipboard`'s `ClipboardPasteButton` (`UIPasteControl`), iOS only */
|
|
8
|
+
@Component({
|
|
9
|
+
selector: 'ClipboardPasteButton',
|
|
10
|
+
standalone: true,
|
|
11
|
+
imports: [DescriptorOutlet],
|
|
12
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
13
|
+
template: `@if (descriptor; as node) {
|
|
14
|
+
<symbiote-descriptor-outlet [node]="node" />
|
|
15
|
+
}`,
|
|
16
|
+
})
|
|
17
|
+
export class ClipboardPasteButton extends NativeViewBase {
|
|
18
|
+
@Input({ required: true }) onPress!: IClipboardPasteButtonProps['onPress'];
|
|
19
|
+
@Input() backgroundColor?: IClipboardPasteButtonProps['backgroundColor'];
|
|
20
|
+
@Input() foregroundColor?: IClipboardPasteButtonProps['foregroundColor'];
|
|
21
|
+
@Input() cornerStyle?: IClipboardPasteButtonProps['cornerStyle'];
|
|
22
|
+
@Input() displayMode?: IClipboardPasteButtonProps['displayMode'];
|
|
23
|
+
@Input() imageOptions?: IClipboardPasteButtonProps['imageOptions'];
|
|
24
|
+
@Input()
|
|
25
|
+
acceptedContentTypes?: IClipboardPasteButtonProps['acceptedContentTypes'];
|
|
26
|
+
|
|
27
|
+
protected override readonly propNames = [
|
|
28
|
+
'onPress',
|
|
29
|
+
'backgroundColor',
|
|
30
|
+
'foregroundColor',
|
|
31
|
+
'cornerStyle',
|
|
32
|
+
'displayMode',
|
|
33
|
+
'imageOptions',
|
|
34
|
+
'acceptedContentTypes',
|
|
35
|
+
] as const satisfies readonly (keyof ClipboardPasteButton)[];
|
|
36
|
+
|
|
37
|
+
protected override renderView(props: object): IDescriptor | null {
|
|
38
|
+
return renderClipboardPasteButton(props);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Platform, requireNativeViewManager } from 'expo-modules-core';
|
|
2
|
+
import { el } from '@symbiote-native/components';
|
|
3
|
+
import type {
|
|
4
|
+
IAccessibilityProps,
|
|
5
|
+
IAriaProps,
|
|
6
|
+
IDescriptor,
|
|
7
|
+
IResponderProps,
|
|
8
|
+
} from '@symbiote-native/components';
|
|
9
|
+
import {
|
|
10
|
+
expoViewManagerName,
|
|
11
|
+
tryRegisterNativeView,
|
|
12
|
+
} from '@symbiote-native/engine';
|
|
13
|
+
import type {
|
|
14
|
+
IStyleProp,
|
|
15
|
+
ISymbioteEvent,
|
|
16
|
+
IViewStyle,
|
|
17
|
+
} from '@symbiote-native/engine';
|
|
18
|
+
import type {
|
|
19
|
+
IAcceptedContentType,
|
|
20
|
+
IClipboardImage,
|
|
21
|
+
ICornerStyle,
|
|
22
|
+
IDisplayMode,
|
|
23
|
+
IGetImageOptions,
|
|
24
|
+
IPasteEventPayload,
|
|
25
|
+
} from './types';
|
|
26
|
+
|
|
27
|
+
export const CLIPBOARD_PASTE_BUTTON_MODULE_NAME = 'ExpoClipboard';
|
|
28
|
+
|
|
29
|
+
const PASTE_EVENT_PROP = 'onPastePressed';
|
|
30
|
+
|
|
31
|
+
const PASTE_TYPE = { text: 'text', image: 'image' } as const;
|
|
32
|
+
|
|
33
|
+
// Apple restricts the control: its colors, corners and label come from the props below, not `style`
|
|
34
|
+
export type IClipboardPasteButtonProps = IAccessibilityProps &
|
|
35
|
+
IAriaProps &
|
|
36
|
+
IResponderProps & {
|
|
37
|
+
/** Called with the pasted text or image, inspect `type` to tell them apart */
|
|
38
|
+
onPress: (data: IPasteEventPayload) => void;
|
|
39
|
+
/** Leaving it out lets the color follow the system theme */
|
|
40
|
+
backgroundColor?: string | null;
|
|
41
|
+
/** @default 'white' */
|
|
42
|
+
foregroundColor?: string | null;
|
|
43
|
+
/** @default 'capsule' */
|
|
44
|
+
cornerStyle?: ICornerStyle | null;
|
|
45
|
+
/** @default 'iconAndLabel' */
|
|
46
|
+
displayMode?: IDisplayMode | null;
|
|
47
|
+
/** Needs a width and a height, or the button does not appear */
|
|
48
|
+
style?: IStyleProp<
|
|
49
|
+
Omit<IViewStyle, 'backgroundColor' | 'borderRadius' | 'color'>
|
|
50
|
+
>;
|
|
51
|
+
imageOptions?: IGetImageOptions | null;
|
|
52
|
+
/** Do not combine `plain-text` with `html`, all text would be treated as `html` */
|
|
53
|
+
acceptedContentTypes?: IAcceptedContentType[];
|
|
54
|
+
testID?: string;
|
|
55
|
+
nativeID?: string;
|
|
56
|
+
onLayout?: (event: ISymbioteEvent) => void;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export function clipboardPasteButtonViewName(): string {
|
|
60
|
+
return expoViewManagerName(CLIPBOARD_PASTE_BUTTON_MODULE_NAME);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Registers the view config in React Native's registry, which the engine derives the view's events
|
|
64
|
+
// and prop processors from. Called at render, not at import: a registration that only a barrel's
|
|
65
|
+
// load-time side effect performs is dropped by Metro's `inlineRequires` in release
|
|
66
|
+
export function ensureClipboardPasteButtonRegistered(): boolean {
|
|
67
|
+
if (!Platform.select({ ios: true, default: false })) return false;
|
|
68
|
+
return tryRegisterNativeView(() =>
|
|
69
|
+
requireNativeViewManager(CLIPBOARD_PASTE_BUTTON_MODULE_NAME),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isImageSize(value: unknown): value is IClipboardImage['size'] {
|
|
74
|
+
return (
|
|
75
|
+
typeof value === 'object' &&
|
|
76
|
+
value !== null &&
|
|
77
|
+
typeof Reflect.get(value, 'width') === 'number' &&
|
|
78
|
+
typeof Reflect.get(value, 'height') === 'number'
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Reads the native paste event, `null` when its payload has neither a text nor an image shape */
|
|
83
|
+
export function toPasteEventPayload(
|
|
84
|
+
event: ISymbioteEvent,
|
|
85
|
+
): IPasteEventPayload | null {
|
|
86
|
+
const { type, text, data, size } = event.nativeEvent;
|
|
87
|
+
if (type === PASTE_TYPE.text && typeof text === 'string')
|
|
88
|
+
return { type, text };
|
|
89
|
+
if (
|
|
90
|
+
type === PASTE_TYPE.image &&
|
|
91
|
+
typeof data === 'string' &&
|
|
92
|
+
isImageSize(size)
|
|
93
|
+
) {
|
|
94
|
+
return { type, data, size };
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// `object`, not the props type: Vue and Angular hand over an untyped attribute bag
|
|
100
|
+
export function renderClipboardPasteButton(props: object): IDescriptor | null {
|
|
101
|
+
if (!ensureClipboardPasteButtonRegistered()) return null;
|
|
102
|
+
const onPress: unknown = Reflect.get(props, 'onPress');
|
|
103
|
+
const viewProps = Object.fromEntries(
|
|
104
|
+
Object.entries(props).filter(([key]) => key !== 'onPress'),
|
|
105
|
+
);
|
|
106
|
+
return el(clipboardPasteButtonViewName(), {
|
|
107
|
+
...viewProps,
|
|
108
|
+
[PASTE_EVENT_PROP]: (event: ISymbioteEvent): void => {
|
|
109
|
+
const payload = toPasteEventPayload(event);
|
|
110
|
+
if (payload && typeof onPress === 'function') onPress(payload);
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
package/src/core/clipboard.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UnavailabilityError } from 'expo-modules-core';
|
|
1
|
+
import { Platform, UnavailabilityError } from 'expo-modules-core';
|
|
2
2
|
import type { EventSubscription } from 'expo-modules-core';
|
|
3
3
|
|
|
4
4
|
import { CLIPBOARD_CHANGED_EVENT_NAME, expoClipboard } from './native-module';
|
|
@@ -163,6 +163,12 @@ export function addClipboardListener(
|
|
|
163
163
|
return expoClipboard.addListener(CLIPBOARD_CHANGED_EVENT_NAME, listener);
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
/** Whether `ClipboardPasteButton` can render, needs iOS 16 or newer */
|
|
167
|
+
export const isPasteButtonAvailable: boolean = Platform.select({
|
|
168
|
+
ios: expoClipboard.isPasteButtonAvailable ?? false,
|
|
169
|
+
default: false,
|
|
170
|
+
});
|
|
171
|
+
|
|
166
172
|
/**
|
|
167
173
|
* Removes the listener added by `addClipboardListener`.
|
|
168
174
|
* @deprecated use `subscription.remove()` instead.
|
package/src/core/index.ts
CHANGED
|
@@ -10,7 +10,15 @@ export {
|
|
|
10
10
|
hasImageAsync,
|
|
11
11
|
addClipboardListener,
|
|
12
12
|
removeClipboardListener,
|
|
13
|
+
isPasteButtonAvailable,
|
|
13
14
|
} from './clipboard';
|
|
15
|
+
export {
|
|
16
|
+
clipboardPasteButtonViewName,
|
|
17
|
+
ensureClipboardPasteButtonRegistered,
|
|
18
|
+
renderClipboardPasteButton,
|
|
19
|
+
toPasteEventPayload,
|
|
20
|
+
type IClipboardPasteButtonProps,
|
|
21
|
+
} from './clipboard-paste-button';
|
|
14
22
|
export {
|
|
15
23
|
ContentType,
|
|
16
24
|
StringFormat,
|
|
@@ -19,5 +27,11 @@ export {
|
|
|
19
27
|
type IGetImageOptions,
|
|
20
28
|
type IClipboardImage,
|
|
21
29
|
type IClipboardEvent,
|
|
30
|
+
type IAcceptedContentType,
|
|
31
|
+
type ICornerStyle,
|
|
32
|
+
type IDisplayMode,
|
|
33
|
+
type ITextPasteEvent,
|
|
34
|
+
type IImagePasteEvent,
|
|
35
|
+
type IPasteEventPayload,
|
|
22
36
|
} from './types';
|
|
23
37
|
export type { EventSubscription } from 'expo-modules-core';
|
|
@@ -35,6 +35,8 @@ export type INativeClipboardModule = {
|
|
|
35
35
|
getImageAsync?(options: IGetImageOptions): Promise<IClipboardImage | null>;
|
|
36
36
|
setImageAsync?(base64Image: string): Promise<void>;
|
|
37
37
|
hasImageAsync?(): Promise<boolean>;
|
|
38
|
+
// iOS 16+ only, absent elsewhere
|
|
39
|
+
isPasteButtonAvailable?: boolean;
|
|
38
40
|
};
|
|
39
41
|
|
|
40
42
|
export const expoClipboard = requireNativeModule<INativeClipboardModule>(
|
package/src/core/types.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
// Ported from expo-clipboard's own Clipboard.types.ts. ContentType and StringFormat are enums —
|
|
2
2
|
// kept unprefixed, matching this repo's convention for enums (see AuthenticationType /
|
|
3
3
|
// SecurityLevel in @symbiote-native/local-auth); the plain option/result shapes get this repo's
|
|
4
|
-
// `I`-prefix convention for exported types
|
|
5
|
-
// (PasteEventPayload, TextPasteEvent, ImagePasteEvent, AcceptedContentType, CornerStyleType,
|
|
6
|
-
// DisplayModeType) are intentionally not ported — that native paste-button view is out of scope
|
|
7
|
-
// for this pass (see the package README).
|
|
4
|
+
// `I`-prefix convention for exported types
|
|
8
5
|
|
|
9
6
|
/**
|
|
10
7
|
* Type used to define what type of data is stored in the clipboard.
|
|
@@ -79,3 +76,21 @@ export type IClipboardEvent = {
|
|
|
79
76
|
*/
|
|
80
77
|
contentTypes: ContentType[];
|
|
81
78
|
};
|
|
79
|
+
|
|
80
|
+
export type IAcceptedContentType = 'plain-text' | 'image' | 'url' | 'html';
|
|
81
|
+
|
|
82
|
+
export type ICornerStyle =
|
|
83
|
+
'dynamic' | 'fixed' | 'capsule' | 'large' | 'medium' | 'small';
|
|
84
|
+
|
|
85
|
+
export type IDisplayMode = 'iconAndLabel' | 'iconOnly' | 'labelOnly';
|
|
86
|
+
|
|
87
|
+
export type ITextPasteEvent = {
|
|
88
|
+
text: string;
|
|
89
|
+
type: 'text';
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type IImagePasteEvent = {
|
|
93
|
+
type: 'image';
|
|
94
|
+
} & IClipboardImage;
|
|
95
|
+
|
|
96
|
+
export type IPasteEventPayload = ITextPasteEvent | IImagePasteEvent;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import { descriptorToReact } from '@symbiote-native/react';
|
|
3
|
+
import { renderClipboardPasteButton } from '../core/clipboard-paste-button';
|
|
4
|
+
import type { IClipboardPasteButtonProps } from '../core/clipboard-paste-button';
|
|
5
|
+
|
|
6
|
+
/** React twin of `expo-clipboard`'s `ClipboardPasteButton` (`UIPasteControl`), iOS only */
|
|
7
|
+
export function ClipboardPasteButton(
|
|
8
|
+
props: IClipboardPasteButtonProps,
|
|
9
|
+
): ReactElement | null {
|
|
10
|
+
const descriptor = renderClipboardPasteButton(props);
|
|
11
|
+
return descriptor ? descriptorToReact(descriptor) : null;
|
|
12
|
+
}
|
package/src/react/index.ts
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { descriptorToSolid } from '@symbiote-native/solid';
|
|
2
|
+
import { renderClipboardPasteButton } from '../core/clipboard-paste-button';
|
|
3
|
+
import type { IClipboardPasteButtonProps } from '../core/clipboard-paste-button';
|
|
4
|
+
|
|
5
|
+
// The platform decision is made once at mount: the descriptor bridge builds the node once and
|
|
6
|
+
// only diffs prop values afterwards, so the descriptor's shape must not change
|
|
7
|
+
export function ClipboardPasteButton(
|
|
8
|
+
props: IClipboardPasteButtonProps,
|
|
9
|
+
): ReturnType<typeof descriptorToSolid> | null {
|
|
10
|
+
const initial = renderClipboardPasteButton({ ...props });
|
|
11
|
+
if (!initial) return null;
|
|
12
|
+
return descriptorToSolid(
|
|
13
|
+
() => renderClipboardPasteButton({ ...props }) ?? initial,
|
|
14
|
+
);
|
|
15
|
+
}
|