@ng-native/components 0.3.0 → 0.5.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.
@@ -1,4 +1,3 @@
1
- import 'react-native-gesture-handler';
2
1
  import { NativeGestureBase } from './native-gesture.ts';
3
2
  import * as i0 from "@angular/core";
4
3
  export { type GestureSpec, type GestureTarget } from './gesture-backend.ts';
package/dist/gestures.js CHANGED
@@ -46,15 +46,16 @@
46
46
  * cannot parse, and the rest of the package has to stay loadable in the test suite.
47
47
  */
48
48
  import { Component, Directive, ElementRef, inject } from '@angular/core';
49
- // For the side effect: evaluating the package's index is what starts its event receiver, which
50
- // is what delivers a gesture whose callbacks are ordinary functions. An app importing `Gesture`
51
- // does this too; this file does not depend on that.
52
- import 'react-native-gesture-handler';
53
49
  import { claimHost, nativePlatform, registerViewName } from '@ng-native/fabric';
54
50
  import { gestureDispatcher, } from "./gesture-dispatch.js";
55
51
  import { GESTURES } from "./gesture-backend.js";
56
52
  import { NativeGestureBase } from "./native-gesture.js";
57
53
  import * as i0 from "@angular/core";
54
+ // For the side effect: evaluating the package's index is what starts its event receiver, which
55
+ // is what delivers a gesture whose callbacks are ordinary functions. An app importing `Gesture`
56
+ // does this too; this file does not depend on that. A `require`, so the published types do not
57
+ // name a library a web app may not have installed.
58
+ require('react-native-gesture-handler');
58
59
  export {} from "./gesture-backend.js";
