@hellotext/hellotext 2.5.6 → 2.5.8

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 (113) hide show
  1. package/README.md +5 -26
  2. package/dist/hellotext.js +1 -1
  3. package/dist/hellotext.js.LICENSE.txt +1 -1
  4. package/index.d.ts +15 -6
  5. package/lib/api/acks.cjs +17 -31
  6. package/lib/api/acks.js +17 -42
  7. package/lib/api/businesses.cjs +14 -28
  8. package/lib/api/businesses.js +13 -36
  9. package/lib/api/events.cjs +26 -40
  10. package/lib/api/events.js +28 -52
  11. package/lib/api/forms.cjs +24 -40
  12. package/lib/api/forms.js +24 -57
  13. package/lib/api/identifications.cjs +15 -29
  14. package/lib/api/identifications.js +15 -40
  15. package/lib/api/index.cjs +26 -46
  16. package/lib/api/index.js +28 -49
  17. package/lib/api/push/identities.cjs +43 -0
  18. package/lib/api/push/identities.js +35 -0
  19. package/lib/api/response.cjs +30 -52
  20. package/lib/api/response.js +31 -60
  21. package/lib/api/submissions.cjs +18 -34
  22. package/lib/api/submissions.js +18 -48
  23. package/lib/api/webchat/messages.cjs +44 -64
  24. package/lib/api/webchat/messages.js +44 -80
  25. package/lib/api/webchats.cjs +37 -56
  26. package/lib/api/webchats.js +37 -65
  27. package/lib/api/whatsapp_widgets.cjs +49 -72
  28. package/lib/api/whatsapp_widgets.js +48 -91
  29. package/lib/builders/input_builder.cjs +36 -48
  30. package/lib/builders/input_builder.js +36 -48
  31. package/lib/builders/logo_builder.cjs +10 -29
  32. package/lib/builders/logo_builder.js +20 -28
  33. package/lib/channels/application_channel.cjs +136 -178
  34. package/lib/channels/application_channel.js +137 -180
  35. package/lib/channels/webchat_channel.cjs +125 -170
  36. package/lib/channels/webchat_channel.js +125 -170
  37. package/lib/controllers/form_controller.cjs +82 -121
  38. package/lib/controllers/form_controller.js +82 -130
  39. package/lib/controllers/message_controller.cjs +211 -282
  40. package/lib/controllers/message_controller.js +209 -284
  41. package/lib/controllers/mixins/usePopover.cjs +3 -6
  42. package/lib/controllers/mixins/usePopover.js +17 -22
  43. package/lib/controllers/webchat/emoji_picker_controller.cjs +106 -150
  44. package/lib/controllers/webchat/emoji_picker_controller.js +105 -170
  45. package/lib/controllers/webchat/useBehaviour.js +5 -5
  46. package/lib/controllers/webchat/useOpeningSequence.js +6 -6
  47. package/lib/controllers/webchat/useTeaser.js +9 -9
  48. package/lib/controllers/webchat_controller.cjs +916 -1088
  49. package/lib/controllers/webchat_controller.js +926 -1152
  50. package/lib/core/configuration/forms.cjs +21 -35
  51. package/lib/core/configuration/forms.js +20 -35
  52. package/lib/core/configuration/locale.cjs +36 -71
  53. package/lib/core/configuration/locale.js +36 -70
  54. package/lib/core/configuration/push.cjs +16 -0
  55. package/lib/core/configuration/push.js +10 -0
  56. package/lib/core/configuration/webchat.cjs +142 -182
  57. package/lib/core/configuration/webchat.js +145 -189
  58. package/lib/core/configuration/whatsapp.cjs +76 -102
  59. package/lib/core/configuration/whatsapp.js +76 -105
  60. package/lib/core/configuration.cjs +62 -75
  61. package/lib/core/configuration.js +61 -75
  62. package/lib/core/event.cjs +36 -59
  63. package/lib/core/event.js +35 -61
  64. package/lib/core/sanitize_html.js +4 -4
  65. package/lib/errors/invalid_event.cjs +5 -26
  66. package/lib/errors/invalid_event.js +5 -26
  67. package/lib/errors/not_initialized_error.cjs +5 -26
  68. package/lib/errors/not_initialized_error.js +5 -26
  69. package/lib/hellotext.cjs +186 -211
  70. package/lib/hellotext.js +189 -236
  71. package/lib/index.js +1 -1
  72. package/lib/models/business.cjs +115 -152
  73. package/lib/models/business.js +118 -162
  74. package/lib/models/cookies.cjs +34 -51
  75. package/lib/models/cookies.js +34 -51
  76. package/lib/models/fingerprint.cjs +8 -23
  77. package/lib/models/fingerprint.js +25 -58
  78. package/lib/models/form.cjs +106 -142
  79. package/lib/models/form.js +105 -153
  80. package/lib/models/form_collection.cjs +63 -101
  81. package/lib/models/form_collection.js +61 -107
  82. package/lib/models/index.cjs +7 -0
  83. package/lib/models/index.js +1 -0
  84. package/lib/models/page.cjs +106 -129
  85. package/lib/models/page.js +106 -131
  86. package/lib/models/push.cjs +345 -0
  87. package/lib/models/push.js +339 -0
  88. package/lib/models/query.cjs +21 -41
  89. package/lib/models/query.js +21 -41
  90. package/lib/models/session.cjs +33 -65
  91. package/lib/models/session.js +30 -63
  92. package/lib/models/user.cjs +29 -51
  93. package/lib/models/user.js +29 -51
  94. package/lib/models/utm.cjs +15 -27
  95. package/lib/models/utm.js +17 -32
  96. package/lib/models/webchat.cjs +52 -76
  97. package/lib/models/webchat.js +52 -90
  98. package/lib/models/whatsapp_widget.cjs +41 -59
  99. package/lib/models/whatsapp_widget.js +41 -73
  100. package/lib/vanilla.cjs +4 -7
  101. package/lib/vanilla.js +2 -1
  102. package/package.json +2 -10
  103. package/src/api/index.js +5 -0
  104. package/src/api/push/identities.js +42 -0
  105. package/src/core/configuration/push.js +12 -0
  106. package/src/core/configuration.js +5 -0
  107. package/src/hellotext.js +15 -1
  108. package/src/index.bundle.js +0 -1
  109. package/src/models/business.js +1 -0
  110. package/src/models/index.js +1 -0
  111. package/src/models/push.js +397 -0
  112. package/src/vanilla.js +2 -1
  113. package/styles/index.css +0 -30
