@symbiote-native/components 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/build/accessibility-props.d.ts +64 -0
- package/build/accessibility-props.js +150 -0
- package/build/component-names/index.android.d.ts +3 -0
- package/build/component-names/index.android.js +32 -0
- package/build/component-names/index.d.ts +1 -0
- package/build/component-names/index.ios.d.ts +3 -0
- package/build/component-names/index.ios.js +26 -0
- package/build/component-names/index.js +5 -0
- package/build/component-names/shared.d.ts +7 -0
- package/build/component-names/shared.js +36 -0
- package/build/descriptor.d.ts +11 -0
- package/build/descriptor.js +17 -0
- package/build/index.d.ts +51 -0
- package/build/index.js +63 -0
- package/build/responder-props.d.ts +18 -0
- package/build/responder-props.js +9 -0
- package/build/scroll-view-commands.d.ts +23 -0
- package/build/scroll-view-commands.js +123 -0
- package/build/state/drawer-layout-android.d.ts +22 -0
- package/build/state/drawer-layout-android.js +53 -0
- package/build/state/flat-list.d.ts +12 -0
- package/build/state/flat-list.js +40 -0
- package/build/state/modal.d.ts +11 -0
- package/build/state/modal.js +28 -0
- package/build/state/pressable.d.ts +90 -0
- package/build/state/pressable.js +236 -0
- package/build/state/section-list.d.ts +46 -0
- package/build/state/section-list.js +51 -0
- package/build/state/switch.d.ts +12 -0
- package/build/state/switch.js +31 -0
- package/build/state/text-input.d.ts +103 -0
- package/build/state/text-input.js +205 -0
- package/build/state/touchable.d.ts +15 -0
- package/build/state/touchable.js +22 -0
- package/build/state/virtualized-list.d.ts +161 -0
- package/build/state/virtualized-list.js +306 -0
- package/build/view/render-activity-indicator.d.ts +25 -0
- package/build/view/render-activity-indicator.js +54 -0
- package/build/view/render-button.d.ts +19 -0
- package/build/view/render-button.js +24 -0
- package/build/view/render-drawer-layout-android.d.ts +23 -0
- package/build/view/render-drawer-layout-android.js +56 -0
- package/build/view/render-image-background.d.ts +9 -0
- package/build/view/render-image-background.js +48 -0
- package/build/view/render-image.d.ts +86 -0
- package/build/view/render-image.js +298 -0
- package/build/view/render-input-accessory-view.d.ts +9 -0
- package/build/view/render-input-accessory-view.js +18 -0
- package/build/view/render-keyboard-avoiding-view.d.ts +30 -0
- package/build/view/render-keyboard-avoiding-view.js +75 -0
- package/build/view/render-modal.d.ts +23 -0
- package/build/view/render-modal.js +70 -0
- package/build/view/render-pressable.d.ts +8 -0
- package/build/view/render-pressable.js +42 -0
- package/build/view/render-scroll-sticky.d.ts +24 -0
- package/build/view/render-scroll-sticky.js +81 -0
- package/build/view/render-scroll-view.d.ts +18 -0
- package/build/view/render-scroll-view.js +85 -0
- package/build/view/render-switch.d.ts +29 -0
- package/build/view/render-switch.js +33 -0
- package/build/view/render-text-input.d.ts +11 -0
- package/build/view/render-text-input.js +35 -0
- package/build/view/render-touchable-native-feedback.d.ts +17 -0
- package/build/view/render-touchable-native-feedback.js +39 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 A. Prokopenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @symbiote-native/components
|
|
2
|
+
|
|
3
|
+
The **framework-agnostic component layer** of [SymbioteJS](../../README.md) — pure state machines
|
|
4
|
+
and pure render functions for every visual component (`Switch`, `Modal`, `ScrollView`, the
|
|
5
|
+
`FlatList`/`SectionList` family, …), written **once** and inherited by every framework adapter
|
|
6
|
+
(`@symbiote-native/react`, `@symbiote-native/vue`, `@symbiote-native/angular`, and the ones after them). It
|
|
7
|
+
exists so that "add component X to a new adapter" means writing a thin lifecycle + descriptor
|
|
8
|
+
bridge, not re-implementing X's logic per framework.
|
|
9
|
+
|
|
10
|
+
> New to SymbioteJS? The [root README](../../README.md) has the architecture. This package is
|
|
11
|
+
> "Workstream B" — the piece that makes cross-adapter feature parity **structural** instead of a
|
|
12
|
+
> promise kept by hand.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## The split this package embodies
|
|
17
|
+
|
|
18
|
+
A component's logic splits into three layers; this package owns the first two, an adapter
|
|
19
|
+
supplies only the third:
|
|
20
|
+
|
|
21
|
+
1. **Logic — `src/state/*.ts`.** A pure reducer `(state, action) => state`, a
|
|
22
|
+
`createInitial*State` factory, and pure predicates. Zero framework, zero render —
|
|
23
|
+
`switchReducer` / `shouldSnapBack` / `valueFromChange` for `Switch`, `modalReducer` for `Modal`,
|
|
24
|
+
the `virtualized-list` windowing math for the list family.
|
|
25
|
+
2. **View — `src/view/render-*.ts`.** A pure function `render*(viewState, platform) => Descriptor`.
|
|
26
|
+
State and visuals enter **only through arguments**; out comes a tree of `Descriptor` nodes
|
|
27
|
+
(`{ type, props, children, key }`, built with `el()` / `txt()`) over the intrinsic primitives
|
|
28
|
+
(`symbiote-view`, `symbiote-switch`, …). No framework, no state, no events.
|
|
29
|
+
3. **Lifecycle — the adapter.** React wires the reducer through `useReducer`/`useLayoutEffect` and
|
|
30
|
+
bridges the `Descriptor` to `React.createElement`; Vue wires it through `ref`/`watch` and
|
|
31
|
+
bridges to `h()`. This is the ONLY part a new adapter has to write.
|
|
32
|
+
|
|
33
|
+
`Switch` is the canonical reference for a full three-layer component; `ActivityIndicator` is the
|
|
34
|
+
canonical render-only reference (no state machine needed).
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
Nearly every consumer reaches this package **through an adapter**, not directly — an app imports
|
|
41
|
+
`Switch` from `@symbiote-native/react` (or `@symbiote-native/vue`), and that adapter re-exports the prop
|
|
42
|
+
types and wires the reducer/render pair from here. Calling the render function directly is what an
|
|
43
|
+
adapter itself does, to build its lifecycle wrapper:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { renderSwitch, createInitialSwitchState, switchReducer } from '@symbiote-native/components';
|
|
47
|
+
|
|
48
|
+
// inside an adapter's own hook/composable:
|
|
49
|
+
const state = createInitialSwitchState();
|
|
50
|
+
const next = switchReducer(state, { type: 'native-reported', value: true });
|
|
51
|
+
const descriptor = renderSwitch(
|
|
52
|
+
{ value: true, disabled: false, passthrough: { onChange, ref } },
|
|
53
|
+
{ trackColorProps: (value, trackColor) => ({ /* platform-specific prop names */ }) },
|
|
54
|
+
);
|
|
55
|
+
// descriptor is then handed to the adapter's own descriptorToReact / descriptorToVue bridge
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The `passthrough` bag on each view-props type is the seam that keeps `render*` framework-agnostic:
|
|
59
|
+
an adapter folds its `ref`, event handlers, and accessibility props into it, and they land on the
|
|
60
|
+
host node untouched — the render function never names a framework type.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## What's in here
|
|
65
|
+
|
|
66
|
+
- **The `Descriptor` model** — `el()` / `txt()`, the `IDescriptor` tree every `render*` function
|
|
67
|
+
builds, and `descriptorFor` / `COMPONENT_DESCRIPTORS` (the `symbiote-*` intrinsic → Fabric
|
|
68
|
+
view-name resolution table, platform-split so the name tables can never drift between adapters).
|
|
69
|
+
- **Accessibility folding** — `resolveAccessibilityProps`, the web-alias (`aria-*`/`role`) →
|
|
70
|
+
canonical `accessibility*` transform, shared so every adapter folds identically.
|
|
71
|
+
- **Components with a full state + render split** — `Switch`, `Modal` (its reducer gates the iOS
|
|
72
|
+
keep-alive frame).
|
|
73
|
+
- **Render-only components** (no state machine) — `ActivityIndicator`, `Image`,
|
|
74
|
+
`ImageBackground`, `InputAccessoryView`.
|
|
75
|
+
- **Pure logic/plumbing without a `Descriptor`** — `Pressable`'s press state machine
|
|
76
|
+
(`createPressHandlers` / `createPressRuntime`), the `Touchable*` timing constants,
|
|
77
|
+
`Button`'s shared text-style fold, `TextInput`'s controlled-value/event-count handshake
|
|
78
|
+
(`resolveTextInputProps`, `foldText`, `eventCountFromChange`, …), `KeyboardAvoidingView`'s inset
|
|
79
|
+
math, `ScrollView`'s intrinsics/sticky-header math (no full 3-layer split — the adapter owns the
|
|
80
|
+
element assembly).
|
|
81
|
+
- **The `VirtualizedList` family's windowing engine** — `computeWindow`, `buildListPlan`,
|
|
82
|
+
viewability tracking (`computeViewableSet`, `diffViewable`), and the `FlatList`/`SectionList`
|
|
83
|
+
row/section folding helpers. Lists have no `view/render-*.ts` (a cell's content is the
|
|
84
|
+
framework's own children) — the shared layer here is pure state/logic, reused verbatim by every
|
|
85
|
+
adapter.
|
|
86
|
+
|
|
87
|
+
## What it does NOT do
|
|
88
|
+
|
|
89
|
+
- It does not touch the DOM, Fabric, or any framework's reactivity system — it depends only on
|
|
90
|
+
`@symbiote-native/engine`'s agnostic types (`IStyleProp`, `ISymbioteEvent`, accessibility types).
|
|
91
|
+
- It does not own `children`, refs, or render-callback props — a prop type with a framework
|
|
92
|
+
element in it (`IViewProps`, `IPressableProps`, `renderItem`) is declared **per adapter**, over
|
|
93
|
+
an agnostic base this package may still supply.
|
|
94
|
+
- It is not itself renderable — a `Descriptor` tree only becomes native views once an adapter's
|
|
95
|
+
`descriptorTo<Framework>` bridge turns it into a host element and the reconciler commits it
|
|
96
|
+
through `@symbiote-native/engine`.
|
|
97
|
+
|
|
98
|
+
## Related packages
|
|
99
|
+
|
|
100
|
+
- [`@symbiote-native/engine`](../engine) — the retained-tree/clone-on-write engine this package's
|
|
101
|
+
render output ultimately commits through.
|
|
102
|
+
- [`@symbiote-native/react`](../../adapters/react) / [`@symbiote-native/vue`](../../adapters/vue) /
|
|
103
|
+
[`@symbiote-native/angular`](../../adapters/angular) — the adapters that supply the lifecycle layer
|
|
104
|
+
over these state machines and render functions.
|
|
105
|
+
|
|
106
|
+
## Test it
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pnpm test # vitest, from the workspace root — reducers + render-fn snapshots, headless
|
|
110
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type ISymbioteEvent } from '@symbiote-native/engine';
|
|
2
|
+
export type IAccessibilityRole = 'none' | 'button' | 'dropdownlist' | 'togglebutton' | 'link' | 'search' | 'image' | 'keyboardkey' | 'text' | 'adjustable' | 'imagebutton' | 'header' | 'summary' | 'alert' | 'checkbox' | 'combobox' | 'menu' | 'menubar' | 'menuitem' | 'progressbar' | 'radio' | 'radiogroup' | 'scrollbar' | 'spinbutton' | 'switch' | 'tab' | 'tabbar' | 'tablist' | 'timer' | 'list' | 'toolbar' | 'grid' | 'pager' | 'scrollview' | 'horizontalscrollview' | 'viewgroup' | 'webview' | 'drawerlayout' | 'slidingdrawer' | 'iconmenu' | (string & {});
|
|
3
|
+
export type IRole = 'alert' | 'alertdialog' | 'application' | 'article' | 'banner' | 'button' | 'cell' | 'checkbox' | 'columnheader' | 'combobox' | 'complementary' | 'contentinfo' | 'definition' | 'dialog' | 'directory' | 'document' | 'feed' | 'figure' | 'form' | 'grid' | 'group' | 'heading' | 'img' | 'link' | 'list' | 'listitem' | 'log' | 'main' | 'marquee' | 'math' | 'menu' | 'menubar' | 'menuitem' | 'meter' | 'navigation' | 'none' | 'note' | 'option' | 'presentation' | 'progressbar' | 'radio' | 'radiogroup' | 'region' | 'row' | 'rowgroup' | 'rowheader' | 'scrollbar' | 'searchbox' | 'separator' | 'slider' | 'spinbutton' | 'status' | 'summary' | 'switch' | 'tab' | 'table' | 'tablist' | 'tabpanel' | 'term' | 'timer' | 'toolbar' | 'tooltip' | 'tree' | 'treegrid' | 'treeitem';
|
|
4
|
+
export interface IAccessibilityStateValue {
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
selected?: boolean;
|
|
7
|
+
checked?: boolean | 'mixed';
|
|
8
|
+
busy?: boolean;
|
|
9
|
+
expanded?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface IAccessibilityValue {
|
|
12
|
+
min?: number;
|
|
13
|
+
max?: number;
|
|
14
|
+
now?: number;
|
|
15
|
+
text?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface IAccessibilityActionInfo {
|
|
18
|
+
name: string;
|
|
19
|
+
label?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface IAccessibilityProps {
|
|
22
|
+
testID?: string;
|
|
23
|
+
nativeID?: string;
|
|
24
|
+
accessible?: boolean;
|
|
25
|
+
accessibilityLabel?: string;
|
|
26
|
+
accessibilityHint?: string;
|
|
27
|
+
accessibilityRole?: IAccessibilityRole;
|
|
28
|
+
accessibilityState?: IAccessibilityStateValue;
|
|
29
|
+
accessibilityValue?: IAccessibilityValue;
|
|
30
|
+
accessibilityActions?: ReadonlyArray<IAccessibilityActionInfo>;
|
|
31
|
+
accessibilityLabelledBy?: string | string[];
|
|
32
|
+
importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants';
|
|
33
|
+
accessibilityLiveRegion?: 'none' | 'polite' | 'assertive';
|
|
34
|
+
screenReaderFocusable?: boolean;
|
|
35
|
+
accessibilityViewIsModal?: boolean;
|
|
36
|
+
accessibilityElementsHidden?: boolean;
|
|
37
|
+
accessibilityIgnoresInvertColors?: boolean;
|
|
38
|
+
accessibilityLanguage?: string;
|
|
39
|
+
accessibilityRespondsToUserInteraction?: boolean;
|
|
40
|
+
accessibilityShowsLargeContentViewer?: boolean;
|
|
41
|
+
accessibilityLargeContentTitle?: string;
|
|
42
|
+
onAccessibilityAction?: (event: ISymbioteEvent) => void;
|
|
43
|
+
onAccessibilityTap?: (event: ISymbioteEvent) => void;
|
|
44
|
+
onMagicTap?: (event: ISymbioteEvent) => void;
|
|
45
|
+
onAccessibilityEscape?: (event: ISymbioteEvent) => void;
|
|
46
|
+
}
|
|
47
|
+
export interface IAriaProps {
|
|
48
|
+
role?: IRole;
|
|
49
|
+
'aria-label'?: string;
|
|
50
|
+
'aria-labelledby'?: string;
|
|
51
|
+
'aria-live'?: 'polite' | 'assertive' | 'off';
|
|
52
|
+
'aria-hidden'?: boolean;
|
|
53
|
+
'aria-busy'?: boolean;
|
|
54
|
+
'aria-checked'?: boolean | 'mixed';
|
|
55
|
+
'aria-disabled'?: boolean;
|
|
56
|
+
'aria-expanded'?: boolean;
|
|
57
|
+
'aria-selected'?: boolean;
|
|
58
|
+
'aria-modal'?: boolean;
|
|
59
|
+
'aria-valuemax'?: number;
|
|
60
|
+
'aria-valuemin'?: number;
|
|
61
|
+
'aria-valuenow'?: number;
|
|
62
|
+
'aria-valuetext'?: string;
|
|
63
|
+
}
|
|
64
|
+
export declare function resolveAccessibilityProps<T extends IAccessibilityProps & IAriaProps>(props: T): T;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// The accessibility prop surface shared by every user-facing component. symbiote
|
|
2
|
+
// forwards any non-function / non-style prop straight to Fabric (engine's
|
|
3
|
+
// fabricProps pass-through), so the canonical `accessibility*` props need no
|
|
4
|
+
// wiring beyond being declared here. The web-alias `aria-*` / `role` props are
|
|
5
|
+
// the exception: native reads only `accessibility*`, so they must be normalized
|
|
6
|
+
// in JS before commit; `resolveAccessibilityProps` does that, mirroring RN's
|
|
7
|
+
// own View.js transform. Types are kept in sync with RN's ViewAccessibility.js.
|
|
8
|
+
//
|
|
9
|
+
// Framework-agnostic (imports only @symbiote-native/engine), so every adapter (React,
|
|
10
|
+
// Vue, and the next) folds aria/role into accessibility* identically (ADR 0024).
|
|
11
|
+
import { dlog } from '@symbiote-native/engine';
|
|
12
|
+
// RN's web `role` → native `accessibilityRole`. Where the web role has no native
|
|
13
|
+
// counterpart it is forwarded unchanged (the AccessibilityRole union stays open),
|
|
14
|
+
// so the map only lists the values that actually differ.
|
|
15
|
+
const ROLE_TO_ACCESSIBILITY_ROLE = {
|
|
16
|
+
alert: 'alert',
|
|
17
|
+
button: 'button',
|
|
18
|
+
checkbox: 'checkbox',
|
|
19
|
+
combobox: 'combobox',
|
|
20
|
+
grid: 'grid',
|
|
21
|
+
heading: 'header',
|
|
22
|
+
img: 'image',
|
|
23
|
+
link: 'link',
|
|
24
|
+
list: 'list',
|
|
25
|
+
listitem: 'list',
|
|
26
|
+
menu: 'menu',
|
|
27
|
+
menubar: 'menubar',
|
|
28
|
+
menuitem: 'menuitem',
|
|
29
|
+
none: 'none',
|
|
30
|
+
presentation: 'none',
|
|
31
|
+
progressbar: 'progressbar',
|
|
32
|
+
radio: 'radio',
|
|
33
|
+
radiogroup: 'radiogroup',
|
|
34
|
+
scrollbar: 'scrollbar',
|
|
35
|
+
searchbox: 'search',
|
|
36
|
+
slider: 'adjustable',
|
|
37
|
+
spinbutton: 'spinbutton',
|
|
38
|
+
summary: 'summary',
|
|
39
|
+
switch: 'switch',
|
|
40
|
+
tab: 'tab',
|
|
41
|
+
tablist: 'tablist',
|
|
42
|
+
timer: 'timer',
|
|
43
|
+
toolbar: 'toolbar',
|
|
44
|
+
};
|
|
45
|
+
function accessibilityRoleFromRole(role) {
|
|
46
|
+
return ROLE_TO_ACCESSIBILITY_ROLE[role] ?? role;
|
|
47
|
+
}
|
|
48
|
+
const ARIA_KEYS = [
|
|
49
|
+
'role',
|
|
50
|
+
'aria-label',
|
|
51
|
+
'aria-labelledby',
|
|
52
|
+
'aria-live',
|
|
53
|
+
'aria-hidden',
|
|
54
|
+
'aria-busy',
|
|
55
|
+
'aria-checked',
|
|
56
|
+
'aria-disabled',
|
|
57
|
+
'aria-expanded',
|
|
58
|
+
'aria-selected',
|
|
59
|
+
'aria-modal',
|
|
60
|
+
'aria-valuemax',
|
|
61
|
+
'aria-valuemin',
|
|
62
|
+
'aria-valuenow',
|
|
63
|
+
'aria-valuetext',
|
|
64
|
+
];
|
|
65
|
+
function hasAnyAriaKey(props) {
|
|
66
|
+
return ARIA_KEYS.some(key => props[key] !== undefined);
|
|
67
|
+
}
|
|
68
|
+
// Fold the web-alias `aria-*` / `role` props into the canonical `accessibility*`
|
|
69
|
+
// props, mirroring RN's View.js transform. Canonical props take precedence per
|
|
70
|
+
// View.js: each aria value fills in via `??` only where the canonical field is
|
|
71
|
+
// still empty. The alias keys are blanked to `undefined` in the result so they
|
|
72
|
+
// never reach native (the commit layer drops undefined props); the returned
|
|
73
|
+
// object keeps type `T`, spreadable straight into createElement. When no alias
|
|
74
|
+
// is present the input passes through untouched (cheap fast path).
|
|
75
|
+
export function resolveAccessibilityProps(props) {
|
|
76
|
+
if (!hasAnyAriaKey(props))
|
|
77
|
+
return props;
|
|
78
|
+
dlog('resolveAccessibilityProps: folding aria/role aliases into accessibility* props');
|
|
79
|
+
const { role, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-live': ariaLive, 'aria-hidden': ariaHidden, 'aria-busy': ariaBusy, 'aria-checked': ariaChecked, 'aria-disabled': ariaDisabled, 'aria-expanded': ariaExpanded, 'aria-selected': ariaSelected, 'aria-modal': ariaModal, 'aria-valuemax': ariaValueMax, 'aria-valuemin': ariaValueMin, 'aria-valuenow': ariaValueNow, 'aria-valuetext': ariaValueText, } = props;
|
|
80
|
+
const next = {
|
|
81
|
+
...props,
|
|
82
|
+
role: undefined,
|
|
83
|
+
'aria-label': undefined,
|
|
84
|
+
'aria-labelledby': undefined,
|
|
85
|
+
'aria-live': undefined,
|
|
86
|
+
'aria-hidden': undefined,
|
|
87
|
+
'aria-busy': undefined,
|
|
88
|
+
'aria-checked': undefined,
|
|
89
|
+
'aria-disabled': undefined,
|
|
90
|
+
'aria-expanded': undefined,
|
|
91
|
+
'aria-selected': undefined,
|
|
92
|
+
'aria-modal': undefined,
|
|
93
|
+
'aria-valuemax': undefined,
|
|
94
|
+
'aria-valuemin': undefined,
|
|
95
|
+
'aria-valuenow': undefined,
|
|
96
|
+
'aria-valuetext': undefined,
|
|
97
|
+
};
|
|
98
|
+
if (ariaLabelledBy !== undefined && next.accessibilityLabelledBy === undefined) {
|
|
99
|
+
next.accessibilityLabelledBy = ariaLabelledBy.split(/\s*,\s*/g);
|
|
100
|
+
}
|
|
101
|
+
if (ariaLabel !== undefined && next.accessibilityLabel === undefined) {
|
|
102
|
+
next.accessibilityLabel = ariaLabel;
|
|
103
|
+
}
|
|
104
|
+
if (ariaLive !== undefined && next.accessibilityLiveRegion === undefined) {
|
|
105
|
+
next.accessibilityLiveRegion = ariaLive === 'off' ? 'none' : ariaLive;
|
|
106
|
+
}
|
|
107
|
+
if (ariaHidden !== undefined) {
|
|
108
|
+
if (next.accessibilityElementsHidden === undefined) {
|
|
109
|
+
next.accessibilityElementsHidden = ariaHidden;
|
|
110
|
+
}
|
|
111
|
+
if (ariaHidden === true && next.importantForAccessibility === undefined) {
|
|
112
|
+
next.importantForAccessibility = 'no-hide-descendants';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (ariaModal !== undefined && next.accessibilityViewIsModal === undefined) {
|
|
116
|
+
next.accessibilityViewIsModal = ariaModal;
|
|
117
|
+
}
|
|
118
|
+
if (role !== undefined && next.accessibilityRole === undefined) {
|
|
119
|
+
next.accessibilityRole = accessibilityRoleFromRole(role);
|
|
120
|
+
}
|
|
121
|
+
const existingState = props.accessibilityState;
|
|
122
|
+
if (existingState !== undefined ||
|
|
123
|
+
ariaBusy !== undefined ||
|
|
124
|
+
ariaChecked !== undefined ||
|
|
125
|
+
ariaDisabled !== undefined ||
|
|
126
|
+
ariaExpanded !== undefined ||
|
|
127
|
+
ariaSelected !== undefined) {
|
|
128
|
+
next.accessibilityState = {
|
|
129
|
+
busy: ariaBusy ?? existingState?.busy,
|
|
130
|
+
checked: ariaChecked ?? existingState?.checked,
|
|
131
|
+
disabled: ariaDisabled ?? existingState?.disabled,
|
|
132
|
+
expanded: ariaExpanded ?? existingState?.expanded,
|
|
133
|
+
selected: ariaSelected ?? existingState?.selected,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const existingValue = props.accessibilityValue;
|
|
137
|
+
if (existingValue !== undefined ||
|
|
138
|
+
ariaValueMax !== undefined ||
|
|
139
|
+
ariaValueMin !== undefined ||
|
|
140
|
+
ariaValueNow !== undefined ||
|
|
141
|
+
ariaValueText !== undefined) {
|
|
142
|
+
next.accessibilityValue = {
|
|
143
|
+
max: ariaValueMax ?? existingValue?.max,
|
|
144
|
+
min: ariaValueMin ?? existingValue?.min,
|
|
145
|
+
now: ariaValueNow ?? existingValue?.now,
|
|
146
|
+
text: ariaValueText ?? existingValue?.text,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return next;
|
|
150
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { ISymbioteIntrinsic, IComponentDescriptor } from './shared';
|
|
2
|
+
export declare const COMPONENT_DESCRIPTORS: Readonly<Record<string, import("./shared").IComponentDescriptor>>;
|
|
3
|
+
export declare const descriptorFor: (type: string) => import("./shared").IComponentDescriptor;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Android Fabric component names. Metro picks this file on an Android host. See ADR 0020.
|
|
2
|
+
// Each name is the ViewManager's REACT_CLASS in react-native/ReactAndroid/.../views/**.
|
|
3
|
+
// device-verify-pending: source-confirmed from RN's Android ViewManagers, proven on a
|
|
4
|
+
// real host by the absence of a "Can't find ViewManager '<name>'" red box.
|
|
5
|
+
import { buildDescriptors, makeDescriptorFor } from './shared';
|
|
6
|
+
const ANDROID_NAMES = {
|
|
7
|
+
'symbiote-view': 'RCTView',
|
|
8
|
+
'symbiote-text': 'RCTText',
|
|
9
|
+
'symbiote-image': 'RCTImageView',
|
|
10
|
+
'symbiote-scroll-view': 'RCTScrollView',
|
|
11
|
+
// RN's VScrollContentViewNativeComponent is `Platform.OS === 'android' ? View : …`,
|
|
12
|
+
// so a vertical scroll's content is a plain RCTView on Android, not RCTScrollContentView.
|
|
13
|
+
'symbiote-scroll-content': 'RCTView',
|
|
14
|
+
// Horizontal scroll on Android is its own ViewManager; RCTScrollView is vertical-only and
|
|
15
|
+
// ignores `horizontal`. RN routes it to AndroidHorizontalScrollView with a dedicated content
|
|
16
|
+
// view (HScrollViewNativeComponents.js: `Platform.OS === 'android' ? AndroidHorizontal… : …`).
|
|
17
|
+
'symbiote-horizontal-scroll-view': 'AndroidHorizontalScrollView',
|
|
18
|
+
'symbiote-horizontal-scroll-content': 'AndroidHorizontalScrollContentView',
|
|
19
|
+
// Android has one text-input ViewManager for both single- and multiline.
|
|
20
|
+
'symbiote-text-input': 'AndroidTextInput',
|
|
21
|
+
'symbiote-text-input-multiline': 'AndroidTextInput',
|
|
22
|
+
'symbiote-switch': 'AndroidSwitch',
|
|
23
|
+
'symbiote-activity-indicator': 'AndroidProgressBar',
|
|
24
|
+
'symbiote-safe-area-view': 'RCTSafeAreaView',
|
|
25
|
+
'symbiote-modal': 'RCTModalHostView',
|
|
26
|
+
'symbiote-refresh-control': 'AndroidSwipeRefreshLayout',
|
|
27
|
+
// iOS-only primitive; RN ships no Android InputAccessoryView. Degrade to a plain
|
|
28
|
+
// container so an iOS-targeted usage doesn't red-box on Android.
|
|
29
|
+
'symbiote-input-accessory-view': 'RCTView',
|
|
30
|
+
};
|
|
31
|
+
export const COMPONENT_DESCRIPTORS = buildDescriptors(ANDROID_NAMES);
|
|
32
|
+
export const descriptorFor = makeDescriptorFor(COMPONENT_DESCRIPTORS);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.ios';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { ISymbioteIntrinsic, IComponentDescriptor } from './shared';
|
|
2
|
+
export declare const COMPONENT_DESCRIPTORS: Readonly<Record<string, import("./shared").IComponentDescriptor>>;
|
|
3
|
+
export declare const descriptorFor: (type: string) => import("./shared").IComponentDescriptor;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// iOS Fabric component names. Metro picks this file on an iOS host; it is also the base
|
|
2
|
+
// (component-names.ts re-exports it) for headless tsx / tsc / web fallback. See ADR 0020.
|
|
3
|
+
// Fabric names are the codegen spec's registered name (the new-arch name), not the legacy
|
|
4
|
+
// paperComponentName (RCTSwitch, …).
|
|
5
|
+
import { buildDescriptors, makeDescriptorFor } from './shared';
|
|
6
|
+
const IOS_NAMES = {
|
|
7
|
+
'symbiote-view': 'RCTView',
|
|
8
|
+
'symbiote-text': 'RCTText',
|
|
9
|
+
'symbiote-image': 'RCTImageView',
|
|
10
|
+
'symbiote-scroll-view': 'RCTScrollView',
|
|
11
|
+
'symbiote-scroll-content': 'RCTScrollContentView',
|
|
12
|
+
// iOS uses one scroll view for both axes; horizontal is RCTScrollView with the
|
|
13
|
+
// `horizontal` prop set, so these resolve identically to the vertical pair.
|
|
14
|
+
'symbiote-horizontal-scroll-view': 'RCTScrollView',
|
|
15
|
+
'symbiote-horizontal-scroll-content': 'RCTScrollContentView',
|
|
16
|
+
'symbiote-text-input': 'RCTSinglelineTextInputView',
|
|
17
|
+
'symbiote-text-input-multiline': 'RCTMultilineTextInputView',
|
|
18
|
+
'symbiote-switch': 'Switch',
|
|
19
|
+
'symbiote-activity-indicator': 'ActivityIndicatorView',
|
|
20
|
+
'symbiote-safe-area-view': 'SafeAreaView',
|
|
21
|
+
'symbiote-modal': 'ModalHostView',
|
|
22
|
+
'symbiote-refresh-control': 'PullToRefreshView',
|
|
23
|
+
'symbiote-input-accessory-view': 'RCTInputAccessoryView',
|
|
24
|
+
};
|
|
25
|
+
export const COMPONENT_DESCRIPTORS = buildDescriptors(IOS_NAMES);
|
|
26
|
+
export const descriptorFor = makeDescriptorFor(COMPONENT_DESCRIPTORS);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Base / default component-name table: re-exports the iOS table. Metro overrides this
|
|
2
|
+
// with component-names.ios.ts / component-names.android.ts on a real host; under tsx /
|
|
3
|
+
// tsc / web (no Metro) the host config resolves here. Filename is the selector, no
|
|
4
|
+
// Platform.OS read. See ADR 0020.
|
|
5
|
+
export * from './index.ios';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type ISymbioteIntrinsic = 'symbiote-view' | 'symbiote-text' | 'symbiote-image' | 'symbiote-scroll-view' | 'symbiote-scroll-content' | 'symbiote-horizontal-scroll-view' | 'symbiote-horizontal-scroll-content' | 'symbiote-text-input' | 'symbiote-text-input-multiline' | 'symbiote-switch' | 'symbiote-activity-indicator' | 'symbiote-safe-area-view' | 'symbiote-modal' | 'symbiote-refresh-control' | 'symbiote-input-accessory-view';
|
|
2
|
+
export interface IComponentDescriptor {
|
|
3
|
+
component: string;
|
|
4
|
+
isText: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function buildDescriptors(names: Readonly<Record<ISymbioteIntrinsic, string>>): Readonly<Record<string, IComponentDescriptor>>;
|
|
7
|
+
export declare function makeDescriptorFor(descriptors: Readonly<Record<string, IComponentDescriptor>>): (type: string) => IComponentDescriptor;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// The intrinsic JSX types symbiote's host config maps to Fabric components, plus the
|
|
2
|
+
// machinery to turn a platform name table into the descriptors the host config reads.
|
|
3
|
+
// Per ADR 0020 the Fabric NAME of a primitive is platform-specific (iOS 'Switch' vs
|
|
4
|
+
// Android 'AndroidSwitch'), so the name tables live in component-names.ios.ts /
|
|
5
|
+
// .android.ts and the filename selects, no Platform.OS read. The isText flag is
|
|
6
|
+
// platform-invariant, so it lives here once and both tables share it.
|
|
7
|
+
// The only text-laying intrinsic; drives the RCTText / RCTVirtualText nesting choice
|
|
8
|
+
// (a <Text> inside another <Text> becomes a virtual span). Platform-invariant, so it is
|
|
9
|
+
// not part of the per-platform name table.
|
|
10
|
+
const TEXT_INTRINSICS = new Set(['symbiote-text']);
|
|
11
|
+
// Assemble the descriptor map a platform file exports: each intrinsic's Fabric name from
|
|
12
|
+
// the platform table, paired with its invariant isText flag.
|
|
13
|
+
export function buildDescriptors(names) {
|
|
14
|
+
const descriptors = {};
|
|
15
|
+
for (const [intrinsic, component] of Object.entries(names)) {
|
|
16
|
+
descriptors[intrinsic] = { component, isText: TEXT_INTRINSICS.has(intrinsic) };
|
|
17
|
+
}
|
|
18
|
+
return descriptors;
|
|
19
|
+
}
|
|
20
|
+
// Resolve an intrinsic type to its descriptor, against the platform-selected map. The
|
|
21
|
+
// logic is identical for every adapter (and was duplicated in React's host-config and
|
|
22
|
+
// Vue's component-names), so it lives here once; each platform file binds it to its own
|
|
23
|
+
// COMPONENT_DESCRIPTORS. A `symbiote-*` miss is a typo in our own code; any other string
|
|
24
|
+
// is a raw Fabric view name from a library's codegen component and flows through untouched
|
|
25
|
+
// (the engine derives its events/processors from the view's ViewConfig, no per-library glue).
|
|
26
|
+
export function makeDescriptorFor(descriptors) {
|
|
27
|
+
return type => {
|
|
28
|
+
const descriptor = descriptors[type];
|
|
29
|
+
if (descriptor !== undefined)
|
|
30
|
+
return descriptor;
|
|
31
|
+
if (type.startsWith('symbiote-')) {
|
|
32
|
+
throw new Error(`Unknown symbiote component type: ${type}`);
|
|
33
|
+
}
|
|
34
|
+
return { component: type, isText: false };
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type IDescriptorType = string;
|
|
2
|
+
export type IDescriptorProps = Record<string, unknown>;
|
|
3
|
+
export type IDescriptorChild = IDescriptor | string;
|
|
4
|
+
export type IDescriptor = {
|
|
5
|
+
type: IDescriptorType;
|
|
6
|
+
props: IDescriptorProps;
|
|
7
|
+
children: IDescriptorChild[];
|
|
8
|
+
key?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function el(type: IDescriptorType, props?: IDescriptorProps, children?: IDescriptorChild[], key?: string): IDescriptor;
|
|
11
|
+
export declare function txt(props?: IDescriptorProps, children?: IDescriptorChild[]): IDescriptor;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// The framework-agnostic node a render function paints. A `Descriptor` is a tiny VDOM
|
|
2
|
+
// description, `{ type, props, children, key }`, that each adapter maps to its own
|
|
3
|
+
// element (`descriptorToReact` → React.createElement, `descriptorToVue` → h()). The
|
|
4
|
+
// adapter's host element then flows on through its reconciler → engine → Fabric.
|
|
5
|
+
//
|
|
6
|
+
// The wolf-tui twin is `internal/shared/src/wnode/types.ts` (`WNode` + `wbox`/`wtext`).
|
|
7
|
+
// We diverge in one way: `type` is an open host-component string, not a closed two-member
|
|
8
|
+
// union, because symbiote paints one host element PER native component
|
|
9
|
+
// (`symbiote-activity-indicator`, `symbiote-switch`, …), not just box/text.
|
|
10
|
+
// el(): a host element of any type. txt(): shorthand for the `symbiote-text` primitive.
|
|
11
|
+
// Mirror wolf-tui's `wbox` / `wtext`.
|
|
12
|
+
export function el(type, props = {}, children = [], key) {
|
|
13
|
+
return { type, props, children, key };
|
|
14
|
+
}
|
|
15
|
+
export function txt(props = {}, children = []) {
|
|
16
|
+
return { type: 'symbiote-text', props, children };
|
|
17
|
+
}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export { el, txt } from './descriptor';
|
|
2
|
+
export type { IDescriptor, IDescriptorType, IDescriptorProps, IDescriptorChild, } from './descriptor';
|
|
3
|
+
export { resolveAccessibilityProps } from './accessibility-props';
|
|
4
|
+
export type { IAccessibilityProps, IAriaProps, IAccessibilityRole, IRole, IAccessibilityStateValue, IAccessibilityValue, IAccessibilityActionInfo, } from './accessibility-props';
|
|
5
|
+
export { descriptorFor, COMPONENT_DESCRIPTORS } from './component-names';
|
|
6
|
+
export { buildDescriptors, makeDescriptorFor } from './component-names/shared';
|
|
7
|
+
export type { ISymbioteIntrinsic, IComponentDescriptor } from './component-names/shared';
|
|
8
|
+
export { renderActivityIndicator } from './view/render-activity-indicator';
|
|
9
|
+
export type { IActivityIndicatorProps, IActivityIndicatorViewProps, IActivityIndicatorPlatform, IActivityIndicatorSize, } from './view/render-activity-indicator';
|
|
10
|
+
export { renderSwitch } from './view/render-switch';
|
|
11
|
+
export type { ISwitchProps, ISwitchViewProps, ISwitchPlatform, ISwitchTrackColor, } from './view/render-switch';
|
|
12
|
+
export type { IResponderProps } from './responder-props';
|
|
13
|
+
export { switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChange, } from './state/switch';
|
|
14
|
+
export type { ISwitchState, ISwitchAction } from './state/switch';
|
|
15
|
+
export { resolveDecelerationRate, selectScrollIntrinsics, readLayoutDimension, didContentSizeChange, SCROLL_VIEW_BASE_HORIZONTAL, SCROLL_VIEW_BASE_VERTICAL, } from './view/render-scroll-view';
|
|
16
|
+
export type { IScrollIntrinsics, IContentSize } from './view/render-scroll-view';
|
|
17
|
+
export { buildScrollViewHandle, splitLayoutProps, attachStickyScroll, isSymbioteEvent, forwardScrollEvent, } from './scroll-view-commands';
|
|
18
|
+
export type { IScrollViewHandle } from './scroll-view-commands';
|
|
19
|
+
export { computeStickyInterpolation, nextStickyHeaderY, stickyDebounceMs, readLayoutNumber, STICKY_HEADER_Z_INDEX, } from './view/render-scroll-sticky';
|
|
20
|
+
export type { IStickyHeaderProps, IStickyInterpolationParams } from './view/render-scroll-sticky';
|
|
21
|
+
export type { IImageSource, IImageStatics, IImageSourceProp, IResizeMode, IImageSize, IImageCacheStatus, IImageProps, IImageViewProps, } from './view/render-image';
|
|
22
|
+
export { renderImage, imageStatics, setImageSourceResolver } from './view/render-image';
|
|
23
|
+
export { renderImageBackground } from './view/render-image-background';
|
|
24
|
+
export type { IImageBackgroundViewProps } from './view/render-image-background';
|
|
25
|
+
export { renderInputAccessoryView } from './view/render-input-accessory-view';
|
|
26
|
+
export type { IInputAccessoryViewViewProps } from './view/render-input-accessory-view';
|
|
27
|
+
export { renderModal } from './view/render-modal';
|
|
28
|
+
export type { IModalViewProps, IModalAnimationType, IModalPresentationStyle, IModalOrientation, IModalOrientationChangeEvent, } from './view/render-modal';
|
|
29
|
+
export { modalReducer, createInitialModalState, shouldRenderModal } from './state/modal';
|
|
30
|
+
export type { IModalState, IModalAction } from './state/modal';
|
|
31
|
+
export { computeInset, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from './view/render-keyboard-avoiding-view';
|
|
32
|
+
export type { IKeyboardAvoidingBehavior, IMeasuredFrame, IKeyboardFrame, IKeyboardAvoidingLayout, IResolveKeyboardAvoidingLayoutParams, } from './view/render-keyboard-avoiding-view';
|
|
33
|
+
export { createPressHandlers, createPressRuntime, normalizeRect, maxEdge, isTouchWithinRegion, readPoint, computeRegion, rippleProps, DEFAULT_DELAY_LONG_PRESS_MS, DEFAULT_PRESS_RECT_OFFSETS, } from './state/pressable';
|
|
34
|
+
export type { IPressState, IPressHandler, IPressHandlers, IPressHost, IPressRuntime, IPressMachineConfig, IFrameCallback, IRectOffset, IEdgeInsets, IResponderRegion, IPressableAndroidRippleConfig, IRippleBackground as IPressableRippleBackground, } from './state/pressable';
|
|
35
|
+
export { buildPressableListeners, resolveDisabledAccessibilityState, noteHoverNoop, } from './view/render-pressable';
|
|
36
|
+
export { computePressOutWait, DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_UNDERLAY_COLOR, DEFAULT_MIN_PRESS_DURATION_MS, } from './state/touchable';
|
|
37
|
+
export type { IPressTimingProps, ITouchableHandler } from './state/touchable';
|
|
38
|
+
export { backgroundProps, canUseNativeForeground, selectableBackground, selectableBackgroundBorderless, rippleBackground, } from './view/render-touchable-native-feedback';
|
|
39
|
+
export type { INativeFeedbackBackground, IThemeAttrBackground, IRippleBackground, } from './view/render-touchable-native-feedback';
|
|
40
|
+
export { BUTTON_ACCESSIBILITY_ROLE, buttonTextStyle, resolveButtonTextStyle, } from './view/render-button';
|
|
41
|
+
export type { IButtonProps } from './view/render-button';
|
|
42
|
+
export { resolveTextInputProps, foldText, foldAutoComplete, foldSubmitBehavior, mapAutoComplete, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from './state/text-input';
|
|
43
|
+
export type { ITextInputProps, ITextInputHandle, ITextInputSelection, ITextInputEventHandler, ITextInputFoldInput, IFoldedTextInputProps, IInputMode, IEnterKeyHint, ISubmitBehavior, } from './state/text-input';
|
|
44
|
+
export { renderTextInput } from './view/render-text-input';
|
|
45
|
+
export type { ITextInputViewProps } from './view/render-text-input';
|
|
46
|
+
export { DEFAULT_WINDOW_SIZE, DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_END_REACHED_THRESHOLD, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_VIEW_AREA_COVERAGE_PERCENT_THRESHOLD, DEFAULT_START_REACHED_THRESHOLD, FIRST_INDEX, EMPTY_OFFSET, NO_INDEX, NO_CONTENT_LENGTH_SENT, INVERTED_Y_STYLE, INVERTED_X_STYLE, readScrollOffset, readLayoutLength, buildOffsets, computeWindow, throttleWindow, visiblePercent, isCellViewable, offsetForIndex, averageMeasuredLength, highestMeasuredIndex, computeEndReached, computeStartReached, buildViewabilityPairs, computeViewableSet, diffViewable, maxMinimumViewTime, buildListPlan, } from './state/virtualized-list';
|
|
47
|
+
export type { ICellLayout, ISeparators, ISeparatorProps, IViewToken, IViewableItemsChangedInfo, IViewabilityConfig, IViewabilityConfigCallbackPair, IVirtualizedListHandle, IViewableSetParams, IListCellPlan, IListPlan, IListPlanParams, } from './state/virtualized-list';
|
|
48
|
+
export { SINGLE_COLUMN, chunkIntoRows, rowKeyExtractor, expandRowToken, expandRowViewability, lastItemOfRow, firstItemOfRow, } from './state/flat-list';
|
|
49
|
+
export type { IRow } from './state/flat-list';
|
|
50
|
+
export { flattenSections, unwrapEntryItem, sectionEntryKey, scrollLocationToFlatIndex, } from './state/section-list';
|
|
51
|
+
export type { ISection, ISectionEntry, IVirtualizedSectionListHandle } from './state/section-list';
|
package/build/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// @symbiote-native/components: the framework-agnostic component layer. Pure state machines
|
|
2
|
+
// (`state/`) and render functions (`view/`) that paint `Descriptor` trees; every adapter
|
|
3
|
+
// wires state→render with ITS lifecycle (React hooks / Vue reactivity) and maps the
|
|
4
|
+
// Descriptor onto its own element. See CLAUDE.md <components_split_logic_view_lifecycle>.
|
|
5
|
+
export { el, txt } from './descriptor';
|
|
6
|
+
// Accessibility folding: the web-alias (aria-*/role) → canonical accessibility* transform
|
|
7
|
+
// and its types. Framework-agnostic (ADR 0024), so React, Vue, and the next adapter all fold
|
|
8
|
+
// identically; moved here from @symbiote-native/react. RefreshControl/SafeAreaView/ScrollView consume it.
|
|
9
|
+
export { resolveAccessibilityProps } from './accessibility-props';
|
|
10
|
+
// Intrinsic (`symbiote-*`) → Fabric view-name resolution. Shared by every adapter so the
|
|
11
|
+
// names CANNOT drift between them (one engine, one Fabric). The name tables are
|
|
12
|
+
// Metro-split (.ios/.android, filename selects, no Platform.OS read, ADR 0020); the base
|
|
13
|
+
// re-exports iOS for headless. descriptorFor is the per-platform-bound resolver.
|
|
14
|
+
export { descriptorFor, COMPONENT_DESCRIPTORS } from './component-names';
|
|
15
|
+
export { buildDescriptors, makeDescriptorFor } from './component-names/shared';
|
|
16
|
+
export { renderActivityIndicator } from './view/render-activity-indicator';
|
|
17
|
+
export { renderSwitch } from './view/render-switch';
|
|
18
|
+
// Switch is the first STATE machine off this layer (ActivityIndicator was render-only):
|
|
19
|
+
// the reducer + the two pure predicates are the logic half, the adapter supplies the hook.
|
|
20
|
+
export { switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChange, } from './state/switch';
|
|
21
|
+
// ScrollView: pure render/command helpers (no state machine, no 3-layer split). The adapter
|
|
22
|
+
// owns the refs/effects/element assembly and the sticky-header component; these supply the
|
|
23
|
+
// platform-invariant math and plumbing every adapter shares (ADR 0024).
|
|
24
|
+
export { resolveDecelerationRate, selectScrollIntrinsics, readLayoutDimension, didContentSizeChange, SCROLL_VIEW_BASE_HORIZONTAL, SCROLL_VIEW_BASE_VERTICAL, } from './view/render-scroll-view';
|
|
25
|
+
export { buildScrollViewHandle, splitLayoutProps, attachStickyScroll, isSymbioteEvent, forwardScrollEvent, } from './scroll-view-commands';
|
|
26
|
+
export { computeStickyInterpolation, nextStickyHeaderY, stickyDebounceMs, readLayoutNumber, STICKY_HEADER_Z_INDEX, } from './view/render-scroll-sticky';
|
|
27
|
+
export { renderImage, imageStatics, setImageSourceResolver } from './view/render-image';
|
|
28
|
+
// ImageBackground: render-only composition (absolute-fill image behind, children on top).
|
|
29
|
+
export { renderImageBackground } from './view/render-image-background';
|
|
30
|
+
// InputAccessoryView: render-only host assembly (nativeID/backgroundColor).
|
|
31
|
+
export { renderInputAccessoryView } from './view/render-input-accessory-view';
|
|
32
|
+
// Modal: full 3-layer split (state machine gates the iOS keep-alive frame).
|
|
33
|
+
export { renderModal } from './view/render-modal';
|
|
34
|
+
export { modalReducer, createInitialModalState, shouldRenderModal } from './state/modal';
|
|
35
|
+
// KeyboardAvoidingView: pure inset/behavior math; the adapter owns the Keyboard subscription.
|
|
36
|
+
export { computeInset, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from './view/render-keyboard-avoiding-view';
|
|
37
|
+
// Pressable: the press state machine (logic) + render decisions. The pure lifecycle (timers,
|
|
38
|
+
// geometry, drift test, suppression flags) lives in state/pressable; the responder-listener +
|
|
39
|
+
// accessibilityState + ripple render decisions in view/render-pressable. Every adapter supplies
|
|
40
|
+
// only its reactive `pressed` cell + the View's measure handle (see the 3-layer split).
|
|
41
|
+
export { createPressHandlers, createPressRuntime, normalizeRect, maxEdge, isTouchWithinRegion, readPoint, computeRegion, rippleProps, DEFAULT_DELAY_LONG_PRESS_MS, DEFAULT_PRESS_RECT_OFFSETS, } from './state/pressable';
|
|
42
|
+
export { buildPressableListeners, resolveDisabledAccessibilityState, noteHoverNoop, } from './view/render-pressable';
|
|
43
|
+
// Touchable*: shared press-timing constants + the deactivation-floor math (the Animated feedback
|
|
44
|
+
// itself stays per-adapter), and TouchableNativeFeedback's pure static factories + background map.
|
|
45
|
+
export { computePressOutWait, DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_UNDERLAY_COLOR, DEFAULT_MIN_PRESS_DURATION_MS, } from './state/touchable';
|
|
46
|
+
export { backgroundProps, canUseNativeForeground, selectableBackground, selectableBackgroundBorderless, rippleBackground, } from './view/render-touchable-native-feedback';
|
|
47
|
+
// Button: shared base text style, role constant, and color fold (the adapter composes its own
|
|
48
|
+
// TouchableOpacity + Text).
|
|
49
|
+
export { BUTTON_ACCESSIBILITY_ROLE, buttonTextStyle, resolveButtonTextStyle, } from './view/render-button';
|
|
50
|
+
// TextInput: the controlled-value / event-count handshake. The logic half is the pure
|
|
51
|
+
// folds/maps + the controlled-write predicate (not a single reducer: count must re-render the
|
|
52
|
+
// imperative handle, lastNativeText must not); the view half picks the intrinsic and maps the
|
|
53
|
+
// resolved native props. Both shared verbatim across React and Vue; the adapter owns only the
|
|
54
|
+
// hooks/reactivity + the imperative handle.
|
|
55
|
+
export { resolveTextInputProps, foldText, foldAutoComplete, foldSubmitBehavior, mapAutoComplete, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from './state/text-input';
|
|
56
|
+
export { renderTextInput } from './view/render-text-input';
|
|
57
|
+
// VirtualizedList family: the framework-agnostic windowing engine + data shapes. Lists
|
|
58
|
+
// have NO view/render-*.ts (the cell content is the framework's own children, so there is
|
|
59
|
+
// no Descriptor render fn) — the shared layer for lists is this STATE/logic, reused
|
|
60
|
+
// verbatim by React and Vue. See core/components/.docs-note-lists.md.
|
|
61
|
+
export { DEFAULT_WINDOW_SIZE, DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_END_REACHED_THRESHOLD, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_VIEW_AREA_COVERAGE_PERCENT_THRESHOLD, DEFAULT_START_REACHED_THRESHOLD, FIRST_INDEX, EMPTY_OFFSET, NO_INDEX, NO_CONTENT_LENGTH_SENT, INVERTED_Y_STYLE, INVERTED_X_STYLE, readScrollOffset, readLayoutLength, buildOffsets, computeWindow, throttleWindow, visiblePercent, isCellViewable, offsetForIndex, averageMeasuredLength, highestMeasuredIndex, computeEndReached, computeStartReached, buildViewabilityPairs, computeViewableSet, diffViewable, maxMinimumViewTime, buildListPlan, } from './state/virtualized-list';
|
|
62
|
+
export { SINGLE_COLUMN, chunkIntoRows, rowKeyExtractor, expandRowToken, expandRowViewability, lastItemOfRow, firstItemOfRow, } from './state/flat-list';
|
|
63
|
+
export { flattenSections, unwrapEntryItem, sectionEntryKey, scrollLocationToFlatIndex, } from './state/section-list';
|