59
60
  /**
60
61
  * The internals, required rather than imported, and each with a literal path because Metro builds
@@ -1 +1 @@
1
- {"version":3,"file":"gestures.js","sourceRoot":"","sources":["../src/gestures.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * react-native-gesture-handler, without React: a native gesture attached to one of our nodes.\n *\n * ```ts\n * import { Gesture } from 'react-native-gesture-handler';\n * import { NativeGesture } from '@ng-native/components/gestures';\n *\n * protected readonly pan = Gesture.Pan().onUpdate((event) => {\n * 'worklet';\n * x.value = event.translationX;\n * });\n * ```\n * ```html\n * <gesture-root>\n * <view [gesture]=\"pan\" [workletStyle]=\"slide\"></view>\n * </gesture-root>\n * ```\n *\n * `GestureDetector` is a React component whose job is to hold a ref, turn it into a view tag, and\n * hand that tag to the native module. Everything under it is a plain function of that tag:\n * `attachHandlers` and `dropHandlers` import no React at runtime, so they are used here as they\n * are, and the gesture objects themselves - `Gesture.Pan()`, the compositions, the config - are\n * the library's own public API and come across untouched.\n *\n * What is written out is the part `useAnimatedGesture` does with hooks: a worklet that turns the\n * raw stream of events into the callbacks a gesture declares. Reanimated's `registerEventHandler`\n * is the same call their `WorkletEventHandler` makes, once per event name per view tag.\n *\n * A gesture whose callbacks are not worklets needs none of that: the library attaches it as a\n * JavaScript-function gesture and its own event receiver, started when the package is first\n * imported, calls them on the JavaScript thread.\n *\n * **A gesture callback must not read `this`, on either thread.** The Babel plugin rewrites one\n * into a worklet whether or not it will run on the UI thread, and a rewritten callback has no\n * `this`; `runOnJS(true)` decides where it runs, not what it may close over. Read what it needs\n * through a local, as a worklet style does.\n *\n * **The internals are reached through `src/`, and that is load-bearing.** Both libraries point\n * their `react-native` package field at their TypeScript source, and Metro prefers that field, so\n * `react-native-gesture-handler` in an app resolves to `src/index.ts`. Importing the built `lib/`\n * copy of a file instead gives a second, parallel copy of the library with its own module state:\n * handlers registered in one copy's registry, the event receiver listening in the other's, and\n * every JavaScript gesture silently doing nothing.\n *\n * Deliberately outside the barrel: everything here reaches React Native's Flow source, which Node\n * cannot parse, and the rest of the package has to stay loadable in the test suite.\n */\nimport { Component, Directive, ElementRef, inject } from '@angular/core';\n// For the side effect: evaluating the package's index is what starts its event receiver, which\n// is what delivers a gesture whose callbacks are ordinary functions. An app importing `Gesture`\n// does this too; this file does not depend on that.\nimport 'react-native-gesture-handler';\nimport { claimHost, nativePlatform, registerViewName, type HostNode } from '@ng-native/fabric';\nimport {\n gestureDispatcher,\n type GestureCallbacks,\n type GestureStateManager,\n} from './gesture-dispatch.ts';\nimport { GESTURES, type GestureBackend } from './gesture-backend.ts';\nimport { NativeGestureBase } from './native-gesture.ts';\n\nexport { type GestureSpec, type GestureTarget } from './gesture-backend.ts';\n\n/**\n * The internals, required rather than imported, and each with a literal path because Metro builds\n * its graph from those.\n *\n * Not for laziness: a static import would put these TypeScript sources into our own type-checking\n * program, where they fail against settings of ours they were never written for\n * (`verbatimModuleSyntax`, `erasableSyntaxOnly`). `require` asks Metro for the module and leaves\n * the compiler out of it, which is the same trade `@ng-native/device` makes for React Native.\n */\nconst { attachHandlers } =\n require('react-native-gesture-handler/src/handlers/gestures/GestureDetector/attachHandlers.ts') as {\n attachHandlers(config: {\n preparedGesture: object;\n gestureConfig: object;\n gesturesToAttach: readonly object[];\n viewTag: number;\n webEventHandlersRef: object;\n }): void;\n };\n\nconst { dropHandlers } =\n require('react-native-gesture-handler/src/handlers/gestures/GestureDetector/dropHandlers.ts') as {\n dropHandlers(prepared: object): void;\n };\n\nconst { maybeInitializeFabric } = require('react-native-gesture-handler/src/init.ts') as {\n maybeInitializeFabric(): void;\n};\n\nconst { GestureStateManager } =\n require('react-native-gesture-handler/src/handlers/gestures/gestureStateManager.ts') as {\n GestureStateManager: { create(handlerTag: number): GestureStateManager };\n };\n\n/**\n * The same call Reanimated's own `WorkletEventHandler` makes: one registration per event name per\n * view tag, which is all a gesture needs to reach the UI runtime. Not public either.\n */\nconst { registerEventHandler, unregisterEventHandler } =\n require('react-native-reanimated/src/core.ts') as {\n registerEventHandler(\n worklet: (event: never) => void,\n eventName: string,\n emitterReactTag: number,\n ): number;\n unregisterEventHandler(id: number): void;\n };\n\n/** The gesture object, as far as this file needs to know it. */\ninterface Attachable {\n initialize(): void;\n prepare(): void;\n toGestureArray(): { handlers: GestureCallbacks; shouldUseReanimated: boolean }[];\n}\n\nconst EVENT_NAMES = ['onGestureHandlerStateChange', 'onGestureHandlerEvent'];\n\n/**\n * A gesture's own state controller, for the touch callbacks: a worklet that accepts or rejects\n * the gesture while it is still being recognised. Wrapped in a worklet of ours because everything\n * the dispatcher closes over is serialised onto the UI runtime with it.\n */\nconst createManager = (handlerTag: number): GestureStateManager => {\n 'worklet';\n return GestureStateManager.create(handlerTag);\n};\n\nconst backend: GestureBackend = {\n attach: (target, gesture) => {\n maybeInitializeFabric();\n const config = gesture as Attachable;\n const gesturesToAttach = config.toGestureArray();\n // The library's own state object. Only `isMounted` is read back by anything of ours - the\n // microtasks `attachHandlers` queues check it, so a directive torn down in the same tick as\n // it was created does not attach a handler nobody will drop.\n const prepared = {\n attachedGestures: [],\n animatedEventHandler: null,\n animatedHandlers: null,\n shouldUseReanimated: gesturesToAttach.some((g) => g.shouldUseReanimated),\n isMounted: true,\n };\n attachHandlers({\n preparedGesture: prepared,\n gestureConfig: config,\n gesturesToAttach,\n viewTag: target.tag,\n // Web only, and there is no web here. The library reads `.current` off it on that platform.\n webEventHandlersRef: { current: {} },\n });\n\n // One dispatcher for both event names, as the library's own event handler is: a gesture's\n // state changes and its updates arrive on different names and share the same state.\n const animated = gesturesToAttach.filter((g) => g.shouldUseReanimated);\n const dispatch = gestureDispatcher(\n animated.map((g) => g.handlers),\n createManager,\n );\n const registrations = animated.length\n ? EVENT_NAMES.map((name) => registerEventHandler(dispatch, name, target.tag))\n : [];\n\n return () => {\n prepared.isMounted = false;\n for (const id of registrations) unregisterEventHandler(id);\n dropHandlers(prepared);\n };\n },\n};\n\n@Directive({\n selector: '[gesture]',\n providers: [{ provide: GESTURES, useValue: backend }],\n})\nexport class NativeGesture extends NativeGestureBase {}\n\n/**\n * The root the gestures are recognised inside. Wrap the app in one, as the library's own\n * `GestureHandlerRootView` is wrapped.\n *\n * **It is a different view on each platform, and that is the library's own split.**\n * `RNGestureHandlerRootView` is an Android view group that intercepts touches before the rest of\n * the tree sees them; on iOS the recognisers hang off the target view itself, the component\n * provider returns nil, and their own root view renders a plain `View`. Registering the native\n * name on both would render an unimplemented component on iOS.\n */\n@Component({ selector: 'gesture-root', template: '<ng-content />' })\nexport class GestureRoot {\n constructor() {\n const android = nativePlatform() === 'android';\n registerViewName('gesture-root', android ? 'RNGestureHandlerRootView' : 'RCTView', {\n flex: 1,\n });\n claimHost(inject(ElementRef).nativeElement as HostNode);\n // The library does this in its root view's render: it installs the JSI bindings the new\n // architecture needs, and it can only happen once Fabric is there to install them into.\n maybeInitializeFabric();\n }\n}\n"]}
1
+ {"version":3,"file":"gestures.js","sourceRoot":"","sources":["../src/gestures.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * react-native-gesture-handler, without React: a native gesture attached to one of our nodes.\n *\n * ```ts\n * import { Gesture } from 'react-native-gesture-handler';\n * import { NativeGesture } from '@ng-native/components/gestures';\n *\n * protected readonly pan = Gesture.Pan().onUpdate((event) => {\n * 'worklet';\n * x.value = event.translationX;\n * });\n * ```\n * ```html\n * <gesture-root>\n * <view [gesture]=\"pan\" [workletStyle]=\"slide\"></view>\n * </gesture-root>\n * ```\n *\n * `GestureDetector` is a React component whose job is to hold a ref, turn it into a view tag, and\n * hand that tag to the native module. Everything under it is a plain function of that tag:\n * `attachHandlers` and `dropHandlers` import no React at runtime, so they are used here as they\n * are, and the gesture objects themselves - `Gesture.Pan()`, the compositions, the config - are\n * the library's own public API and come across untouched.\n *\n * What is written out is the part `useAnimatedGesture` does with hooks: a worklet that turns the\n * raw stream of events into the callbacks a gesture declares. Reanimated's `registerEventHandler`\n * is the same call their `WorkletEventHandler` makes, once per event name per view tag.\n *\n * A gesture whose callbacks are not worklets needs none of that: the library attaches it as a\n * JavaScript-function gesture and its own event receiver, started when the package is first\n * imported, calls them on the JavaScript thread.\n *\n * **A gesture callback must not read `this`, on either thread.** The Babel plugin rewrites one\n * into a worklet whether or not it will run on the UI thread, and a rewritten callback has no\n * `this`; `runOnJS(true)` decides where it runs, not what it may close over. Read what it needs\n * through a local, as a worklet style does.\n *\n * **The internals are reached through `src/`, and that is load-bearing.** Both libraries point\n * their `react-native` package field at their TypeScript source, and Metro prefers that field, so\n * `react-native-gesture-handler` in an app resolves to `src/index.ts`. Importing the built `lib/`\n * copy of a file instead gives a second, parallel copy of the library with its own module state:\n * handlers registered in one copy's registry, the event receiver listening in the other's, and\n * every JavaScript gesture silently doing nothing.\n *\n * Deliberately outside the barrel: everything here reaches React Native's Flow source, which Node\n * cannot parse, and the rest of the package has to stay loadable in the test suite.\n */\nimport { Component, Directive, ElementRef, inject } from '@angular/core';\nimport { claimHost, nativePlatform, registerViewName, type HostNode } from '@ng-native/fabric';\nimport {\n gestureDispatcher,\n type GestureCallbacks,\n type GestureStateManager,\n} from './gesture-dispatch.ts';\nimport { GESTURES, type GestureBackend } from './gesture-backend.ts';\nimport { NativeGestureBase } from './native-gesture.ts';\n\n// For the side effect: evaluating the package's index is what starts its event receiver, which\n// is what delivers a gesture whose callbacks are ordinary functions. An app importing `Gesture`\n// does this too; this file does not depend on that. A `require`, so the published types do not\n// name a library a web app may not have installed.\nrequire('react-native-gesture-handler');\n\nexport { type GestureSpec, type GestureTarget } from './gesture-backend.ts';\n\n/**\n * The internals, required rather than imported, and each with a literal path because Metro builds\n * its graph from those.\n *\n * Not for laziness: a static import would put these TypeScript sources into our own type-checking\n * program, where they fail against settings of ours they were never written for\n * (`verbatimModuleSyntax`, `erasableSyntaxOnly`). `require` asks Metro for the module and leaves\n * the compiler out of it, which is the same trade `@ng-native/device` makes for React Native.\n */\nconst { attachHandlers } =\n require('react-native-gesture-handler/src/handlers/gestures/GestureDetector/attachHandlers.ts') as {\n attachHandlers(config: {\n preparedGesture: object;\n gestureConfig: object;\n gesturesToAttach: readonly object[];\n viewTag: number;\n webEventHandlersRef: object;\n }): void;\n };\n\nconst { dropHandlers } =\n require('react-native-gesture-handler/src/handlers/gestures/GestureDetector/dropHandlers.ts') as {\n dropHandlers(prepared: object): void;\n };\n\nconst { maybeInitializeFabric } = require('react-native-gesture-handler/src/init.ts') as {\n maybeInitializeFabric(): void;\n};\n\nconst { GestureStateManager } =\n require('react-native-gesture-handler/src/handlers/gestures/gestureStateManager.ts') as {\n GestureStateManager: { create(handlerTag: number): GestureStateManager };\n };\n\n/**\n * The same call Reanimated's own `WorkletEventHandler` makes: one registration per event name per\n * view tag, which is all a gesture needs to reach the UI runtime. Not public either.\n */\nconst { registerEventHandler, unregisterEventHandler } =\n require('react-native-reanimated/src/core.ts') as {\n registerEventHandler(\n worklet: (event: never) => void,\n eventName: string,\n emitterReactTag: number,\n ): number;\n unregisterEventHandler(id: number): void;\n };\n\n/** The gesture object, as far as this file needs to know it. */\ninterface Attachable {\n initialize(): void;\n prepare(): void;\n toGestureArray(): { handlers: GestureCallbacks; shouldUseReanimated: boolean }[];\n}\n\nconst EVENT_NAMES = ['onGestureHandlerStateChange', 'onGestureHandlerEvent'];\n\n/**\n * A gesture's own state controller, for the touch callbacks: a worklet that accepts or rejects\n * the gesture while it is still being recognised. Wrapped in a worklet of ours because everything\n * the dispatcher closes over is serialised onto the UI runtime with it.\n */\nconst createManager = (handlerTag: number): GestureStateManager => {\n 'worklet';\n return GestureStateManager.create(handlerTag);\n};\n\nconst backend: GestureBackend = {\n attach: (target, gesture) => {\n maybeInitializeFabric();\n const config = gesture as Attachable;\n const gesturesToAttach = config.toGestureArray();\n // The library's own state object. Only `isMounted` is read back by anything of ours - the\n // microtasks `attachHandlers` queues check it, so a directive torn down in the same tick as\n // it was created does not attach a handler nobody will drop.\n const prepared = {\n attachedGestures: [],\n animatedEventHandler: null,\n animatedHandlers: null,\n shouldUseReanimated: gesturesToAttach.some((g) => g.shouldUseReanimated),\n isMounted: true,\n };\n attachHandlers({\n preparedGesture: prepared,\n gestureConfig: config,\n gesturesToAttach,\n viewTag: target.tag,\n // Web only, and there is no web here. The library reads `.current` off it on that platform.\n webEventHandlersRef: { current: {} },\n });\n\n // One dispatcher for both event names, as the library's own event handler is: a gesture's\n // state changes and its updates arrive on different names and share the same state.\n const animated = gesturesToAttach.filter((g) => g.shouldUseReanimated);\n const dispatch = gestureDispatcher(\n animated.map((g) => g.handlers),\n createManager,\n );\n const registrations = animated.length\n ? EVENT_NAMES.map((name) => registerEventHandler(dispatch, name, target.tag))\n : [];\n\n return () => {\n prepared.isMounted = false;\n for (const id of registrations) unregisterEventHandler(id);\n dropHandlers(prepared);\n };\n },\n};\n\n@Directive({\n selector: '[gesture]',\n providers: [{ provide: GESTURES, useValue: backend }],\n})\nexport class NativeGesture extends NativeGestureBase {}\n\n/**\n * The root the gestures are recognised inside. Wrap the app in one, as the library's own\n * `GestureHandlerRootView` is wrapped.\n *\n * **It is a different view on each platform, and that is the library's own split.**\n * `RNGestureHandlerRootView` is an Android view group that intercepts touches before the rest of\n * the tree sees them; on iOS the recognisers hang off the target view itself, the component\n * provider returns nil, and their own root view renders a plain `View`. Registering the native\n * name on both would render an unimplemented component on iOS.\n */\n@Component({ selector: 'gesture-root', template: '<ng-content />' })\nexport class GestureRoot {\n constructor() {\n const android = nativePlatform() === 'android';\n registerViewName('gesture-root', android ? 'RNGestureHandlerRootView' : 'RCTView', {\n flex: 1,\n });\n claimHost(inject(ElementRef).nativeElement as HostNode);\n // The library does this in its root view's render: it installs the JSI bindings the new\n // architecture needs, and it can only happen once Fabric is there to install them into.\n maybeInitializeFabric();\n }\n}\n"]}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Text filled with a gradient, or with any background: the background is drawn through the shapes
3
+ * of the letters.
4
+ *
5
+ * ```html
6
+ * <gradient-text class="brand">Week</gradient-text>
7
+ * ```
8
+ *
9
+ * ```css
10
+ * .brand {
11
+ * background-image: linear-gradient(to bottom, #437dfc, #4ad0ef);
12
+ * background-clip: text;
13
+ * color: transparent;
14
+ * font-size: 34px;
15
+ * font-weight: 700;
16
+ * }
17
+ * ```
18
+ *
19
+ * The rule is the one a web page writes. `background-clip: text` is what this element does, so a
20
+ * rule that has it applies to `<gradient-text>` and to nothing else: on a `<text>` it would leave
21
+ * transparent letters on a block of colour. The `color` is not used, since the letters are the
22
+ * mask and are drawn in full.
23
+ *
24
+ * It is text like any other: it wraps, follows the device's text size, takes `<text>` spans
25
+ * inside it with their own weight or style, and is sized by its letters. What a span cannot have
26
+ * here is a colour of its own, because the fill is the one background behind all of it.
27
+ *
28
+ * The app must have `@react-native-masked-view/masked-view` installed, which is where the native
29
+ * view comes from (`npx expo install @react-native-masked-view/masked-view`); none of its
30
+ * JavaScript is imported. The view masks what is inside it by its first child, so the letters are
31
+ * that child and the background is painted on a view behind them.
32
+ */
33
+ import { type AfterContentChecked, type AfterViewInit } from '@angular/core';
34
+ import { ViewBase } from './view-base.ts';
35
+ import * as i0 from "@angular/core";
36
+ export declare class GradientText extends ViewBase implements AfterViewInit, AfterContentChecked {
37
+ private readonly fill;
38
+ private readonly letters;
39
+ /** The label last written from the letters, to write it again only when they change. */
40
+ private spoken;
41
+ constructor();
42
+ ngAfterViewInit(): void;
43
+ ngAfterContentChecked(): void;
44
+ /**
45
+ * Say the letters. iOS takes the mask out of the view hierarchy, so there is no text under the
46
+ * element for VoiceOver to read, and an element with nothing to say is not found at all. A
47
+ * label the app gave is left as it is.
48
+ */
49
+ private labelFromLetters;
50
+ /**
51
+ * The host's background is the fill's to paint: the view masks its children and not itself.
52
+ * Before the first commit, so the background is never drawn unmasked.
53
+ */
54
+ private paintOnFill;
55
+ static ɵfac: i0.ɵɵFactoryDeclaration<GradientText, never>;
56
+ static ɵcmp: i0.ɵɵComponentDeclaration<GradientText, "gradient-text", never, {}, {}, never, ["*"], true, never>;
57
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Text filled with a gradient, or with any background: the background is drawn through the shapes
3
+ * of the letters.
4
+ *
5
+ * ```html
6
+ * <gradient-text class="brand">Week</gradient-text>
7
+ * ```
8
+ *
9
+ * ```css
10
+ * .brand {
11
+ * background-image: linear-gradient(to bottom, #437dfc, #4ad0ef);
12
+ * background-clip: text;
13
+ * color: transparent;
14
+ * font-size: 34px;
15
+ * font-weight: 700;
16
+ * }
17
+ * ```
18
+ *
19
+ * The rule is the one a web page writes. `background-clip: text` is what this element does, so a
20
+ * rule that has it applies to `<gradient-text>` and to nothing else: on a `<text>` it would leave
21
+ * transparent letters on a block of colour. The `color` is not used, since the letters are the
22
+ * mask and are drawn in full.
23
+ *
24
+ * It is text like any other: it wraps, follows the device's text size, takes `<text>` spans
25
+ * inside it with their own weight or style, and is sized by its letters. What a span cannot have
26
+ * here is a colour of its own, because the fill is the one background behind all of it.
27
+ *
28
+ * The app must have `@react-native-masked-view/masked-view` installed, which is where the native
29
+ * view comes from (`npx expo install @react-native-masked-view/masked-view`); none of its
30
+ * JavaScript is imported. The view masks what is inside it by its first child, so the letters are
31
+ * that child and the background is painted on a view behind them.
32
+ */
33
+ import { Component, ElementRef, viewChild, } from '@angular/core';
34
+ import { registerViewName } from '@ng-native/fabric';
35
+ import { Text } from "./text.js";
36
+ import { View } from "./view.js";
37
+ import { ViewBase } from "./view-base.js";
38
+ import * as i0 from "@angular/core";
39
+ /** The characters under a node, in order. */
40
+ const textOf = (node) => node.kind === 'text' ? node.text : node.children.map(textOf).join('');
41
+ let registered = false;
42
+ /** Teach the engine the element, once, before its first commit. */
43
+ function registerGradientText() {
44
+ if (registered)
45
+ return;
46
+ registered = true;
47
+ registerViewName('gradient-text', 'RNCMaskedView');
48
+ }
49
+ export class GradientText extends ViewBase {
50
+ fill = viewChild.required('fill', { ...(ngDevMode ? { debugName: "fill" } : /* istanbul ignore next */ {}), read: ElementRef });
51
+ letters = viewChild('letters', { ...(ngDevMode ? { debugName: "letters" } : /* istanbul ignore next */ {}), read: ElementRef });
52
+ /** The label last written from the letters, to write it again only when they change. */
53
+ spoken;
54
+ constructor() {
55
+ super();
56
+ registerGradientText();
57
+ // One element to a screen reader, as a text is. An input of the same name is written after.
58
+ this.engine.setProp(this.node, 'accessible', true);
59
+ this.engine.setProp(this.node, 'accessibilityRole', 'text');
60
+ }
61
+ ngAfterViewInit() {
62
+ this.paintOnFill();
63
+ this.labelFromLetters();
64
+ }
65
+ ngAfterContentChecked() {
66
+ this.labelFromLetters();
67
+ }
68
+ /**
69
+ * Say the letters. iOS takes the mask out of the view hierarchy, so there is no text under the
70
+ * element for VoiceOver to read, and an element with nothing to say is not found at all. A
71
+ * label the app gave is left as it is.
72
+ */
73
+ labelFromLetters() {
74
+ const letters = this.letters()?.nativeElement;
75
+ const given = this.accessibilityLabel() ?? this.ariaLabel();
76
+ if (!letters || given !== undefined)
77
+ return;
78
+ const label = textOf(letters).replace(/\s+/g, ' ').trim();
79
+ if (label === this.spoken)
80
+ return;
81
+ this.spoken = label;
82
+ this.engine.setProp(this.node, 'accessibilityLabel', label || null);
83
+ }
84
+ /**
85
+ * The host's background is the fill's to paint: the view masks its children and not itself.
86
+ * Before the first commit, so the background is never drawn unmasked.
87
+ */
88
+ paintOnFill() {
89
+ const engine = this.engine;
90
+ engine.paintOn?.(this.node, this.fill().nativeElement);
91
+ }
92
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: GradientText, deps: [], target: i0.ɵɵFactoryTarget.Component });
93
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.2.0", type: GradientText, isStandalone: true, selector: "gradient-text", viewQueries: [{ propertyName: "fill", first: true, predicate: ["fill"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "letters", first: true, predicate: ["letters"], descendants: true, read: ElementRef, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
94
+ <text #letters class="letters"><ng-content /></text>
95
+ <view #fill class="fill" pointerEvents="none"></view>
96
+ `, isInline: true, styles: ["\n .letters {\n color: black;\n }\n .fill {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n "], dependencies: [{ kind: "directive", type: Text, selector: "text", inputs: ["numberOfLines", "ellipsizeMode", "selectable", "selectionColor", "allowFontScaling", "maxFontSizeMultiplier", "dynamicTypeRamp", "adjustsFontSizeToFit", "minimumFontScale", "lineBreakStrategyIOS", "textBreakStrategy", "dataDetectorType", "android_hyphenationFrequency", "pressable", "suppressHighlighting"], exportAs: ["text"] }, { kind: "directive", type: View, selector: "view" }] });
97
+ }
98
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: GradientText, decorators: [{
99
+ type: Component,
100
+ args: [{ selector: 'gradient-text', imports: [Text, View], template: `
101
+ <text #letters class="letters"><ng-content /></text>
102
+ <view #fill class="fill" pointerEvents="none"></view>
103
+ `, styles: ["\n .letters {\n color: black;\n }\n .fill {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n "] }]
104
+ }], ctorParameters: () => [], propDecorators: { fill: [{ type: i0.ViewChild, args: ['fill', { ...{ read: ElementRef }, isSignal: true }] }], letters: [{ type: i0.ViewChild, args: ['letters', { ...{ read: ElementRef }, isSignal: true }] }] } });
105
+ //# sourceMappingURL=gradient-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gradient-text.js","sourceRoot":"","sources":["../src/gradient-text.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Text filled with a gradient, or with any background: the background is drawn through the shapes\n * of the letters.\n *\n * ```html\n * <gradient-text class=\"brand\">Week</gradient-text>\n * ```\n *\n * ```css\n * .brand {\n * background-image: linear-gradient(to bottom, #437dfc, #4ad0ef);\n * background-clip: text;\n * color: transparent;\n * font-size: 34px;\n * font-weight: 700;\n * }\n * ```\n *\n * The rule is the one a web page writes. `background-clip: text` is what this element does, so a\n * rule that has it applies to `<gradient-text>` and to nothing else: on a `<text>` it would leave\n * transparent letters on a block of colour. The `color` is not used, since the letters are the\n * mask and are drawn in full.\n *\n * It is text like any other: it wraps, follows the device's text size, takes `<text>` spans\n * inside it with their own weight or style, and is sized by its letters. What a span cannot have\n * here is a colour of its own, because the fill is the one background behind all of it.\n *\n * The app must have `@react-native-masked-view/masked-view` installed, which is where the native\n * view comes from (`npx expo install @react-native-masked-view/masked-view`); none of its\n * JavaScript is imported. The view masks what is inside it by its first child, so the letters are\n * that child and the background is painted on a view behind them.\n */\nimport {\n Component,\n ElementRef,\n viewChild,\n type AfterContentChecked,\n type AfterViewInit,\n} from '@angular/core';\nimport { registerViewName, type Engine, type EngineNode } from '@ng-native/fabric';\nimport { Text } from './text.ts';\nimport { View } from './view.ts';\nimport { ViewBase } from './view-base.ts';\n\n/** The characters under a node, in order. */\nconst textOf = (node: EngineNode): string =>\n node.kind === 'text' ? node.text : node.children.map(textOf).join('');\n\nlet registered = false;\n\n/** Teach the engine the element, once, before its first commit. */\nfunction registerGradientText(): void {\n if (registered) return;\n registered = true;\n registerViewName('gradient-text', 'RNCMaskedView');\n}\n\n@Component({\n selector: 'gradient-text',\n imports: [Text, View],\n template: `\n <text #letters class=\"letters\"><ng-content /></text>\n <view #fill class=\"fill\" pointerEvents=\"none\"></view>\n `,\n styles: `\n .letters {\n color: black;\n }\n .fill {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n `,\n})\nexport class GradientText extends ViewBase implements AfterViewInit, AfterContentChecked {\n private readonly fill = viewChild.required('fill', { read: ElementRef });\n private readonly letters = viewChild('letters', { read: ElementRef });\n /** The label last written from the letters, to write it again only when they change. */\n private spoken: string | undefined;\n\n constructor() {\n super();\n registerGradientText();\n // One element to a screen reader, as a text is. An input of the same name is written after.\n this.engine.setProp(this.node, 'accessible', true);\n this.engine.setProp(this.node, 'accessibilityRole', 'text');\n }\n\n ngAfterViewInit(): void {\n this.paintOnFill();\n this.labelFromLetters();\n }\n\n ngAfterContentChecked(): void {\n this.labelFromLetters();\n }\n\n /**\n * Say the letters. iOS takes the mask out of the view hierarchy, so there is no text under the\n * element for VoiceOver to read, and an element with nothing to say is not found at all. A\n * label the app gave is left as it is.\n */\n private labelFromLetters(): void {\n const letters = this.letters()?.nativeElement as EngineNode | undefined;\n const given = this.accessibilityLabel() ?? this.ariaLabel();\n if (!letters || given !== undefined) return;\n const label = textOf(letters).replace(/\\s+/g, ' ').trim();\n if (label === this.spoken) return;\n this.spoken = label;\n this.engine.setProp(this.node, 'accessibilityLabel', label || null);\n }\n\n /**\n * The host's background is the fill's to paint: the view masks its children and not itself.\n * Before the first commit, so the background is never drawn unmasked.\n */\n private paintOnFill(): void {\n const engine = this.engine as Partial<Pick<Engine, 'paintOn'>>;\n engine.paintOn?.(this.node as EngineNode, this.fill().nativeElement as EngineNode);\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ export { Modal, type ModalOrientation, type ModalPresentationStyle } from './mod
20
20
  export { NativeRef } from './native-ref.ts';