@@ -0,0 +1,42 @@
1
+ import Hellotext from '../../hellotext'
2
+
3
+ import { Configuration } from '../../core'
4
+ import { Response } from '../response'
5
+
6
+ class PushIdentitiesAPI {
7
+ static get endpoint() {
8
+ return Configuration.endpoint('public/push/identities')
9
+ }
10
+
11
+ static async create(data = {}) {
12
+ const response = await fetch(this.endpoint, {
13
+ method: 'POST',
14
+ keepalive: true,
15
+ headers: Hellotext.headers,
16
+ body: JSON.stringify({
17
+ ...data,
18
+ session: Hellotext.session,
19
+ origin: window.location.origin,
20
+ }),
21
+ })
22
+
23
+ return new Response(response.ok, response)
24
+ }
25
+
26
+ static async destroy(data = {}) {
27
+ const response = await fetch(this.endpoint, {
28
+ method: 'DELETE',
29
+ keepalive: true,
30
+ headers: Hellotext.headers,
31
+ body: JSON.stringify({
32
+ ...data,
33
+ session: Hellotext.session,
34
+ origin: window.location.origin,
35
+ }),
36
+ })
37
+
38
+ return new Response(response.ok, response)
39
+ }
40
+ }
41
+
42
+ export default PushIdentitiesAPI
@@ -0,0 +1,12 @@
1
+ class Push {
2
+ static serviceWorkerUrl = null
3
+ static channelId = null
4
+
5
+ static assign(props) {
6
+ this.serviceWorkerUrl = props?.serviceWorkerUrl || null
7
+ this.channelId = props?.channelId || null
8
+ return this
9
+ }
10
+ }
11
+
12
+ export { Push }
@@ -2,6 +2,7 @@ import { Forms } from './configuration/forms'
2
2
  import { Locale } from './configuration/locale'
3
3
  import { Webchat } from './configuration/webchat'
4
4
  import { WhatsApp } from './configuration/whatsapp'
5
+ import { Push } from './configuration/push'
5
6
 
6
7
  /**
7
8
  * @class Configuration
@@ -12,6 +13,7 @@ import { WhatsApp } from './configuration/whatsapp'
12
13
  * @property {Forms} [forms] - form configuration
13
14
  * @property {Webchat} [webchat] - webchat configuration
14
15
  * @property {WhatsApp} [whatsappWidget] - WhatsApp widget configuration
16
+ * @property {Push} [push] - push subscription configuration
15
17
  * @property {Locale} [locale] - locale configuration
16
18
  */
