phoenix_live_view 1.2.0-rc.2 → 1.2.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.
Files changed (27) hide show
  1. package/README.md +5 -5
  2. package/assets/js/phoenix_live_view/README.md +3 -0
  3. package/assets/js/phoenix_live_view/{aria.js → aria.ts} +18 -10
  4. package/assets/js/phoenix_live_view/{browser.js → browser.ts} +12 -8
  5. package/assets/js/phoenix_live_view/{dom.js → dom.ts} +107 -34
  6. package/assets/js/phoenix_live_view/{dom_patch.js → dom_patch.ts} +187 -124
  7. package/assets/js/phoenix_live_view/{dom_post_morph_restorer.js → dom_post_morph_restorer.ts} +17 -2
  8. package/assets/js/phoenix_live_view/{element_ref.js → element_ref.ts} +17 -11
  9. package/assets/js/phoenix_live_view/entry_uploader.js +4 -4
  10. package/assets/js/phoenix_live_view/{hooks.js → hooks.ts} +108 -91
  11. package/assets/js/phoenix_live_view/index.ts +14 -301
  12. package/assets/js/phoenix_live_view/js.js +2 -1
  13. package/assets/js/phoenix_live_view/js_commands.ts +12 -9
  14. package/assets/js/phoenix_live_view/{live_socket.js → live_socket.ts} +582 -114
  15. package/assets/js/phoenix_live_view/live_uploader.js +1 -1
  16. package/assets/js/phoenix_live_view/rendered.js +3 -0
  17. package/assets/js/phoenix_live_view/{utils.js → utils.ts} +35 -6
  18. package/assets/js/phoenix_live_view/{view.js → view.ts} +221 -110
  19. package/assets/js/phoenix_live_view/view_hook.ts +92 -32
  20. package/package.json +5 -2
  21. package/priv/static/phoenix_live_view.cjs.js +577 -314
  22. package/priv/static/phoenix_live_view.cjs.js.map +4 -4
  23. package/priv/static/phoenix_live_view.esm.js +577 -314
  24. package/priv/static/phoenix_live_view.esm.js.map +4 -4
  25. package/priv/static/phoenix_live_view.js +584 -314
  26. package/priv/static/phoenix_live_view.min.js +7 -7
  27. /package/assets/js/phoenix_live_view/{constants.js → constants.ts} +0 -0
