Skip to content

Commit 440f282

Browse files
authored
🤖 Merge PR DefinitelyTyped#51296 phoenix_live_view 0.15.4: support for uploaders by @pzingg
* phoenix_live_view v0.14.2 * Bump to 0.15.4, add uploaders option, UploadEntryInterface, LiveViewUploader… (#1) * Bump to 0.15.4, add uploaders, UploadEntryInterface, LiveViewUploaderMeta * Provide a URL for documentation * phoenix_live_view: added tests and lint (DefinitelyTyped#2) * updated methods, closer type signatures * lint and test * reopen PR for phoenix_live_view 0.15
1 parent 0a6c958 commit 440f282

File tree

3 files changed

+146
-52
lines changed

3 files changed

+146
-52
lines changed
+99-51
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
// Type definitions for phoenix_live_view 0.14
1+
// Type definitions for phoenix_live_view 0.15
22
// Project: https://github.com/phoenixframework/phoenix_live_view
33
// Definitions by: Peter Zingg <https://github.com/pzingg>
44
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
55

6+
// Version 0.15.4 added options and interfaces for LiveView uploads
7+
// See: https://hexdocs.pm/phoenix_live_view/uploads.html
8+
69
import { Socket, SocketConnectOption } from 'phoenix';
710

811
export interface Defaults {
@@ -32,6 +35,7 @@ export interface SocketOptions {
3235
hooks?: object;
3336
loaderTimeout?: number;
3437
params?: object;
38+
uploaders?: object;
3539
viewLogger?: ViewLogger;
3640
}
3741

@@ -42,7 +46,6 @@ export class LiveSocket {
4246
constructor(url: string, phxSocket: any, opts: SocketOptions);
4347

4448
// public
45-
4649
connect(): void;
4750
disableDebug(): void;
4851
disableLatencySim(): void;
@@ -54,67 +57,66 @@ export class LiveSocket {
5457
getLatencySim(): number | null;
5558
getSocket(): Socket;
5659
isDebugEnabled(): boolean;
57-
isPhxView(el: HTMLElement): boolean;
5860
isProfileEnabled(): boolean;
5961

6062
// private
61-
62-
// channel(topic: string, params: any): Channel;
63-
// binding(kind: any): string;
64-
// bind(events: any[], callback: BindCallback): void;
63+
// bind(events: string[], callback: BindCallback): void;
64+
// bindClick(eventName: string, bindingName: string, capture: boolean): void;
6565
// bindClicks(): void;
6666
// bindForms(): void;
67+
// binding(kind: string): string;
6768
// bindNav(): void;
6869
// bindTopLevelEvents(): void;
6970
// blurActiveElement(): void;
71+
// channel(topic: string, params: any): Channel;
7072
// commitPendingLink(linkRef: number): boolean;
71-
// debounce(el: HTMLElement, event: string, callback: any): void;
73+
// debounce(el: HTMLElement, event: Event, callback: any): void;
7274
// destroyAllViews(): void;
7375
// destroyViewByEl(el: HTMLElement): void;
7476
// dropActiveElement(view: View): void;
75-
// eventMeta(eventName: string, e: any, targetEl: HTMLElement): object;
76-
// getActiveElement(): HTMLElement;
77+
// eventMeta(eventName: string, e: Event, targetEl: HTMLElement): object;
78+
// getActiveElement(): Element;
7779
// getBindingPrefix(): string;
7880
// getHookCallbacks(hookName: string): any;
7981
// getHref(): string;
8082
// getRootById(id: string): any;
8183
// getViewByEl(el: HTMLElement): any;
8284
// hasPendingLink(): boolean;
83-
// historyPatch(href: string, linkState: any): void;
84-
// historyRedirect(href: string, linkState: any, flash: any): void;
85+
// historyPatch(href: string, linkState: string): void;
86+
// historyRedirect(href: string, linkState: string, flash: string): void;
8587
// isConnected(): boolean;
88+
// isPhxView(el: HTMLElement): boolean;
8689
// isUnloaded(): boolean;
87-
// joinRootView(el: HTMLElement, href: string, flash: any, callback: any): View;
90+
// joinRootView(el: HTMLElement, href: string, flash: string, callback: (view: View, joinCount: number) => void): View;
8891
// joinRootViews(): boolean;
8992
// log(view: View, kind: string, msgCallback: () => [any, any]): void;
9093
// on(event: string, callback: (e: Event) => void): void;
91-
// onChannel(channel: any, event: any, cb: (data: any) => void): void;
94+
// onChannel(channel: Channel, event: string, cb: (data: any) => void): void;
9295
// owner(childEl: HTMLElement, callback: (view: View) => void): void;
9396
// pushHistoryPatch(href: string, linkState: any, targetEl: HTMLElement): void;
94-
// redirect(to: string, flash: any): void;
97+
// redirect(to: string, flash: string): void;
9598
// registerNewLocation(newLocation: Location): boolean;
96-
// reloadWithJitter(view: any): void;
97-
// replaceMain(href: string, flash: any, callback?: any, linkRef?: any): void;
99+
// reloadWithJitter(view: View): void;
100+
// replaceMain(href: string, flash: string, callback?: any, linkRef?: number): void;
98101
// replaceRootHistory(): void;
99102
// restorePreviouslyActiveFocus(): void;
100-
// setActiveElement(target: HTMLElement): void;
103+
// setActiveElement(target: Element): void;
101104
// setPendingLink(href: string): number;
102105
// silenceEvents(callback: () => void): void;
103106
// time(name: string, func: () => any): any;
104107
// triggerDOM(kind: string, args: any): void;
105108
// withinOwners(childEl: HTMLElement, callback: (view: View, el: HTMLElement) => void): void;
106109
// withPageLoading(info: Event, callback: any): any;
107-
// wrapPush(push: any): any;
110+
// wrapPush(view: View, opts: any, push: () => any): any;
108111
}
109112

110113
export class Rendered {
111114
constructor(viewId: string, rendered: any);
112115

113116
// public
114-
115117
componentCIDs(diff: any): number[];
116118
componentToString(cid: number): string;
117-
expandStatics(diff: any): void;
119+
doRecursiveMerge(target: any, source: any): void;
118120
getComponent(diff: any, cid: number): any;
119121
isComponentOnlyDiff(diff: any): boolean;
120122
mergeDiff(diff: any): void;
@@ -125,7 +127,6 @@ export class Rendered {
125127
toString(onlyCids?: number[]): string;
126128

127129
// private
128-
129130
// comprehensionToBuffer(rendered: any, output: any): void;
130131
// createSpan(text: string, cid: number): HTMLSpanElement;
131132
// dynamicToBuffer(rendered: any, output: any): void;
@@ -135,7 +136,7 @@ export class Rendered {
135136
// toOutputBuffer(rendered: any, output: object): any;
136137
}
137138

138-
export interface ViewHookInterface {
139+
export interface ViewHook {
139140
el: HTMLElement;
140141
viewName: string;
141142
pushEvent(event: string, payload: object, onReply?: (reply: any, ref: number) => any): void;
@@ -153,77 +154,112 @@ export interface ViewHookInterface {
153154
}
154155

155156
export class View {
156-
constructor(el: HTMLElement, liveSocket: LiveSocket, parentView: View, href: string, o: any);
157+
constructor(el: HTMLElement, liveSocket: LiveSocket, parentView: View, href: string, flash: string);
157158

158-
ackJoin(child: any): void;
159+
// public?
160+
ackJoin(child: View): void;
159161
addHook(el: HTMLElement): void;
160-
applyJoinPatch(live_patch: any, html: any, events: Array<[string, object]>): void;
162+
applyDiff(type: string, rawDiff: any, callback: any): any;
163+
applyJoinPatch(live_patch: any, html: string, events: Array<[string, object]>): void;
161164
applyPendingUpdates(): void;
162165
attachTrueDocEl(): void;
163166
bindChannel(): void;
164167
binding(kind: string): any;
168+
cancelSubmit(formEl: HTMLElement): void;
165169
closestComponentID(targetCtx: object | null): number | null;
166170
componentID(el: HTMLElement): number | null;
167171
componentPatch(diff: any, cid: number): boolean;
168172
connectParams(): object;
169173
destroy(callback?: () => void): void;
170174
destroyAllChildren(): void;
171175
destroyDescendent(id: string): any;
172-
destroyHook(hook: ViewHookInterface): void;
173-
displayError(): void;
176+
destroyHook(hook: ViewHook): void;
174177
dispatchEvents(events: Array<[string, object]>): void;
178+
displayError(): void;
175179
dropPendingRefs(): void;
176180
expandURL(to: string): string;
177181
extractMeta(el: HTMLElement, meta: object): object;
178182
formsForRecovery(html: string): HTMLElement[];
179183
getChildById(id: string): any;
180184
getDescendentByEl(el: HTMLElement): any;
181-
getHook(el: HTMLElement): ViewHookInterface;
182-
getSession(): string;
185+
getHook(el: HTMLElement): ViewHook;
186+
getScheduledSubmit(formEl: HTMLElement): any;
187+
getSession(): any;
183188
getStatic(): string | null;
184189
hideLoader(): void;
185190
isConnected(): boolean;
186191
isDestroyed(): boolean;
187192
isJoinPending(): boolean;
188193
isLoading(): boolean;
189194
isMain(): boolean;
190-
join(callback?: (view: View, joinCount: number) => void): any;
195+
join(callback: any): void;
191196
joinChild(el: HTMLElement): any;
192197
joinNewChildren(): void;
193198
log(kind: string, msgCallback: any): void;
194199
maybePushComponentsDestroyed(destroyedCIDs: number[]): any;
195200
name(): string;
196201
onAllChildJoinsComplete(): void;
197202
onChannel(event: string, cb: (resp: any) => void): void;
198-
onClose(): void;
199-
onError(reason: any): void;
203+
onClose(reason: string): void;
204+
onError(reason: string): void;
200205
onJoin(resp: object): void;
201-
onJoinComplete(resp: object, html: any, events: Array<[string, object]>): void;
206+
onJoinComplete(resp: object, html: string, events: Array<[string, object]>): void;
202207
onJoinError(resp: object): void;
203208
onLivePatch(redir: object): void;
204209
onLiveRedirect(redir: object): void;
205210
onRedirect(redir: object): void;
206211
ownsElement(el: HTMLElement): boolean;
207212
performPatch(patch: any, pruneCids: boolean): boolean;
208213
pushEvent(type: string, el: HTMLElement, targetCtx: object | null, phxEvent: string, meta: object): void;
214+
pushFileProgress(fileEl: HTMLElement, entryRef: string, progress: number, onReply?: () => void): void;
209215
pushFormRecovery(form: HTMLElement, callback: any): void;
210-
pushFormSubmit(inputEl: HTMLElement, targetCtx: object | null, kind: string, phxEvent: string, onReply: any): void;
211-
pushHookEvent(targetCtx: object | null, event: string, payload: object): void;
212-
pushInput(inputEl: HTMLElement, targetCtx: object | null, kind: string, phxEvent: string, callback: any): void;
216+
pushFormSubmit(formEl: HTMLElement, targetCtx: object | null, phxEvent: string, onReply: any): void;
217+
pushHookEvent(targetCtx: object | null, event: string, payload: object, onReply: any): void;
218+
pushInput(inputEl: HTMLElement, targetCtx: object | null, phxEvent: string, callback: any): void;
213219
pushKey(keyElement: HTMLElement, targetCtx: object | null, kind: string, phxEvent: string, meta: object): void;
214220
pushLinkPatch(href: string, targetEl: HTMLElement, callback: any): void;
215-
pushWithReply(refGenerator: any, event: string, payload: object, onReply: any): any;
221+
pushWithReply(refGenerator: any, event: string, payload: object, onReply?: () => void): any;
216222
putRef(elements: HTMLElement[], event: string): [number, HTMLElement[]];
217223
renderContainer(diff: any, kind: string): string;
218-
setContainerClasses(...classes: any[]): void;
224+
scheduleSubmit(formEl: HTMLElement, ref: number, callback: any): boolean;
225+
setContainerClasses(...classes: string[]): void;
219226
showLoader(timeout?: number): void;
220227
submitForm(form: HTMLElement, targetCtx: object | null, phxEvent: string): void;
221228
targetComponentID(target: HTMLElement, targetCtx?: object): number | null;
222-
triggerBeforeUpdate(fromEl: HTMLElement, toEl: HTMLElement): any;
229+
triggerAwaitingSubmit(formEl: HTMLElement): void;
230+
triggerBeforeUpdateHook(fromEl: HTMLElement, toEl: HTMLElement): any;
223231
triggerReconnected(): void;
224-
triggerUpdatedHook(hook: any): void;
225-
update(diff: any, events: Array<[string, object]>): void;
226232
undoRefs(ref: number): void;
233+
update(diff: any, events: Array<[string, object]>): void;
234+
uploadFiles(formEl: HTMLElement, targetCtx: object | null, ref: number, cid: number, onComplete: any): void;
235+
withinTargets(phxTarget: string, callback: any): void;
236+
}
237+
238+
export interface LiveViewFile extends File {
239+
_phxRef?: string;
240+
}
241+
242+
export class UploadEntry {
243+
constructor(fileEl: HTMLInputElement, file: LiveViewFile, view: View);
244+
245+
fileEl: HTMLInputElement;
246+
file: LiveViewFile;
247+
view: View;
248+
meta: object | null;
249+
metadata: () => object | null;
250+
progress: (progress: number) => void;
251+
cancel: () => void;
252+
isDone: () => boolean;
253+
error: (reason: string) => void;
254+
}
255+
256+
export interface LiveViewUploaderMeta {
257+
path: string;
258+
ref: string;
259+
name: string;
260+
type: string;
261+
size: number;
262+
last_modified?: number;
227263
}
228264

229265
export function debug(view: View, kind: string, msg: object, obj: object): void;
@@ -233,43 +269,55 @@ export namespace Browser {
233269
function dropLocal(namespace: string, subkey: string): any;
234270
function fetchPage(href: string, callback: (status: number, resp?: string) => any): any;
235271
function getCookie(name: string): string;
236-
function getHashTargetEl(hash: any): HTMLElement | null;
272+
function getHashTargetEl(maybeHash: any): HTMLElement | null;
237273
function getLocal(namespace: string, subkey: string): any;
238274
function localKey(namespace: string, subkey: string): string;
239-
function pushState(kind: any, meta: any, to: string): void;
240-
function redirect(toURL: string, flash: any): void;
275+
function pushState(kind: string, meta: object, to: string): void;
276+
function redirect(toURL: string, flash: string): void;
241277
function setCookie(name: string, value: string): void;
278+
function updateCurrentState(callback: any): void;
242279
function updateLocal(namespace: string, subkey: string, initial: any, func: (current: any) => any): any;
243280
}
244281

245282
export namespace DOM {
246283
function all(node: Node, query: string, callback: (el: HTMLElement) => HTMLElement): HTMLElement[];
247284
function byId(id: string): HTMLElement | void;
248-
function cleanChildNodes(container: any, phxUpdate: any): void;
249-
function cloneNode(node: Node, html: any): Node;
285+
function childNodeLength(html: string): number;
286+
function cleanChildNodes(container: Node, phxUpdate: string): void;
287+
function cloneNode(node: Node, html: string): Node;
250288
function copyPrivates(target: HTMLElement, source: HTMLElement): void;
251289
function debounce(el: HTMLElement, event: Event, phxDebounce: string, defaultDebounce: string | null, phxThrottle: string, defaultThrottle: string | null, callback: () => any): any;
252290
function deletePrivate(el: HTMLElement, key: string): void;
253-
function discardError(container: HTMLElement, el: HTMLElement, phxFeedbackFor: string): void;
291+
function discardError(container: Node, el: HTMLElement, phxFeedbackFor: string): void;
254292
function dispatchEvent(target: Node, eventString: string, detail?: object): void;
293+
function filterWithinSameLiveView(nodes: Node[], parent: any): any;
255294
function findComponentNode(node: Node, cid: number): HTMLElement[];
256295
function findParentCIDs(node: Node, cids: number[]): Set<number>;
257296
function findPhxChildren(el: HTMLElement, parentId: string): HTMLElement[];
258297
function findPhxChildrenInFragment(html: string, parentId: string): HTMLElement[];
298+
function findUploadInputs(node: Node): void | any[];
299+
function hasSelectionRange(el: HTMLElement): boolean;
259300
function incCycle(el: HTMLElement, key: string, trigger?: any): number;
260301
function isFormInput(el: HTMLElement): boolean;
302+
function isIgnored(el: HTMLElement, phxUpdate: string): boolean;
261303
function isNowTriggerFormExternal(el: HTMLElement, phxTriggerExternal: string): boolean;
262-
function isPhxChild(el: HTMLElement): boolean;
263-
function isPhxUpdate(el: HTMLElement, phxUpdate: any, updateTypes: string[]): boolean;
304+
function isPhxChild(el: Node): boolean;
305+
function isPhxDestroyed(node: Node): boolean;
306+
function isPhxUpdate(el: Node, phxUpdate: string, updateTypes: string[]): boolean;
264307
function isTextualInput(el: HTMLElement): boolean;
308+
function isUploadInput(el: HTMLElement): boolean;
309+
function markPhxChildDestroyed(el: HTMLElement): void;
265310
function mergeAttrs(target: HTMLElement, source: HTMLElement, exclude?: string[]): void;
266311
function mergeFocusedInput(target: HTMLElement, source: HTMLElement): void;
267312
function once(el: HTMLElement, key: string): boolean;
313+
function private(el: HTMLElement, key: string): any;
268314
function putPrivate(el: HTMLElement, key: string, value: any): void;
269315
function putTitle(str: string): void;
270316
function removeClass(el: HTMLElement, className: string): void;
271317
function restoreFocus(focused: HTMLElement, selectionStart: number, selectionEnd: number): void;
318+
function showError(inputEl: HTMLElement, phxFeedbackFor: string): void;
272319
function syncAttrsToProps(el: HTMLElement): void;
273-
function syncPendingRef(ref: number | null, fromEl: HTMLElement, toEl: HTMLElement): boolean;
320+
function syncPendingRef(fromEl: HTMLElement, toEl: HTMLElement, disableWith: string): boolean;
274321
function triggerCycle(el: HTMLElement, key: string, currentCycle?: number): void;
322+
function withinSameLiveView(node: Node, parent: Node): boolean;
275323
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Socket } from "phoenix";
2+
import { LiveSocket, SocketOptions, ViewHook, UploadEntry } from "phoenix_live_view";
3+
4+
function test_socket() {
5+
// Hooks
6+
const testHook = {
7+
mounted() {
8+
const hook = this as unknown as ViewHook;
9+
console.log('TestHook mounted');
10+
hook.pushEvent('hook-mounted', { name: 'testHook' },
11+
(reply, ref) => {
12+
console.log(`Got hook-mounted reply ${JSON.stringify(reply)} ref ${ref}`);
13+
});
14+
}
15+
};
16+
17+
// Uploaders
18+
function testUploader(entries: UploadEntry[], _onViewError: any) {
19+
entries.forEach(entry => {
20+
console.log(`file: ${entry.file.name}`);
21+
console.log(`meta: ${JSON.stringify(entry.meta)}`);
22+
});
23+
}
24+
25+
const MyHooks = {
26+
test: testHook
27+
};
28+
29+
const MyUploaders = {
30+
test: testUploader
31+
};
32+
33+
const opts: SocketOptions = {
34+
params: {
35+
_csrf_token: '1234'
36+
},
37+
hooks: MyHooks,
38+
uploaders: MyUploaders
39+
};
40+
41+
const liveSocket = new LiveSocket("/live", Socket, opts);
42+
liveSocket.enableDebug();
43+
liveSocket.enableProfiling();
44+
liveSocket.connect();
45+
}

‎types/phoenix_live_view/tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"forceConsistentCasingInFileNames": true
1919
},
2020
"files": [
21-
"index.d.ts"
21+
"index.d.ts",
22+
"phoenix_live_view-tests.ts"
2223
]
2324
}

0 commit comments

Comments
 (0)