21
21
  export { ControlBase, PressBehavior, Pressable, TouchableBase, type AndroidRipple, type PressEvent, } from './pressable.ts';
22
22
  export { RefreshControl } from './refresh-control.ts';
23
+ export { GradientText } from './gradient-text.ts';
23
24
  export { type SafeAreaEdge, type SafeAreaEdges } from './safe-area.ts';
24
25
  export { SafeAreaProvider } from './safe-area-provider.ts';
25
26
  export { SafeAreaView, type SafeAreaEdgeMode } from './safe-area-view.ts';
@@ -32,7 +33,7 @@ export { TextInput, type KeyboardType, type ReturnKeyType, type SubmitBehavior,
32
33
  export { TouchableOpacity } from './touchable-opacity.ts';
33
34
  export { optionalBoolean, optionalNumber } from './transforms.ts';
34
35
  export { View } from './view.ts';
35
- export { ViewBase, ViewBehavior, contributeAccessibility, type AccessibilityAction, type AccessibilityContribution, type AccessibilityLiveRegion, type AccessibilityRole, type AccessibilityState, type AccessibilityValue, type AndroidDrawable, type ImportantForAccessibility, type PointerEvents, } from './view-base.ts';
36
+ export { ViewBase, ViewBehavior, contributeAccessibility, type AccessibilityAction, type AccessibilityContribution, type AccessibilityLiveRegion, type AccessibilityRole, type Role, type AccessibilityState, type AccessibilityValue, type AndroidDrawable, type ImportantForAccessibility, type PointerEvents, } from './view-base.ts';
36
37
  export { VirtualList, VirtualListRow, VirtualListSeparator, type VirtualItemHeight, type VirtualListSeparatorContext, type VirtualListPadding, type VirtualListVisiblePosition, type VirtualRow, } from './virtual-list.ts';
37
38
  export { type GestureBackend, type GestureSpec, type GestureTarget } from './gesture-backend.ts';
38
39
  export { workletScroll, workletStyle, type SharedValue, type WorkletBackend, type WorkletScrollSpec, type WorkletStyleSpec, type WorkletTarget, } from './worklets.ts';
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ export { Modal } from "./modal.js";
20
20
  export { NativeRef } from "./native-ref.js";
21
21
  export { ControlBase, PressBehavior, Pressable, TouchableBase, } from "./pressable.js";
22
22
  export { RefreshControl } from "./refresh-control.js";
23
+ export { GradientText } from "./gradient-text.js";
23
24
  export {} from "./safe-area.js";
24
25
  export { SafeAreaProvider } from "./safe-area-provider.js";
25
26
  export { SafeAreaView } from "./safe-area-view.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAmD,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAwCN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,EAA+D,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAiC,MAAM,6BAA6B,CAAC;AAClG,OAAO,EAAE,KAAK,EAAsD,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,GAGd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAyC,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAyB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAkC,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,gBAAgB,GAOjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAA4C,MAAM,WAAW,CAAC;AAC3E,OAAO,EACL,SAAS,GAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,uBAAuB,GAUxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,cAAc,EACd,oBAAoB,GAMrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA6D,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,aAAa,EACb,YAAY,GAMb,MAAM,eAAe,CAAC","sourcesContent":["/**\n * The host primitives, and the platform-capability tokens they inject.\n *\n * Every element a template renders natively is a component here and must be imported by the\n * component whose template uses it, as any Angular component must. A template that uses one\n * without importing it compiles, renders a plain view, and is reported in dev builds.\n *\n * Importing this barrel evaluates decorators, so anything a Node test needs at runtime has to\n * be reached as a source file instead - see the note in `packages/integration-tests/compile.ts`.\n */\nexport { ActivityIndicator } from './activity-indicator.ts';\nexport { type AnimatedPropsHandle, type AnimationBackend } from './animation.ts';\nexport {\n type AccessibilityActionEvent,\n type AccessibilityActionPayload,\n type ContentSizeChangeEvent,\n type ImageErrorEvent,\n type ImageErrorPayload,\n type ImageLoadEvent,\n type ImageLoadPayload,\n type ImageProgressEvent,\n type ImageProgressPayload,\n type Insets,\n type KeyPressEvent,\n type KeyPressPayload,\n type LayoutEvent,\n type LayoutPayload,\n type OrientationChangeEvent,\n type OrientationChangePayload,\n type Point,\n type Rect,\n type ScrollEvent,\n type ScrollPayload,\n type SelectionChangeEvent,\n type SelectionChangePayload,\n type Size,\n type SwitchChangeEvent,\n type SwitchChangePayload,\n type TextInputChangeEvent,\n type TextInputChangePayload,\n type TextInputContentSizeEvent,\n type TextInputContentSizePayload,\n type TextInputEditingEvent,\n type TextInputFocusEvent,\n type TextInputFocusPayload,\n type TextInputScrollEvent,\n type TextInputScrollPayload,\n type TextLayoutEvent,\n type TextLayoutLine,\n type TextLayoutPayload,\n type TouchEvent,\n type TouchEventPayload,\n} from './events.ts';\nexport { Image, type ImageResizeMode, type ImageSource, type ImageURISource } from './image.ts';\nexport { ImageBackground } from './image-background.ts';\nexport { InputAccessoryView } from './input-accessory-view.ts';\nexport {\n KEYBOARD_CONTROLLER,\n KeyboardDock,\n KeyboardLift,\n provideKeyboardController,\n} from './keyboard-dock.ts';\nexport { KeyboardAvoidingView, type KeyboardAvoidingBehavior } from './keyboard-avoiding-view.ts';\nexport { Modal, type ModalOrientation, type ModalPresentationStyle } from './modal.ts';\nexport { NativeRef } from './native-ref.ts';\nexport {\n ControlBase,\n PressBehavior,\n Pressable,\n TouchableBase,\n type AndroidRipple,\n type PressEvent,\n} from './pressable.ts';\nexport { RefreshControl } from './refresh-control.ts';\nexport { type SafeAreaEdge, type SafeAreaEdges } from './safe-area.ts';\nexport { SafeAreaProvider } from './safe-area-provider.ts';\nexport { SafeAreaView, type SafeAreaEdgeMode } from './safe-area-view.ts';\nexport { type KeyboardShouldPersistTaps } from './keyboard-taps.ts';\nexport { ScrollView } from './scroll-view.ts';\nexport {\n SectionEdgeSeparator,\n SectionFooter,\n SectionHeader,\n SectionItem,\n SectionList,\n SectionSeparator,\n type SectionContext,\n type SectionEdgeSeparatorContext,\n type SectionItemContext,\n type SectionListSection,\n type SectionRow,\n type SectionSeparatorContext,\n} from './section-list.ts';\nexport { Switch } from './switch.ts';\nexport { Text, type DynamicTypeRamp, type EllipsizeMode } from './text.ts';\nexport {\n TextInput,\n type KeyboardType,\n type ReturnKeyType,\n type SubmitBehavior,\n} from './text-input.ts';\nexport { TouchableOpacity } from './touchable-opacity.ts';\nexport { optionalBoolean, optionalNumber } from './transforms.ts';\nexport { View } from './view.ts';\nexport {\n ViewBase,\n ViewBehavior,\n contributeAccessibility,\n type AccessibilityAction,\n type AccessibilityContribution,\n type AccessibilityLiveRegion,\n type AccessibilityRole,\n type AccessibilityState,\n type AccessibilityValue,\n type AndroidDrawable,\n type ImportantForAccessibility,\n type PointerEvents,\n} from './view-base.ts';\nexport {\n VirtualList,\n VirtualListRow,\n VirtualListSeparator,\n type VirtualItemHeight,\n type VirtualListSeparatorContext,\n type VirtualListPadding,\n type VirtualListVisiblePosition,\n type VirtualRow,\n} from './virtual-list.ts';\nexport { type GestureBackend, type GestureSpec, type GestureTarget } from './gesture-backend.ts';\nexport {\n workletScroll,\n workletStyle,\n type SharedValue,\n type WorkletBackend,\n type WorkletScrollSpec,\n type WorkletStyleSpec,\n type WorkletTarget,\n} from './worklets.ts';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAmD,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAwCN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,EAA+D,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAiC,MAAM,6BAA6B,CAAC;AAClG,OAAO,EAAE,KAAK,EAAsD,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,GAGd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAyC,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAyB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAkC,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,gBAAgB,GAOjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAA4C,MAAM,WAAW,CAAC;AAC3E,OAAO,EACL,SAAS,GAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,uBAAuB,GAWxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,cAAc,EACd,oBAAoB,GAMrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA6D,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,aAAa,EACb,YAAY,GAMb,MAAM,eAAe,CAAC","sourcesContent":["/**\n * The host primitives, and the platform-capability tokens they inject.\n *\n * Every element a template renders natively is a component here and must be imported by the\n * component whose template uses it, as any Angular component must. A template that uses one\n * without importing it compiles, renders a plain view, and is reported in dev builds.\n *\n * Importing this barrel evaluates decorators, so anything a Node test needs at runtime has to\n * be reached as a source file instead - see the note in `packages/integration-tests/compile.ts`.\n */\nexport { ActivityIndicator } from './activity-indicator.ts';\nexport { type AnimatedPropsHandle, type AnimationBackend } from './animation.ts';\nexport {\n type AccessibilityActionEvent,\n type AccessibilityActionPayload,\n type ContentSizeChangeEvent,\n type ImageErrorEvent,\n type ImageErrorPayload,\n type ImageLoadEvent,\n type ImageLoadPayload,\n type ImageProgressEvent,\n type ImageProgressPayload,\n type Insets,\n type KeyPressEvent,\n type KeyPressPayload,\n type LayoutEvent,\n type LayoutPayload,\n type OrientationChangeEvent,\n type OrientationChangePayload,\n type Point,\n type Rect,\n type ScrollEvent,\n type ScrollPayload,\n type SelectionChangeEvent,\n type SelectionChangePayload,\n type Size,\n type SwitchChangeEvent,\n type SwitchChangePayload,\n type TextInputChangeEvent,\n type TextInputChangePayload,\n type TextInputContentSizeEvent,\n type TextInputContentSizePayload,\n type TextInputEditingEvent,\n type TextInputFocusEvent,\n type TextInputFocusPayload,\n type TextInputScrollEvent,\n type TextInputScrollPayload,\n type TextLayoutEvent,\n type TextLayoutLine,\n type TextLayoutPayload,\n type TouchEvent,\n type TouchEventPayload,\n} from './events.ts';\nexport { Image, type ImageResizeMode, type ImageSource, type ImageURISource } from './image.ts';\nexport { ImageBackground } from './image-background.ts';\nexport { InputAccessoryView } from './input-accessory-view.ts';\nexport {\n KEYBOARD_CONTROLLER,\n KeyboardDock,\n KeyboardLift,\n provideKeyboardController,\n} from './keyboard-dock.ts';\nexport { KeyboardAvoidingView, type KeyboardAvoidingBehavior } from './keyboard-avoiding-view.ts';\nexport { Modal, type ModalOrientation, type ModalPresentationStyle } from './modal.ts';\nexport { NativeRef } from './native-ref.ts';\nexport {\n ControlBase,\n PressBehavior,\n Pressable,\n TouchableBase,\n type AndroidRipple,\n type PressEvent,\n} from './pressable.ts';\nexport { RefreshControl } from './refresh-control.ts';\nexport { GradientText } from './gradient-text.ts';\nexport { type SafeAreaEdge, type SafeAreaEdges } from './safe-area.ts';\nexport { SafeAreaProvider } from './safe-area-provider.ts';\nexport { SafeAreaView, type SafeAreaEdgeMode } from './safe-area-view.ts';\nexport { type KeyboardShouldPersistTaps } from './keyboard-taps.ts';\nexport { ScrollView } from './scroll-view.ts';\nexport {\n SectionEdgeSeparator,\n SectionFooter,\n SectionHeader,\n SectionItem,\n SectionList,\n SectionSeparator,\n type SectionContext,\n type SectionEdgeSeparatorContext,\n type SectionItemContext,\n type SectionListSection,\n type SectionRow,\n type SectionSeparatorContext,\n} from './section-list.ts';\nexport { Switch } from './switch.ts';\nexport { Text, type DynamicTypeRamp, type EllipsizeMode } from './text.ts';\nexport {\n TextInput,\n type KeyboardType,\n type ReturnKeyType,\n type SubmitBehavior,\n} from './text-input.ts';\nexport { TouchableOpacity } from './touchable-opacity.ts';\nexport { optionalBoolean, optionalNumber } from './transforms.ts';\nexport { View } from './view.ts';\nexport {\n ViewBase,\n ViewBehavior,\n contributeAccessibility,\n type AccessibilityAction,\n type AccessibilityContribution,\n type AccessibilityLiveRegion,\n type AccessibilityRole,\n type Role,\n type AccessibilityState,\n type AccessibilityValue,\n type AndroidDrawable,\n type ImportantForAccessibility,\n type PointerEvents,\n} from './view-base.ts';\nexport {\n VirtualList,\n VirtualListRow,\n VirtualListSeparator,\n type VirtualItemHeight,\n type VirtualListSeparatorContext,\n type VirtualListPadding,\n type VirtualListVisiblePosition,\n type VirtualRow,\n} from './virtual-list.ts';\nexport { type GestureBackend, type GestureSpec, type GestureTarget } from './gesture-backend.ts';\nexport {\n workletScroll,\n workletStyle,\n type SharedValue,\n type WorkletBackend,\n type WorkletScrollSpec,\n type WorkletStyleSpec,\n type WorkletTarget,\n} from './worklets.ts';\n"]}
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Press handling, built on the engine's responder system as RN's `Pressability` is.
3
+ *
4
+ * `onPress` is not a native event: RN synthesises it in JS from the touch primitives, with a
5
+ * press rectangle, delays and a long-press timer around them. This is that machine, on the same
6
+ * responder negotiation, so a button and an enclosing scroll view agree on who owns a drag.
7
+ */
8
+ import { type Signal } from '@angular/core';
1
9
  import type { Insets, TouchEvent } from './events.ts';
2
10
  import { ViewBase } from './view-base.ts';
3
11
  import * as i0 from "@angular/core";
@@ -225,8 +233,23 @@ export declare abstract class ControlBase extends TouchableBase {
225
233
  * read `pressed` without caring whether it landed on this or on a real `<pressable>`.
226
234
  */
227
235
  export declare class PressBehavior extends ControlBase {
236
+ /** The conditions the composing component gave, any of which disables the control. */
237
+ private readonly conditions;
238
+ private readonly held;
239
+ /**
240
+ * Disable the control while `condition` is true, from the component that composes this: a
241
+ * button that is loading, which its caller's `disabled` knows nothing of. Either one disables
242
+ * it, as `disabled={loading || disabled}` does on React Native's `Pressable`: presses are
243
+ * refused, a stylesheet sees `[data-disabled]`, and a screen reader is told.
244
+ *
245
+ * constructor() {
246
+ * inject(PressBehavior).disableWhile(this.loading);
247
+ * }
248
+ */
249
+ disableWhile(condition: Signal<boolean>): void;
228
250
  protected accessibleByDefault(): boolean;
229
251
  protected focusableByDefault(): boolean;
252
+ protected pressDisabled(): boolean;
230
253
  protected disabledForAccessibility(): boolean | undefined;
231
254
  static ɵfac: i0.ɵɵFactoryDeclaration<PressBehavior, never>;
232
255
  static ɵdir: i0.ɵɵDirectiveDeclaration<PressBehavior, never, never, {}, {}, never, never, true, never>;
package/dist/pressable.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * press rectangle, delays and a long-press timer around them. This is that machine, on the same
6
6
  * responder negotiation, so a button and an enclosing scroll view agree on who owns a drag.
7
7
  */
8
- import { Directive, booleanAttribute, forwardRef, input, numberAttribute, output, signal, } from '@angular/core';
8
+ import { Directive, booleanAttribute, computed, forwardRef, input, numberAttribute, output, signal, } from '@angular/core';
9
9
  import { nativePlatform } from '@ng-native/fabric';
10
10
  import { optionalBoolean } from "./transforms.js";
11
11
  import { ViewBase } from "./view-base.js";
@@ -459,7 +459,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
459
459
  */
460
460
  export class ControlBase extends TouchableBase {
461
461
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: ControlBase, deps: null, target: i0.ɵɵFactoryTarget.Directive });
462
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.2.0", type: ControlBase, isStandalone: true, host: { properties: { "accessibilityState": "accessibilityStateProp()", "attr.data-disabled": "disabled() ? '' : null", "nativeBackgroundAndroid": "rippleBackground()", "nativeForegroundAndroid": "rippleForeground()" } }, usesInheritance: true, ngImport: i0 });
462
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.2.0", type: ControlBase, isStandalone: true, host: { properties: { "accessibilityState": "accessibilityStateProp()", "attr.data-disabled": "pressDisabled() ? '' : null", "nativeBackgroundAndroid": "rippleBackground()", "nativeForegroundAndroid": "rippleForeground()" } }, usesInheritance: true, ngImport: i0 });
463
463
  }
464
464
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: ControlBase, decorators: [{
465
465
  type: Directive,
@@ -469,7 +469,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
469
469
  // the one binding that keeps the announced state in step with it.
470
470
  '[accessibilityState]': 'accessibilityStateProp()',
471
471
  // Nor is it left on the node for `:disabled` to read, so this is what a stylesheet matches.
472
- '[attr.data-disabled]': "disabled() ? '' : null",
472
+ '[attr.data-disabled]': "pressDisabled() ? '' : null",
473
473
  '[nativeBackgroundAndroid]': 'rippleBackground()',
474
474
  '[nativeForegroundAndroid]': 'rippleForeground()',
475
475
  },
@@ -488,14 +488,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
488
488
  * read `pressed` without caring whether it landed on this or on a real `<pressable>`.
489
489
  */
490
490
  export class PressBehavior extends ControlBase {
491
+ /** The conditions the composing component gave, any of which disables the control. */
492
+ conditions = signal([], /* @ts-ignore */
493
+ ...(ngDevMode ? [{ debugName: "conditions" }] : /* istanbul ignore next */ []));
494
+ held = computed(() => this.conditions().some((condition) => condition()), /* @ts-ignore */
495
+ ...(ngDevMode ? [{ debugName: "held" }] : /* istanbul ignore next */ []));
496
+ /**
497
+ * Disable the control while `condition` is true, from the component that composes this: a
498
+ * button that is loading, which its caller's `disabled` knows nothing of. Either one disables
499
+ * it, as `disabled={loading || disabled}` does on React Native's `Pressable`: presses are
500
+ * refused, a stylesheet sees `[data-disabled]`, and a screen reader is told.
501
+ *
502
+ * constructor() {
503
+ * inject(PressBehavior).disableWhile(this.loading);
504
+ * }
505
+ */
506
+ disableWhile(condition) {
507
+ this.conditions.update((conditions) => [...conditions, condition]);
508
+ }
491
509
  accessibleByDefault() {
492
510
  return true;
493
511
  }
494
512
  focusableByDefault() {
495
513
  return true;
496
514
  }
515
+ pressDisabled() {
516
+ return this.held() || super.pressDisabled();
517
+ }
497
518
  disabledForAccessibility() {
498
- return this.disabled();
519
+ return this.held() ? true : this.disabled();
499
520
  }
500
521
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: PressBehavior, deps: null, target: i0.ɵɵFactoryTarget.Directive });
501
522
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.2.0", type: PressBehavior, isStandalone: true, providers: [{ provide: TouchableBase, useExisting: forwardRef(() => PressBehavior) }], usesInheritance: true, ngImport: i0 });