17
19
  class Configuration {
@@ -24,6 +26,7 @@ class Configuration {
24
26
  static forms = Forms
25
27
  static webchat = Webchat
26
28
  static whatsapp = WhatsApp
29
+ static push = Push
27
30
 
28
31
  /**
29
32
  *
@@ -47,6 +50,8 @@ class Configuration {
47
50
  this.webchat = Webchat.assign(value)
48
51
  } else if (key === 'whatsappWidget') {
49
52
  this.whatsapp = WhatsApp.assign(value)
53
+ } else if (key === 'push') {
54
+ this.push = Push.assign(value)
50
55
  } else {
51
56
  this[key] = value
52
57
  }
package/src/hellotext.js CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  Fingerprint,
7
7
  FormCollection,
8
8
  Page,
9
+ Push,
9
10
  Query,
10
11
  Session,
11
12
  User,
@@ -21,6 +22,7 @@ class Hellotext {
21
22
  static business
22
23
  static webchat
23
24
  static whatsapp
25
+ static push
24
26
 
25
27
  /**
26
28
  * initialize the module.
@@ -28,10 +30,13 @@ class Hellotext {
28
30
  * @param { Configuration } config
29
31
  */
30
32
  static async initialize(business, config = {}) {
33
+ this.push?.dispose()
34
+ this.push = null
35
+
31
36
  this.business = new Business(business)
32
37
  this.page = new Page()
33
38
 
34
- Configuration.assign(config)
39
+ Configuration.assign({ push: {}, ...config })
35
40
  Session.initialize(this.page)
36
41
 
37
42
  this.forms = new FormCollection()
@@ -39,6 +44,15 @@ class Hellotext {
39
44
  this.query = new Query()
40
45
 
41
46
  const businessData = await this.business.hydrate()
47
+
48
+ if (config.push !== false && businessData?.push?.public_key && Push.supported) {
49
+ this.push = new Push(businessData.push)
50
+
51
+ this.push.initialize().catch(error => {
52
+ console.warn('Hellotext Push initialization failed:', error)
53
+ })
54
+ }
55
+
42
56
  const webchatConfig =
43
57
  config.webchat === false
44
58
  ? false
@@ -1,4 +1,3 @@
1
- import '../styles/index.css'
2
1
  import './index.js'
3
2
 
4
3
  import Hellotext from './index.js'
@@ -27,6 +27,7 @@ const stylesheetLoadTimeout = 10000
27
27
  * @property {String} [locale] - Default dashboard locale for the business.
28
28
  * @property {String} [style_url] - Stylesheet URL to inject for dashboard-managed surfaces.
29
29
  * @property {BusinessWebchat|null} [webchat] - Dashboard webchat defaults.
30
+ * @property {{public_key: String}|null} [push] - Public VAPID key for push subscriptions.
30
31
  * @property {String|Array<String>} [whitelist] - Domain whitelist configuration.
31
32
  * @property {String} [subscription] - Current business subscription tier.
32
33
  */
@@ -4,6 +4,7 @@ export { Fingerprint } from './fingerprint'
4
4
  export { Form } from './form'
5
5
  export { FormCollection } from './form_collection'
6
6
  export { Page } from './page'
7
+ export { Push } from './push'
7
8
  export { Query } from './query'
8
9
  export { Session } from './session'
9
10
  export { User } from './user'
@@ -0,0 +1,397 @@
1
+ import API from '../api'
2
+ import { Configuration } from '../core'
3
+
4
+ /**
5
+ * Manages browser Push subscriptions for Hellotext.
6
+ *
7
+ * @property {Promise<void>|null} ready - Initialization promise, available after initialize().
8
+ */
9
+ class Push {
10
+ /**
11
+ * @param {Object} data - Push configuration from the business response.
12
+ * @param {String} data.public_key - Base64url-encoded VAPID public key.
13
+ */
14
+ constructor(data) {
15
+ this.publicKey = data.public_key
16
+ this.serviceWorkerUrl = Configuration.push.serviceWorkerUrl
17
+
18
+ this.channelId = Configuration.push.channelId
19
+ this.ready = null
20
+
21
+ this.registrationPromise = null
22
+
23
+ this.subscribePromise = null
24
+ this.unsubscribePromise = null
25
+
26
+ this.syncPromise = null
27
+
28
+ this.subscription = null
29
+
30
+ this.retryTimeout = null
31
+ this.retryAttempts = 0
32
+ this.disposed = false
33
+ }
34
+
35
+ /**
36
+ * Prepares the service worker and restores an existing subscription.
37
+ *
38
+ * @returns {Promise<void>}
39
+ */
40
+ initialize() {
41
+ this.ready = this.restoreSubscription()
42
+ return this.ready
43
+ }
44
+
45
+ /**
46
+ * Registers an existing Hellotext subscription with the server without prompting.
47
+ *
48
+ * @private
49
+ * @returns {Promise<void>}
50
+ */
51
+ async restoreSubscription() {
52
+ const registration = await this.getRegistration()
53
+ const subscription = await registration.pushManager.getSubscription()
54
+
55
+ if (this.disposed || this.unsubscribePromise || !subscription || !this.owns(subscription)) {
56
+ return
57
+ }
58
+
59
+ this.subscription = subscription
60
+ await this.sync()
61
+ }
62
+
63
+ /**
64
+ * Creates or reuses a Push subscription. Call from a user click handler.
65
+ * Concurrent calls share the same pending request.
66
+ *
67
+ * @returns {Promise<import('../api/response').Response|void>} Server registration response,
68
+ * or no value when disposed.
69
+ * Rejects when permission is denied or a browser or network operation fails.
70
+ */
71
+ subscribe() {
72
+ if (this.disposed) return Promise.resolve()
73
+ if (this.unsubscribePromise) return Promise.reject(new Error('Push unsubscribe is in progress'))
74
+ if (this.subscribePromise) return this.subscribePromise
75
+
76
+ // Request permission before awaiting worker readiness to retain the click's user activation.
77
+ const permission =
78
+ Notification.permission === 'default'
79
+ ? Notification.requestPermission()
80
+ : Promise.resolve(Notification.permission)
81
+
82
+ this.subscribePromise = this.createSubscription(permission).finally(() => {
83
+ this.subscribePromise = null
84
+ })
85
+
86
+ return this.subscribePromise
87
+ }
88
+
89
+ /**
90
+ * Waits for permission and worker readiness, then subscribes and registers with Hellotext.
91
+ *
92
+ * @private
93
+ * @param {Promise<NotificationPermission>} permission - Pending notification permission result.
94
+ * @returns {Promise<import('../api/response').Response|void>}
95
+ */
96
+ async createSubscription(permission) {
97
+ if ((await permission) !== 'granted') throw new Error('Push permission was not granted')
98
+
99
+ const registration = await this.getRegistration()
100
+ if (this.disposed) return
101
+
102
+ let subscription = await registration.pushManager.getSubscription()
103
+ if (this.disposed) return
104
+ if (subscription && !this.owns(subscription)) {
105
+ throw new Error('The existing Push subscription belongs to a different application')
106
+ }
107
+
108
+ subscription ||= await registration.pushManager.subscribe({
109
+ userVisibleOnly: true,
110
+ applicationServerKey: this.applicationServerKey,
111
+ })
112
+
113
+ if (this.disposed) return
114
+ this.subscription = subscription
115
+ return this.sync()
116
+ }
117
+
118
+ /**
119
+ * Disables the server identity and removes the browser subscription.
120
+ * Keeps the subscription when the server request fails so the caller can retry.
121
+ *
122
+ * @returns {Promise<import('../api/response').Response|null|void>} Server response, null when
123
+ * no subscription exists, or no value when disposed. Rejects when a browser or network
124
+ * operation fails.
125
+ */
126
+ unsubscribe() {
127
+ if (this.disposed) return Promise.resolve()
128
+ if (this.unsubscribePromise) return this.unsubscribePromise
129
+
130
+ this.clearRetryTimeout()
131
+ this.unsubscribePromise = this.removeSubscription().finally(() => {
132
+ this.unsubscribePromise = null
133
+ })
134
+
135
+ return this.unsubscribePromise
136
+ }
137
+
138
+ /**
139
+ * Finishes pending registration before disabling and removing the subscription.
140
+ *
141
+ * @private
142
+ * @returns {Promise<import('../api/response').Response|null|void>}
143
+ */
144
+ async removeSubscription() {
145
+ await this.ready?.catch(() => {})
146
+ await this.subscribePromise?.catch(() => {})
147
+ await this.syncPromise?.catch(() => {})
148
+
149
+ const registration = await this.getRegistration()
150
+ const subscription = (await registration.pushManager.getSubscription()) || this.subscription
151
+ if (this.disposed) return
152
+ if (!subscription) return null
153
+ if (!this.owns(subscription)) {
154
+ throw new Error('The existing Push subscription belongs to a different application')
155
+ }
156
+
157
+ this.subscription = subscription
158
+
159
+ const response = await API.pushIdentities.destroy({
160
+ subscription: subscription.toJSON(),
161
+ })
162
+ if (response.failed) return response
163
+ if (this.disposed) return
164
+
165
+ await subscription.unsubscribe()
166
+ this.subscription = null
167
+ this.clearRetryTimeout()
168
+
169
+ return response
170
+ }
171
+
172
+ /**
173
+ * Registers the current subscription, sharing any request already in progress.
174
+ *
175
+ * @private
176
+ * @returns {Promise<import('../api/response').Response|void>}
177
+ */
178
+ sync() {
179
+ if (this.disposed) return Promise.resolve()
180
+ if (this.syncPromise) return this.syncPromise
181
+
182
+ this.clearRetryTimeout()
183
+ this.syncPromise = this.registerIdentity().finally(() => {
184
+ this.syncPromise = null
185
+ })
186
+
187
+ return this.syncPromise
188
+ }
189
+
190
+ /**
191
+ * Sends the subscription to Hellotext and schedules a retry on failure.
192
+ *
193
+ * @private
194
+ * @returns {Promise<import('../api/response').Response>}
195
+ */
196
+ async registerIdentity() {
197
+ try {
198
+ const response = await API.pushIdentities.create({
199
+ subscription: this.subscription.toJSON(),
200
+ ...(this.channelId ? { channel_id: this.channelId } : {}),
201
+ })
202
+
203
+ if (response.succeeded) {
204
+ this.retryAttempts = 0
205
+ } else {
206
+ this.scheduleRetry()
207
+ }
208
+
209
+ return response
210
+ } catch (error) {
211
+ this.scheduleRetry()
212
+ throw error
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Schedules up to three registration retries with increasing delays.
218
+ *
219
+ * @private
220
+ * @returns {void}
221
+ */
222
+ scheduleRetry() {
223
+ if (this.disposed || this.unsubscribePromise || this.retryTimeout || this.retryAttempts >= 3)
224
+ return
225
+
226
+ this.retryTimeout = setTimeout(() => {
227
+ this.retryTimeout = null
228
+ this.sync().catch(() => {})
229
+ }, 1000 * 2 ** this.retryAttempts)
230
+ this.retryAttempts += 1
231
+ }
232
+
233
+ /**
234
+ * Cancels a pending registration retry.
235
+ *
236
+ * @private
237
+ * @returns {void}
238
+ */
239
+ clearRetryTimeout() {
240
+ clearTimeout(this.retryTimeout)
241
+ this.retryTimeout = null
242
+ }
243
+
244
+ /**
245
+ * Stops registration retries and prevents further use of this instance.
246
+ *
247
+ * @returns {void}
248
+ */
249
+ dispose() {
250
+ this.disposed = true
251
+ this.clearRetryTimeout()
252
+ }
253
+
254
+ /**
255
+ * Whether this instance has a browser subscription, regardless of server registration.
256
+ *
257
+ * @returns {Boolean}
258
+ */
259
+ get subscribed() {
260
+ return !!this.subscription
261
+ }
262
+
263
+ /**
264
+ * Decodes the public key into the bytes expected by PushManager.subscribe().
265
+ *
266
+ * @private
267
+ * @returns {Uint8Array}
268
+ */
269
+ get applicationServerKey() {
270
+ const base64 = this.publicKey.replace(/-/g, '+').replace(/_/g, '/')
271
+ return Uint8Array.from(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, '=')), char =>
272
+ char.charCodeAt(0),
273
+ )
274
+ }
275
+
276
+ /**
277
+ * Checks whether a subscription uses this instance's public key.
278
+ *
279
+ * @private
280
+ * @param {PushSubscription} subscription - Browser subscription to check.
281
+ * @returns {Boolean}
282
+ */
283
+ owns(subscription) {
284
+ const key = subscription.options?.applicationServerKey
285
+ if (!key) return false
286
+
287
+ const actual = new Uint8Array(key)
288
+ const expected = this.applicationServerKey
289
+ return (
290
+ actual.length === expected.length && actual.every((value, index) => value === expected[index])
291
+ )
292
+ }
293
+
294
+ /**
295
+ * Gets the worker registration, sharing any pending lookup.
296
+ * Failed lookups can be retried by a later call.
297
+ *
298
+ * @private
299
+ * @returns {Promise<ServiceWorkerRegistration>}
300
+ */
301
+ getRegistration() {
302
+ if (!this.registrationPromise) {
303
+ this.registrationPromise = this.loadRegistration().catch(error => {
304
+ this.registrationPromise = null
305
+ throw error
306
+ })
307
+ }
308
+
309
+ return this.registrationPromise
310
+ }
311
+
312
+ /**
313
+ * Registers the configured worker or waits for the page's existing registration.
314
+ *
315
+ * @private
316
+ * @returns {Promise<ServiceWorkerRegistration>} An active registration.
317
+ * Rejects if registration fails or the worker readiness wait times out.
318
+ */
319
+ async loadRegistration() {
320
+ if (this.serviceWorkerUrl) {
321
+ const registration = await navigator.serviceWorker.register(this.serviceWorkerUrl)
322
+
323
+ if (registration.active && !registration.installing && !registration.waiting) {
324
+ // A returning visitor may have an older worker that does not include our Push handlers.
325
+ // Calling register() with the same URL can return that existing registration without
326
+ // checking whether the script served at that URL has changed since their last visit.
327
+ //
328
+ // If no replacement is already installing or waiting, explicitly check for an update
329
+ // before treating the active worker as ready. Awaiting update() completes the update
330
+ // check, but does not wait for a replacement worker to activate. The code below selects
331
+ // that replacement, if one was found, and waits for its activation before subscribing.
332
+ await registration.update()
333
+ }
334
+
335
+ const worker = registration.installing || registration.waiting || registration.active
336
+ if (worker?.state === 'activated') return registration
337
+
338
+ return new Promise((resolve, reject) => {
339
+ const timeout = setTimeout(
340
+ () => finish(new Error('Push service worker did not become active')),
341
+ 10000,
342
+ )
343
+
344
+ const finish = error => {
345
+ clearTimeout(timeout)
346
+ worker?.removeEventListener('statechange', changed)
347
+ error ? reject(error) : resolve(registration)
348
+ }
349
+
350
+ const changed = () => {
351
+ if (worker?.state === 'activated') finish()
352
+ if (worker?.state === 'redundant')
353
+ finish(new Error('Push service worker installation failed'))
354
+ }
355
+
356
+ worker?.addEventListener('statechange', changed)
357
+ changed()
358
+ })
359
+ }
360
+
361
+ // Reuse the service worker already registered for this page.
362
+ return new Promise((resolve, reject) => {
363
+ const timeout = setTimeout(
364
+ () => reject(new Error('Push service worker is not available')),
365
+ 10000,
366
+ )
367
+ navigator.serviceWorker.ready.then(
368
+ registration => {
369
+ clearTimeout(timeout)
370
+ resolve(registration)
371
+ },
372
+ error => {
373
+ clearTimeout(timeout)
374
+ reject(error)
375
+ },
376
+ )
377
+ })
378
+ }
379
+
380
+ /**
381
+ * Whether the current page provides the browser APIs required for Push.
382
+ *
383
+ * @returns {Boolean}
384
+ */
385
+ static get supported() {
386
+ return (
387
+ typeof window !== 'undefined' &&
388
+ window.isSecureContext === true &&
389
+ typeof navigator !== 'undefined' &&
390
+ 'serviceWorker' in navigator &&
391
+ typeof PushManager !== 'undefined' &&
392
+ typeof Notification !== 'undefined'
393
+ )
394
+ }
395
+ }
396
+
397
+ export { Push }
package/src/vanilla.js CHANGED
@@ -1 +1,2 @@
1
- export default from './hellotext'
1
+ import Hellotext from './hellotext'
2
+ export default Hellotext
package/styles/index.css DELETED
@@ -1,30 +0,0 @@
1
- form[data-hello-form] {
2
- position: relative;
3
- }
4
-
5
- form[data-hello-form] article [data-error-container] {
6
- font-size: 0.875rem;
7
- line-height: 1.25rem;
8
- display: none;
9
- }
10
-
11
- form[data-hello-form] article:has(input:invalid) [data-error-container] {
12
- display: block;
13
- }
14
-
15
- form[data-hello-form] [data-logo-container] {
16
- display: flex;
17
- justify-content: center;
18
- align-items: flex-end;
19
- position: absolute;
20
- right: 1rem;
21
- bottom: 1rem;
22
- }
23
-
24
- form[data-hello-form] [data-logo-container] small {
25
- margin: 0 0.3rem;
26
- }
27
-
28
- form[data-hello-form] [data-logo-container] [data-hello-brand] {
29
- width: 4rem;
30
- }