Skip to content

Commit 97a08d5

Browse files
authored
feat: input accessory (#659)
1 parent ebca075 commit 97a08d5

File tree

29 files changed

+2317
-122
lines changed

29 files changed

+2317
-122
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
- [@nativescript/google-signin](packages/google-signin/README.md)
2323
- [@nativescript/haptics](packages/haptics/README.md)
2424
- [@nativescript/imagepicker](packages/imagepicker/README.md)
25+
- [@nativescript/input-accessory](packages/input-accessory/README.md)
2526
- [@nativescript/ios-security](packages/ios-security/README.md)
2627
- [@nativescript/iqkeyboardmanager](packages/iqkeyboardmanager/README.md)
2728
- [@nativescript/keyboard-toolbar](packages/keyboard-toolbar/README.md)

apps/demo/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
"license": "SEE LICENSE IN <your-license-filename>",
55
"repository": "<fill-your-repository-here>",
66
"dependencies": {
7-
"@nativescript/google-maps": "file:../../packages/google-maps",
8-
"@nativescript/core": "*",
9-
"@nativescript/google-maps-utils": "file:../../packages/google-maps-utils",
7+
"@nativescript/core": "file:../../node_modules/@nativescript/core",
8+
"@nativescript/input-accessory": "file:../../packages/input-accessory",
109
"@nativescript/animated-circle": "file:../../packages/animated-circle",
1110
"@nativescript/appavailability": "file:../../packages/appavailability",
1211
"@nativescript/apple-sign-in": "file:../../packages/apple-sign-in",
@@ -25,6 +24,8 @@
2524
"@nativescript/facebook": "file:../../packages/facebook",
2625
"@nativescript/fingerprint-auth": "file:../../packages/fingerprint-auth",
2726
"@nativescript/geolocation": "file:../../packages/geolocation",
27+
"@nativescript/google-maps": "file:../../packages/google-maps",
28+
"@nativescript/google-maps-utils": "file:../../packages/google-maps-utils",
2829
"@nativescript/google-mobile-ads": "file:../../packages/google-mobile-ads",
2930
"@nativescript/google-signin": "file:../../packages/google-signin",
3031
"@nativescript/haptics": "file:../../packages/haptics",
@@ -44,8 +45,8 @@
4445
"@nativescript/zip": "file:../../packages/zip"
4546
},
4647
"devDependencies": {
47-
"@nativescript/android": "~8.9.0",
48-
"@nativescript/ios": "~8.9.0",
48+
"@nativescript/android": "~9.0.0",
49+
"@nativescript/ios": "~9.0.0",
4950
"@nativescript/tailwind": "~2.1.0",
5051
"tailwindcss": "~3.4.0"
5152
}

apps/demo/project.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
"uglify": false,
3737
"release": false,
3838
"forDevice": false,
39-
"prepare": false
39+
"prepare": false,
40+
"flags": "--env.commonjs"
4041
}
4142
}
4243
}