@@ -1,312 +1,24 @@
1
1
  /*
2
- ================================================================================
3
- Phoenix LiveView JavaScript Client
4
- ================================================================================
5
-
6
- See the hexdocs at `https://hexdocs.pm/phoenix_live_view` for documentation.
7
- */
2
+ * This is the documentation for the LiveView JavaScript client.
3
+ * It is a more low-level API documentation for advanced users.
4
+ * For a higher-level overview, [see the page on JavaScript interoperability](https://phoenix-live-view.hexdocs.pm/js-interop.html) instead.
5
+ *
6
+ * The main documentation can be found at `https://phoenix-live-view.hexdocs.pm`.
7
+ *
8
+ * @packageDocumentation
9
+ */
8
10
 
9
- import OriginalLiveSocket, { isUsedInput } from "./live_socket";
11
+ import LiveSocket, { type LiveSocketOptions, isUsedInput } from "./live_socket";
10
12
  import DOM from "./dom";
11
13
  import { ViewHook } from "./view_hook";
12
14
  import View from "./view";
13
15
  import { logError } from "./utils";
14
16
 
15
- import type { EncodedJS, LiveSocketJSCommands } from "./js_commands";
16
- import type { Hook, HooksOptions } from "./view_hook";
17
- import type { Socket as PhoenixSocket } from "phoenix";
17
+ import type { EncodedJS } from "./js_commands";
18
+ import type { Hook, HooksOptions, HookInterface } from "./view_hook";
18
19
  import LiveUploader from "./live_uploader";
19
20
 
20
- /**
21
- * Options for configuring the LiveSocket instance.
22
- */
23
- export interface LiveSocketOptions {
24
- /**
25
- * Defaults for phx-debounce and phx-throttle.
26
- */
27
- defaults?: {
28
- /** The millisecond phx-debounce time. Defaults 300 */
29
- debounce?: number;
30
- /** The millisecond phx-throttle time. Defaults 300 */
31
- throttle?: number;
32
- };
33
- /**
34
- * An object or function for passing connect params.
35
- * The function receives the element associated with a given LiveView. For example:
36
- *
37
- * (el) => {view: el.getAttribute("data-my-view-name", token: window.myToken}
38
- *
39
- */
40
- params?:
41
- | ((el: HTMLElement) => { [key: string]: any })
42
- | { [key: string]: any };
43
- /**
44
- * The optional prefix to use for all phx DOM annotations.
45
- *
46
- * Defaults to "phx-".
47
- */
48
- bindingPrefix?: string;
49
- /**
50
- * Callbacks for LiveView hooks.
51
- *
52
- * See [Client hooks via `phx-hook`](https://hexdocs.pm/phoenix_live_view/js-interop.html#client-hooks-via-phx-hook) for more information.
53
- */
54
- hooks?: HooksOptions;
55
- /** Callbacks for LiveView uploaders. */
56
- uploaders?: { [key: string]: any }; // TODO: define more specifically
57
- /** Delay in milliseconds before applying loading states. */
58
- loaderTimeout?: number;
59
- /** Delay in milliseconds before executing phx-disconnected commands. */
60
- disconnectedTimeout?: number;
61
- /** Maximum reloads before entering failsafe mode. */
62
- maxReloads?: number;
63
- /** Minimum time between normal reload attempts. */
64
- reloadJitterMin?: number;
65
- /** Maximum time between normal reload attempts. */
66
- reloadJitterMax?: number;
67
- /** Time between reload attempts in failsafe mode. */
68
- failsafeJitter?: number;
69
- /**
70
- * Function to log debug information. For example:
71
- *
72
- * (view, kind, msg, obj) => console.log(`${view.id} ${kind}: ${msg} - `, obj)
73
- */
74
- viewLogger?: (view: View, kind: string, msg: string, obj: any) => void;
75
- /**
76
- * Object mapping event names to functions for populating event metadata.
77
- *
78
- * metadata: {
79
- * click: (e, el) => {
80
- * return {
81
- * ctrlKey: e.ctrlKey,
82
- * metaKey: e.metaKey,
83
- * detail: e.detail || 1,
84
- * }
85
- * },
86
- * keydown: (e, el) => {
87
- * return {
88
- * key: e.key,
89
- * ctrlKey: e.ctrlKey,
90
- * metaKey: e.metaKey,
91
- * shiftKey: e.shiftKey
92
- * }
93
- * }
94
- * }
95
- *
96
- */
97
- metadata?: { [eventName: string]: (e: Event, el: HTMLElement) => object };
98
- /**
99
- * An optional Storage compatible object
100
- * Useful when LiveView won't have access to `sessionStorage`. For example, This could
101
- * happen if a site loads a cross-domain LiveView in an iframe.
102
- *
103
- * Example usage:
104
- *
105
- * class InMemoryStorage {
106
- * constructor() { this.storage = {} }
107
- * getItem(keyName) { return this.storage[keyName] || null }
108
- * removeItem(keyName) { delete this.storage[keyName] }
109
- * setItem(keyName, keyValue) { this.storage[keyName] = keyValue }
110
- * }
111
- */
112
- sessionStorage?: Storage;
113
- /**
114
- * An optional Storage compatible object
115
- * Useful when LiveView won't have access to `localStorage`.
116
- *
117
- * See `sessionStorage` for an example.
118
- */
119
- localStorage?: Storage;
120
- /**
121
- * If set to `true`, `phx-change` events will be blocked (will not fire)
122
- * while the user is composing input using an IME (Input Method Editor).
123
- * This is determined by the `e.isComposing` property on keyboard events,
124
- * which is `true` when the user is in the process of entering composed characters (for example,
125
- * when typing Japanese or Chinese using romaji or pinyin input methods).
126
- * By default, `phx-change` will not be blocked during a composition session,
127
- * but note that there were issues reported in older versions of Safari,
128
- * where a LiveView patch to the input caused unexpected behavior.
129
- *
130
- * For more information, see
131
- * - https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/isComposing
132
- * - https://github.com/phoenixframework/phoenix_live_view/issues/3322
133
- *
134
- * Defaults to `false`.
135
- */
136
- blockPhxChangeWhileComposing?: boolean;
137
- /** DOM callbacks. */
138
- dom?: {
139
- /**
140
- * An optional function to modify the behavior of querying elements in JS commands.
141
- * @param sourceEl - The source element, e.g. the button that was clicked.
142
- * @param query - The query value.
143
- * @param defaultQuery - A default query function that can be used if no custom query should be applied.
144
- * @returns A list of DOM elements.
145
- */
146
- jsQuerySelectorAll?: (
147
- sourceEl: HTMLElement,
148
- query: string,
149
- defaultQuery: () => Element[],
150
- ) => Element[];
151
- /**
152
- * When defined, called with a start callback that needs to be called
153
- * to perform the actual patch. Failing to call the start callback causes
154
- * the page to become stuck.
155
- *
156
- * This can be used to delay patches in order to perform view transitions,
157
- * for example:
158
- *
159
- * ```javascript
160
- * let liveSocket = new LiveSocket("/live", Socket, {
161
- * dom: {
162
- * onDocumentPatch(start) {
163
- * document.startViewTransition(start);
164
- * }
165
- * }
166
- * })
167
- * ```
168
- *
169
- * It is strongly advised to call start as quickly as possible.
170
- */
171
- onDocumentPatch?: (start: () => void) => void;
172
- /**
173
- * Called immediately before a DOM patch is applied.
174
- */
175
- onPatchStart?: (container: HTMLElement) => void;
176
- /**
177
- * Called immediately after a DOM patch is applied.
178
- */
179
- onPatchEnd?: (container: HTMLElement) => void;
180
- /**
181
- * Called when a new DOM node is added.
182
- */
183
- onNodeAdded?: (node: Node) => void;
184
- /**
185
- * Called before an element is updated.
186
- */
187
- onBeforeElUpdated?: (fromEl: Element, toEl: Element) => void;
188
- };
189
- /** Allow passthrough of other options to the Phoenix Socket constructor. */
190
- [key: string]: any;
191
- }
192
-
193
- /**
194
- * Interface describing the public API of a LiveSocket instance.
195
- */
196
- export interface LiveSocketInstanceInterface {
197
- /**
198
- * Returns the version of the LiveView client.
199
- */
200
- version(): string;
201
- /**
202
- * Returns true if profiling is enabled. See `enableProfiling` and `disableProfiling`.
203
- */
204
- isProfileEnabled(): boolean;
205
- /**
206
- * Returns true if debugging is enabled. See `enableDebug` and `disableDebug`.
207
- */
208
- isDebugEnabled(): boolean;
209
- /**
210
- * Returns true if debugging is disabled. See `enableDebug` and `disableDebug`.
211
- */
212
- isDebugDisabled(): boolean;
213
- /**
214
- * Enables debugging.
215
- *
216
- * When debugging is enabled, the LiveView client will log debug information to the console.
217
- * See [Debugging client events](https://hexdocs.pm/phoenix_live_view/js-interop.html#debugging-client-events) for more information.
218
- */
219
- enableDebug(): void;
220
- /**
221
- * Enables profiling.
222
- *
223
- * When profiling is enabled, the LiveView client will log profiling information to the console.
224
- */
225
- enableProfiling(): void;
226
- /**
227
- * Disables debugging.
228
- */
229
- disableDebug(): void;
230
- /**
231
- * Disables profiling.
232
- */
233
- disableProfiling(): void;
234
- /**
235
- * Enables latency simulation.
236
- *
237
- * When latency simulation is enabled, the LiveView client will add a delay to requests and responses from the server.
238
- * See [Simulating Latency](https://hexdocs.pm/phoenix_live_view/js-interop.html#simulating-latency) for more information.
239
- */
240
- enableLatencySim(upperBoundMs: number): void;
241
- /**
242
- * Disables latency simulation.
243
- */
244
- disableLatencySim(): void;
245
- /**
246
- * Returns the current latency simulation upper bound.
247
- */
248
- getLatencySim(): number | null;
249
- /**
250
- * Returns the Phoenix Socket instance.
251
- */
252
- getSocket(): PhoenixSocket;
253
- /**
254
- * Connects to the LiveView server.
255
- */
256
- connect(): void;
257
- /**
258
- * Disconnects from the LiveView server.
259
- */
260
- disconnect(callback?: () => void): void;
261
- /**
262
- * Can be used to replace the transport used by the underlying Phoenix Socket.
263
- */
264
- replaceTransport(transport: any): void;
265
- /**
266
- * Executes an encoded JS command, targeting the given element.
267
- *
268
- * See [`Phoenix.LiveView.JS`](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.JS.html) for more information.
269
- */
270
- execJS(
271
- el: HTMLElement,
272
- encodedJS: EncodedJS,
273
- eventType?: string | null,
274
- ): void;
275
- /**
276
- * Returns an object with methods to manipulate the DOM and execute JavaScript.
277
- * The applied changes integrate with server DOM patching.
278
- *
279
- * See [JavaScript interoperability](https://hexdocs.pm/phoenix_live_view/js-interop.html) for more information.
280
- */
281
- js(): LiveSocketJSCommands;
282
- }
283
-
284
- /**
285
- * Interface describing the LiveSocket constructor.
286
- */
287
- export interface LiveSocketConstructor {
288
- /**
289
- * Creates a new LiveSocket instance.
290
- *
291
- * @param endpoint - The string WebSocket endpoint, ie, `"wss://example.com/live"`,
292
- * `"/live"` (inherited host & protocol)
293
- * @param socket - the required Phoenix Socket class imported from "phoenix". For example:
294
- *
295
- * import {Socket} from "phoenix"
296
- * import {LiveSocket} from "phoenix_live_view"
297
- * let liveSocket = new LiveSocket("/live", Socket, {...})
298
- *
299
- * @param opts - Optional configuration.
300
- */
301
- new (
302
- endpoint: string,
303
- socket: typeof PhoenixSocket,
304
- opts?: LiveSocketOptions,
305
- ): LiveSocketInstanceInterface;
306
- }
307
-
308
- // because LiveSocket is in JS (for now), we cast it to our defined TypeScript constructor.
309
- const LiveSocket = OriginalLiveSocket as unknown as LiveSocketConstructor;
21
+ export type { LiveSocketOptions, HookInterface, HooksOptions, EncodedJS };
310
22
 
311
23
  /** Creates a hook instance for the given element and callbacks.
312
24
  *
@@ -332,6 +44,8 @@ const LiveSocket = OriginalLiveSocket as unknown as LiveSocketConstructor;
332
44
  * }
333
45
  *
334
46
  * @returns Returns the Hook instance for the custom element.
47
+ *
48
+ * @category JavaScript Hooks
335
49
  */
336
50
  function createHook(el: HTMLElement, callbacks: Hook): ViewHook {
337
51
  let existingHook = DOM.getCustomElHook(el);
@@ -377,6 +91,5 @@ export {
377
91
  createHook,
378
92
  ViewHook,
379
93
  Hook,
380
- HooksOptions,
381
94
  getFileURLForUpload,
382
95
  };
@@ -114,7 +114,8 @@ const JS = {
114
114
  if (eventType === "change") {
115
115
  let { newCid, _target } = args;
116
116
  _target =
117
- _target || (DOM.isFormInput(sourceEl) ? sourceEl.name : undefined);
117
+ _target ||
118
+ (DOM.isFormAssociated(sourceEl) ? sourceEl.name : undefined);
118
119
  if (_target) {
119
120
  pushOpts._target = _target;
120
121
  }
@@ -1,5 +1,6 @@
1
1
  import JS from "./js";
2
2
  import LiveSocket from "./live_socket";
3
+ import { ensureSameOrigin } from "./utils";
3
4
 
4
5
  /**
5
6
  * An encoded JS command. Use functions in the `Phoenix.LiveView.JS` module on
@@ -17,29 +18,29 @@ type BaseOpts = {
17
18
  /**
18
19
  * The CSS transition classes to set.
19
20
  * Accepts a string of classes or a 3-tuple like:
20
- * `["ease-out duration-300", "opacity-0", "opacity-100"]`
21
+ * `["ease-out duration-300", "opacity-0", "opacity-100"]`.
21
22
  */
22
23
  transition?: Transition;
23
- /** The transition duration in milliseconds. Defaults 200. */
24
+ /** The transition duration in milliseconds. Defaults to `200`. */
24
25
  time?: number;
25
- /** Whether to block UI during transition. Defaults `true`. */
26
+ /** Whether to block UI during transition. Defaults to `true`. */
26
27
  blocking?: boolean;
27
28
  };
28
29
 
29
30
  type ShowOpts = BaseOpts & {
30
- /** The CSS display value to set. Defaults "block". */
31
+ /** The CSS display value to set. Defaults to `"block"`. */
31
32
  display?: string;
32
33
  };
33
34
 
34
35
  type ToggleOpts = {
35
- /** The CSS display value to set. Defaults "block". */
36
+ /** The CSS display value to set. Defaults to `"block"`. */
36
37
  display?: string;
37
38
  /**
38
39
  * The CSS transition classes for showing.
39
40
  * Accepts either the string of classes to apply when toggling in, or
40
41
  * a 3-tuple containing the transition class, the class to apply
41
42
  * to start the transition, and the ending transition class, such as:
42
- * `["ease-out duration-300", "opacity-0", "opacity-100"]`
43
+ * `["ease-out duration-300", "opacity-0", "opacity-100"]`.
43
44
  */
44
45
  in?: Transition;
45
46
  /**
@@ -47,7 +48,7 @@ type ToggleOpts = {
47
48
  * Accepts either string of classes to apply when toggling out, or
48
49
  * a 3-tuple containing the transition class, the class to apply
49
50
  * to start the transition, and the ending transition class, such as:
50
- * `["ease-out duration-300", "opacity-100", "opacity-0"]`
51
+ * `["ease-out duration-300", "opacity-100", "opacity-0"]`.
51
52
  */
52
53
  out?: Transition;
53
54
  /** The transition duration in milliseconds. */
@@ -83,7 +84,7 @@ type NavigationOpts = {
83
84
  * Represents all possible JS commands that can be generated by the factory.
84
85
  * This is used as a base for LiveSocketJSCommands and HookJSCommands.
85
86
  */
86
- interface AllJSCommands {
87
+ export interface AllJSCommands {
87
88
  /**
88
89
  * Executes an encoded JS command in the context of an element.
89
90
  * This version is for general use via liveSocket.js().
@@ -243,7 +244,7 @@ interface AllJSCommands {
243
244
  export default (
244
245
  liveSocket: LiveSocket,
245
246
  eventType: string | null,
246
- ): AllJSCommands => {
247
+ ): LiveSocketJSCommands => {
247
248
  return {
248
249
  exec(el, encodedJS) {
249
250
  liveSocket.execJS(el, encodedJS, eventType);
@@ -355,6 +356,7 @@ export default (
355
356
  });
356
357
  },
357
358
  navigate(href, opts = {}) {
359
+ ensureSameOrigin(href, "navigate");
358
360
  const customEvent = new CustomEvent("phx:exec");
359
361
  liveSocket.historyRedirect(
360
362
  customEvent,
@@ -365,6 +367,7 @@ export default (
365
367
  );
366
368
  },
367
369
  patch(href, opts = {}) {
370
+ ensureSameOrigin(href, "patch");
368
371
  const customEvent = new CustomEvent("phx:exec");
369
372
  liveSocket.pushHistoryPatch(
370
373
  customEvent,