apps/demo/src/main-page.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<Button text="google-signin" tap="{{ viewDemo }}" class="bg-blue-500 rounded-full text-white p-4 mb-4"/>
2929
<Button text="haptics" tap="{{ viewDemo }}" class="bg-blue-500 rounded-full text-white p-4 mb-4"/>
3030
<Button text="imagepicker" tap="{{ viewDemo }}" class="bg-blue-500 rounded-full text-white p-4 mb-4"/>
31+
<Button text="input-accessory" tap="{{ viewDemo }}" class="bg-blue-500 rounded-full text-white p-4 mb-4"/>
3132
<Button text="ios-security" tap="{{ viewDemo }}" class="bg-blue-500 rounded-full text-white p-4 mb-4"/>
3233
<Button text="iqkeyboardmanager" tap="{{ viewDemo }}" class="bg-blue-500 rounded-full text-white p-4 mb-4"/>
3334
<Button text="keyboard-toolbar" tap="{{ viewDemo }}" class="bg-blue-500 rounded-full text-white p-4 mb-4"/>
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { EventData, Page, ScrollView, TextView, View } from '@nativescript/core';
2+
import { DemoSharedInputAccessory } from '@demo/shared';
3+
import { InputAccessoryManager } from '@nativescript/input-accessory';
4+
5+
export function navigatingTo(args: EventData) {
6+
const page = <Page>args.object;
7+
page.bindingContext = new DemoModel(page);
8+
}
9+
10+
export class DemoModel extends DemoSharedInputAccessory {
11+
private accessoryManager: InputAccessoryManager | null = null;
12+
private textView: TextView | null = null;
13+
private page: Page;
14+
private isAccessorySetup = false;
15+
private inputText = '';
16+
17+
constructor(page: Page) {
18+
super();
19+
this.page = page;
20+
21+
this.set('inputText', '');
22+
this.set('messages', [
23+
'Welcome to @nativescript/input-accessory 👋',
24+
'Tap in the field below to attach the input to the keyboard.',
25+
'Type and press Send to append messages while tracking keyboard transitions.',
26+
'Random thought: pineapple absolutely belongs on pizza. 🍍',
27+
'Just testing long text wrapping in this message bubble for layout stability.',
28+
'Keyboard animation looks smooth on both platforms so far.',
29+
'Reminder: drink water and stretch every hour 💧',
30+
'If this were a real chat, someone would definitely send a GIF here.',
31+
'This plugin is perfect for support chats and comment threads.',
32+
'Interactive dismiss feels super natural when dragging the list.',
33+
'Quick check-in: are we shipping this in the next release?',
34+
'Edge case test: message count should keep scrolling correctly.',
35+
'Last seeded message: ready for your own typing test 🚀',
36+
]);
37+
38+
this.page.on(Page.loadedEvent, () => {
39+
setTimeout(() => this.setupAccessory(), 100);
40+
});
41+
42+
this.page.on(Page.navigatingFromEvent, () => {
43+
this.accessoryManager?.cleanup();
44+
this.accessoryManager = null;
45+
this.isAccessorySetup = false;
46+
});
47+
}
48+
49+
onMessageInputLoaded(args: EventData) {
50+
this.textView = args.object as TextView;
51+
this.setupAccessory();
52+
}
53+
54+
onMessageTextChange() {
55+
this.inputText = this.textView?.text || '';
56+
this.accessoryManager?.updateAccessoryHeight();
57+
}
58+
59+
onMessageReturnPress() {
60+
this.sendMessage();
61+
}
62+
63+
sendMessage() {
64+
const inputText = (this.inputText || '').trim();
65+
if (!inputText) {
66+
return;
67+
}
68+
69+
this.appendMessage(`You: ${inputText}`);
70+
this.set('inputText', '');
71+
this.inputText = '';
72+
}
73+
74+
dismissKeyboard() {
75+
this.accessoryManager?.dismissKeyboard();
76+
}
77+
78+
private setupAccessory() {
79+
if (this.isAccessorySetup || !this.textView) {
80+
return;
81+
}
82+
83+
const scrollView = this.page.getViewById<ScrollView>('messagesScrollView');
84+
const inputContainer = this.page.getViewById<View>('inputContainer');
85+
86+
if (!scrollView || !inputContainer) {
87+
setTimeout(() => this.setupAccessory(), 100);
88+
return;
89+
}
90+
91+
this.accessoryManager = new InputAccessoryManager();
92+
this.accessoryManager.setup({
93+
page: this.page,
94+
scrollView,
95+
inputContainer,
96+
textView: this.textView,
97+
});
98+
99+
this.isAccessorySetup = true;
100+
this.scrollToBottom();
101+
}
102+
103+
private appendMessage(message: string) {
104+
const currentMessages = (this.get('messages') as string[]) || [];
105+
this.set('messages', [...currentMessages, message]);
106+
this.scrollToBottom();
107+
}
108+
109+
private scrollToBottom() {
110+
setTimeout(() => {
111+
this.accessoryManager?.updateAccessoryHeight();
112+
this.accessoryManager?.relayoutScrollViewContent();
113+
const scrollView = this.page.getViewById<ScrollView>('messagesScrollView');
114+
scrollView?.scrollToVerticalOffset(scrollView.scrollableHeight, true);
115+
}, 100);
116+
}
117+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
2+
<Page.actionBar>
3+
<ActionBar title="input-accessory" icon="" class="action-bar">
4+
</ActionBar>
5+
</Page.actionBar>
6+
<GridLayout rows="auto,*, auto">
7+
<StackLayout class="p-4" tap="{{ dismissKeyboard }}">
8+
<Label text="Keyboard attached input bar demo" class="h2 mb-2" textWrap="true" />
9+
<Label text="Try dragging the list while the keyboard is visible for interactive dismiss." class="mb-4 leading-[3]" textWrap="true" />
10+
</StackLayout>
11+
<GridLayout row="1" class="mx-4" iosOverflowSafeArea="false">
12+
<ScrollView id="messagesScrollView">
13+
<StackLayout tap="{{ dismissKeyboard }}" class="p-2 mb-14 bg-gray-200 rounded-b-lg">
14+
15+
<Repeater items="{{ messages }}">
16+
<Repeater.itemTemplate>
17+
<Label text="{{ $value }}" class="p-2 mb-2 text-sm leading-[3]" textWrap="true" />
18+
</Repeater.itemTemplate>
19+
</Repeater>
20+
</StackLayout>
21+
</ScrollView>
22+
23+
</GridLayout>
24+
25+
<GridLayout id="inputContainer" row="2" columns="*, auto" class="px-5 pb-2">
26+
<TextView id="messageInput" col="0" text="{{ inputText }}" hint="Type a message..." textChange="{{ onMessageTextChange }}" loaded="{{ onMessageInputLoaded }}" returnKeyType="send" class="pl-4 py-4 rounded-full bg-white/30 leading-[2]" />
27+
<Button col="1" text="Send" tap="{{ sendMessage }}" class="text-blue-500 ml-2" />
28+
</GridLayout>
29+
</GridLayout>
30+
</Page>

apps/demo/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050
"@nativescript/google-mobile-ads": ["../../packages/google-mobile-ads/index.d.ts"],
5151
"@nativescript/google-mobile-ads/angular": ["../../packages/google-mobile-ads/angular/index.ts"],
5252
"@nativescript/google-maps-utils": ["../../packages/google-maps-utils/index.d.ts"],
53-
"@nativescript/keyboard-toolbar": ["../../packages/keyboard-toolbar/index.d.ts"]
53+
"@nativescript/keyboard-toolbar": ["../../packages/keyboard-toolbar/index.d.ts"],
54+
"@nativescript/input-accessory": ["../../packages/input-accessory/index.d.ts"]
5455
}
5556
}
5657
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"@nativescript/core": "~8.9.0",
3232
"@nativescript/plugin-tools": "5.5.3",
3333
"@nativescript/tailwind": "^2.1.0",
34-
"@nativescript/types": "~8.9.0",
34+
"@nativescript/types": "~9.0.0",
3535
"@nativescript/webpack": "5.0.24",
3636
"@ngtools/webpack": "^19.0.0",
3737
"@types/geojson": "^7946.0.7",

0 commit comments

Comments
 (0)