flash-notifications 0.0.38 → 0.0.40

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 (36) hide show
  1. package/README.md +66 -1
  2. package/build/container/index.d.ts +12 -0
  3. package/build/container/index.d.ts.map +1 -1
  4. package/build/container/index.js +50 -8
  5. package/build/container/notification.d.ts.map +1 -1
  6. package/build/container/notification.js +5 -2
  7. package/build/flash-notifications.d.ts +2 -2
  8. package/build/flash-notifications.d.ts.map +1 -1
  9. package/build/flash-notifications.js +11 -4
  10. package/build/listener.d.ts.map +1 -1
  11. package/package.json +17 -10
  12. package/.eslintrc.js +0 -12
  13. package/AGENTS.md +0 -3
  14. package/CHANGELOG.md +0 -10
  15. package/android/build.gradle +0 -43
  16. package/android/src/main/AndroidManifest.xml +0 -2
  17. package/android/src/main/java/expo/modules/flashnotifications/FlashNotificationsModule.kt +0 -50
  18. package/android/src/main/java/expo/modules/flashnotifications/FlashNotificationsView.kt +0 -30
  19. package/expo-module.config.json +0 -17
  20. package/ios/FlashNotifications.podspec +0 -29
  21. package/ios/FlashNotificationsModule.swift +0 -48
  22. package/ios/FlashNotificationsView.swift +0 -38
  23. package/peak_flow.yml +0 -5
  24. package/scripts/velocious-test.js +0 -186
  25. package/spec/flash-notifications-spec.js +0 -46
  26. package/spec/support/dummy-http-server.js +0 -52
  27. package/spec/support/system-test-helper.js +0 -99
  28. package/src/configuration.js +0 -10
  29. package/src/container/index.jsx +0 -214
  30. package/src/container/notification.jsx +0 -130
  31. package/src/debug.js +0 -13
  32. package/src/events.js +0 -7
  33. package/src/flash-notifications.js +0 -99
  34. package/src/index.js +0 -15
  35. package/src/listener.js +0 -56
  36. package/tsconfig.json +0 -15
@@ -1,2 +0,0 @@
1
- <manifest>
2
- </manifest>
@@ -1,50 +0,0 @@
1
- package expo.modules.flashnotifications
2
-
3
- import expo.modules.kotlin.modules.Module
4
- import expo.modules.kotlin.modules.ModuleDefinition
5
- import java.net.URL
6
-
7
- class FlashNotificationsModule : Module() {
8
- // Each module class must implement the definition function. The definition consists of components
9
- // that describes the module's functionality and behavior.
10
- // See https://docs.expo.dev/modules/module-api for more details about available components.
11
- override fun definition() = ModuleDefinition {
12
- // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
13
- // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
14
- // The module will be accessible from `requireNativeModule('FlashNotifications')` in JavaScript.
15
- Name("FlashNotifications")
16
-
17
- // Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
18
- Constants(
19
- "PI" to Math.PI
20
- )
21
-
22
- // Defines event names that the module can send to JavaScript.
23
- Events("onChange")
24
-
25
- // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
26
- Function("hello") {
27
- "Hello world! 👋"
28
- }
29
-
30
- // Defines a JavaScript function that always returns a Promise and whose native code
31
- // is by default dispatched on the different thread than the JavaScript runtime runs on.
32
- AsyncFunction("setValueAsync") { value: String ->
33
- // Send an event to JavaScript.
34
- sendEvent("onChange", mapOf(
35
- "value" to value
36
- ))
37
- }
38
-
39
- // Enables the module to be used as a native view. Definition components that are accepted as part of
40
- // the view definition: Prop, Events.
41
- View(FlashNotificationsView::class) {
42
- // Defines a setter for the `url` prop.
43
- Prop("url") { view: FlashNotificationsView, url: URL ->
44
- view.webView.loadUrl(url.toString())
45
- }
46
- // Defines an event that the view can send to JavaScript.
47
- Events("onLoad")
48
- }
49
- }
50
- }
@@ -1,30 +0,0 @@
1
- package expo.modules.flashnotifications
2
-
3
- import android.content.Context
4
- import android.webkit.WebView
5
- import android.webkit.WebViewClient
6
- import expo.modules.kotlin.AppContext
7
- import expo.modules.kotlin.viewevent.EventDispatcher
8
- import expo.modules.kotlin.views.ExpoView
9
-
10
- class FlashNotificationsView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
11
- // Creates and initializes an event dispatcher for the `onLoad` event.
12
- // The name of the event is inferred from the value and needs to match the event name defined in the module.
13
- private val onLoad by EventDispatcher()
14
-
15
- // Defines a WebView that will be used as the root subview.
16
- internal val webView = WebView(context).apply {
17
- layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
18
- webViewClient = object : WebViewClient() {
19
- override fun onPageFinished(view: WebView, url: String) {
20
- // Sends an event to JavaScript. Triggers a callback defined on the view component in JavaScript.
21
- onLoad(mapOf("url" to url))
22
- }
23
- }
24
- }
25
-
26
- init {
27
- // Adds the WebView to the view hierarchy.
28
- addView(webView)
29
- }
30
- }
@@ -1,17 +0,0 @@
1
- {
2
- "platforms": [
3
- "apple",
4
- "android",
5
- "web"
6
- ],
7
- "apple": {
8
- "modules": [
9
- "FlashNotificationsModule"
10
- ]
11
- },
12
- "android": {
13
- "modules": [
14
- "expo.modules.flashnotifications.FlashNotificationsModule"
15
- ]
16
- }
17
- }
@@ -1,29 +0,0 @@
1
- require 'json'
2
-
3
- package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
-
5
- Pod::Spec.new do |s|
6
- s.name = 'FlashNotifications'
7
- s.version = package['version']
8
- s.summary = package['description']
9
- s.description = package['description']
10
- s.license = package['license']
11
- s.author = package['author']
12
- s.homepage = package['homepage']
13
- s.platforms = {
14
- :ios => '15.1',
15
- :tvos => '15.1'
16
- }
17
- s.swift_version = '5.4'
18
- s.source = { git: 'https://github.com/kaspernj/flash-notifications' }
19
- s.static_framework = true
20
-
21
- s.dependency 'ExpoModulesCore'
22
-
23
- # Swift/Objective-C compatibility
24
- s.pod_target_xcconfig = {
25
- 'DEFINES_MODULE' => 'YES',
26
- }
27
-
28
- s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
29
- end
@@ -1,48 +0,0 @@
1
- import ExpoModulesCore
2
-
3
- public class FlashNotificationsModule: Module {
4
- // Each module class must implement the definition function. The definition consists of components
5
- // that describes the module's functionality and behavior.
6
- // See https://docs.expo.dev/modules/module-api for more details about available components.
7
- public func definition() -> ModuleDefinition {
8
- // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
9
- // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
10
- // The module will be accessible from `requireNativeModule('FlashNotifications')` in JavaScript.
11
- Name("FlashNotifications")
12
-
13
- // Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
14
- Constants([
15
- "PI": Double.pi
16
- ])
17
-
18
- // Defines event names that the module can send to JavaScript.
19
- Events("onChange")
20
-
21
- // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
22
- Function("hello") {
23
- return "Hello world! 👋"
24
- }
25
-
26
- // Defines a JavaScript function that always returns a Promise and whose native code
27
- // is by default dispatched on the different thread than the JavaScript runtime runs on.
28
- AsyncFunction("setValueAsync") { (value: String) in
29
- // Send an event to JavaScript.
30
- self.sendEvent("onChange", [
31
- "value": value
32
- ])
33
- }
34
-
35
- // Enables the module to be used as a native view. Definition components that are accepted as part of the
36
- // view definition: Prop, Events.
37
- View(FlashNotificationsView.self) {
38
- // Defines a setter for the `url` prop.
39
- Prop("url") { (view: FlashNotificationsView, url: URL) in
40
- if view.webView.url != url {
41
- view.webView.load(URLRequest(url: url))
42
- }
43
- }
44
-
45
- Events("onLoad")
46
- }
47
- }
48
- }
@@ -1,38 +0,0 @@
1
- import ExpoModulesCore
2
- import WebKit
3
-
4
- // This view will be used as a native component. Make sure to inherit from `ExpoView`
5
- // to apply the proper styling (e.g. border radius and shadows).
6
- class FlashNotificationsView: ExpoView {
7
- let webView = WKWebView()
8
- let onLoad = EventDispatcher()
9
- var delegate: WebViewDelegate?
10
-
11
- required init(appContext: AppContext? = nil) {
12
- super.init(appContext: appContext)
13
- clipsToBounds = true
14
- delegate = WebViewDelegate { url in
15
- self.onLoad(["url": url])
16
- }
17
- webView.navigationDelegate = delegate
18
- addSubview(webView)
19
- }
20
-
21
- override func layoutSubviews() {
22
- webView.frame = bounds
23
- }
24
- }
25
-
26
- class WebViewDelegate: NSObject, WKNavigationDelegate {
27
- let onUrlChange: (String) -> Void
28
-
29
- init(onUrlChange: @escaping (String) -> Void) {
30
- self.onUrlChange = onUrlChange
31
- }
32
-
33
- func webView(_ webView: WKWebView, didFinish navigation: WKNavigation) {
34
- if let url = webView.url {
35
- onUrlChange(url.absoluteString)
36
- }
37
- }
38
- }
package/peak_flow.yml DELETED
@@ -1,5 +0,0 @@
1
- before_script:
2
- - npm install
3
- script:
4
- - npm run test
5
- - npm run lint
@@ -1,186 +0,0 @@
1
- import Configuration from "velocious/build/src/configuration.js"
2
- import NodeEnvironmentHandler from "velocious/build/src/environment-handlers/node.js"
3
- import TestFilesFinder from "velocious/build/src/testing/test-files-finder.js"
4
- import TestRunner from "velocious/build/src/testing/test-runner.js"
5
- import fs from "node:fs/promises"
6
- import {execFileSync} from "node:child_process"
7
- import path from "node:path"
8
-
9
- const INCLUDE_TAG_FLAGS = new Set(["--tag", "--include-tag", "-t"])
10
- const EXCLUDE_TAG_FLAGS = new Set(["--exclude-tag", "--skip-tag", "-x"])
11
-
12
- const splitTags = (value) => {
13
- if (!value) return []
14
-
15
- return value
16
- .split(",")
17
- .map((tag) => tag.trim())
18
- .filter(Boolean)
19
- }
20
-
21
- const parseTagFilters = (processArgs) => {
22
- const includeTags = []
23
- const excludeTags = []
24
- const filteredProcessArgs = []
25
- let inRestArgs = false
26
-
27
- for (let i = 0; i < processArgs.length; i++) {
28
- const arg = processArgs[i]
29
-
30
- if (arg === "--") {
31
- inRestArgs = true
32
- filteredProcessArgs.push(arg)
33
- continue
34
- }
35
-
36
- if (!inRestArgs) {
37
- if (INCLUDE_TAG_FLAGS.has(arg)) {
38
- const nextValue = processArgs[i + 1]
39
-
40
- if (nextValue && !nextValue.startsWith("-")) {
41
- includeTags.push(...splitTags(nextValue))
42
- i++
43
- }
44
-
45
- continue
46
- }
47
-
48
- if (EXCLUDE_TAG_FLAGS.has(arg)) {
49
- const nextValue = processArgs[i + 1]
50
-
51
- if (nextValue && !nextValue.startsWith("-")) {
52
- excludeTags.push(...splitTags(nextValue))
53
- i++
54
- }
55
-
56
- continue
57
- }
58
-
59
- if (arg.startsWith("--tag=")) {
60
- includeTags.push(...splitTags(arg.slice("--tag=".length)))
61
- continue
62
- }
63
-
64
- if (arg.startsWith("--include-tag=")) {
65
- includeTags.push(...splitTags(arg.slice("--include-tag=".length)))
66
- continue
67
- }
68
-
69
- if (arg.startsWith("--exclude-tag=")) {
70
- excludeTags.push(...splitTags(arg.slice("--exclude-tag=".length)))
71
- continue
72
- }
73
-
74
- if (arg.startsWith("--skip-tag=")) {
75
- excludeTags.push(...splitTags(arg.slice("--skip-tag=".length)))
76
- continue
77
- }
78
- }
79
-
80
- filteredProcessArgs.push(arg)
81
- }
82
-
83
- return {
84
- includeTags: Array.from(new Set(includeTags)),
85
- excludeTags: Array.from(new Set(excludeTags)),
86
- filteredProcessArgs
87
- }
88
- }
89
-
90
- const main = async () => {
91
- const processArgs = process.argv.slice(2)
92
-
93
- const distPath = path.join(process.cwd(), "example", "dist")
94
- try {
95
- await fs.stat(distPath)
96
- } catch {
97
- execFileSync("npm", ["run", "export:web"], {stdio: "inherit"})
98
- }
99
-
100
- const environmentHandler = new NodeEnvironmentHandler()
101
- const configuration = new Configuration({
102
- environment: "test",
103
- environmentHandler,
104
- directory: process.cwd(),
105
- database: {test: {}}
106
- })
107
-
108
- configuration.setCurrent()
109
-
110
- let directory
111
- const directories = []
112
-
113
- if (process.env.VELOCIOUS_TEST_DIR) {
114
- directory = process.env.VELOCIOUS_TEST_DIR
115
- directories.push(process.env.VELOCIOUS_TEST_DIR)
116
- } else {
117
- directory = process.cwd()
118
- directories.push(process.cwd())
119
- directories.push(`${process.cwd()}/__tests__`)
120
- directories.push(`${process.cwd()}/tests`)
121
- directories.push(`${process.cwd()}/spec`)
122
- }
123
-
124
- const {includeTags, excludeTags, filteredProcessArgs} = parseTagFilters(processArgs)
125
- const testFilesFinder = new TestFilesFinder({
126
- directory,
127
- directories,
128
- processArgs: filteredProcessArgs
129
- })
130
- const testFiles = await testFilesFinder.findTestFiles()
131
- const testRunner = new TestRunner({configuration, excludeTags, includeTags, testFiles})
132
-
133
- let signalHandled = false
134
- const handleSignal = async (signal) => {
135
- if (signalHandled) return
136
-
137
- signalHandled = true
138
- console.error(`\nReceived ${signal}, running afterAll hooks before exit...`)
139
-
140
- try {
141
- await testRunner.runAfterAllsForActiveScopes()
142
- } catch (error) {
143
- console.error("Failed while running afterAll hooks:", error)
144
- } finally {
145
- process.exit(130)
146
- }
147
- }
148
-
149
- process.once("SIGINT", () => { void handleSignal("SIGINT") })
150
- process.once("SIGTERM", () => { void handleSignal("SIGTERM") })
151
-
152
- await testRunner.prepare()
153
-
154
- if (testRunner.getTestsCount() === 0) {
155
- throw new Error(`${testRunner.getTestsCount()} tests was found in ${testFiles.length} file(s)`)
156
- }
157
-
158
- await testRunner.run()
159
-
160
- const executedTests = testRunner.getExecutedTestsCount()
161
-
162
- if ((includeTags.length > 0 || excludeTags.length > 0) && executedTests === 0) {
163
- console.error("\nNo tests matched the provided tag filters")
164
- process.exit(1)
165
- }
166
-
167
- if (testRunner.isFailed()) {
168
- console.error(
169
- `\nTest run failed with ${testRunner.getFailedTests()} failed tests and ${testRunner.getSuccessfulTests()} successfull`
170
- )
171
- process.exit(1)
172
- } else if (testRunner.areAnyTestsFocussed()) {
173
- console.error(
174
- `\nFocussed run with ${testRunner.getFailedTests()} failed tests and ${testRunner.getSuccessfulTests()} successfull`
175
- )
176
- process.exit(1)
177
- } else {
178
- console.log(`\nTest run succeeded with ${testRunner.getSuccessfulTests()} successful tests`)
179
- process.exit(0)
180
- }
181
- }
182
-
183
- main().catch((error) => {
184
- console.error(error)
185
- process.exit(1)
186
- })
@@ -1,46 +0,0 @@
1
- // @ts-check
2
-
3
- import "velocious/build/src/testing/test.js"
4
- import SystemTest from "system-testing/build/system-test.js"
5
- import SystemTestHelper from "./support/system-test-helper.js"
6
- import wait from "awaitery/build/wait.js"
7
-
8
- SystemTest.rootPath = "/?systemTest=true"
9
-
10
- const systemTestHelper = new SystemTestHelper()
11
- systemTestHelper.installHooks()
12
-
13
- describe("Flash notifications", () => {
14
- it("dismisses a notification when pressed", async () => {
15
- await SystemTest.run(async (systemTest) => {
16
- await systemTest.visit("/")
17
-
18
- const triggerButton = await systemTest.findByTestID("flashNotifications/showNotification")
19
- await systemTest.click(triggerButton)
20
-
21
- const notificationMessage = await systemTest.findByTestID("notification-message", {useBaseSelector: false})
22
- const notificationText = await notificationMessage.getText()
23
- expect(notificationText).toEqual("Dismiss me")
24
- const notificationContainer = await systemTest.findByTestID("flash-notifications-notification", {useBaseSelector: false})
25
-
26
- await systemTest.click(notificationContainer)
27
- await systemTest.waitForNoSelector("[data-testid='flash-notifications-notification']", {useBaseSelector: false})
28
- })
29
- })
30
-
31
- it("auto dismisses a notification after a delay", async () => {
32
- await SystemTest.run(async (systemTest) => {
33
- await systemTest.visit("/")
34
-
35
- const triggerButton = await systemTest.findByTestID("flashNotifications/showNotification")
36
- await systemTest.click(triggerButton)
37
-
38
- const notificationMessage = await systemTest.findByTestID("notification-message", {useBaseSelector: false})
39
- const notificationText = await notificationMessage.getText()
40
- expect(notificationText).toEqual("Dismiss me")
41
-
42
- await wait(4500)
43
- await systemTest.waitForNoSelector("[data-testid='notification-message']", {useBaseSelector: false})
44
- })
45
- })
46
- })
@@ -1,52 +0,0 @@
1
- // @ts-check
2
-
3
- import fs from "node:fs/promises"
4
- import path from "node:path"
5
- import {fileURLToPath} from "node:url"
6
-
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
8
-
9
- /**
10
- * Ensures the dummy app's dist folder is served for system tests.
11
- */
12
- export default class DummyHttpServerEnvironment {
13
- constructor({host = "dist"} = {}) {
14
- this.host = host
15
- this.dummyAppRoot = path.resolve(__dirname, "..", "..", "example")
16
- /** @type {string | undefined} */
17
- this.originalCwd = undefined
18
- this.started = false
19
- }
20
-
21
- /** @returns {Promise<void>} */
22
- async start() {
23
- if (this.started) return
24
-
25
- this.originalCwd = process.cwd()
26
- await this.ensureDistFolder()
27
- process.chdir(this.dummyAppRoot)
28
- process.env.SYSTEM_TEST_HOST ||= this.host
29
- this.started = true
30
- }
31
-
32
- /** @returns {Promise<void>} */
33
- async stop() {
34
- if (!this.started) return
35
- if (this.originalCwd) process.chdir(this.originalCwd)
36
- this.started = false
37
- }
38
-
39
- /** @returns {Promise<void>} */
40
- async ensureDistFolder() {
41
- const distPath = path.join(this.dummyAppRoot, "dist")
42
-
43
- try {
44
- const stats = await fs.stat(distPath)
45
- if (!stats.isDirectory()) {
46
- throw new Error(`Expected dist path to be a directory: ${distPath}`)
47
- }
48
- } catch (error) {
49
- throw new Error(`Missing dist folder for dummy app at ${distPath}: ${error instanceof Error ? error.message : error}`)
50
- }
51
- }
52
- }
@@ -1,99 +0,0 @@
1
- // @ts-check
2
-
3
- import wait from "awaitery/build/wait.js"
4
-
5
- import SystemTest from "system-testing/build/system-test.js"
6
- import DummyHttpServerEnvironment from "./dummy-http-server.js"
7
-
8
- const globalState = /** @type {any} */ (globalThis)
9
- const sharedState = globalState.__systemTestHelperState ??= {
10
- refCount: 0,
11
- started: false,
12
- /** @type {SystemTest | undefined} */
13
- systemTest: undefined,
14
- dummyHttpServerEnvironment: new DummyHttpServerEnvironment()
15
- }
16
-
17
- export default class SystemTestHelper {
18
- constructor({debug = process.env.SYSTEM_TEST_DEBUG === "true"} = {}) {
19
- this.debug = debug
20
- this.dummyHttpServerEnvironment = sharedState.dummyHttpServerEnvironment
21
- this.systemTest = sharedState.systemTest
22
- }
23
-
24
- /** @param {...any} args */
25
- debugLog(...args) { if (this.debug) console.log(...args) }
26
-
27
- installHooks() {
28
- beforeAll(async () => {
29
- await this.start()
30
- })
31
-
32
- afterAll(async () => {
33
- await this.stop()
34
- })
35
- }
36
-
37
- /** @returns {Promise<void>} */
38
- async start() {
39
- sharedState.refCount += 1
40
- if (sharedState.started) {
41
- this.systemTest = sharedState.systemTest
42
- return
43
- }
44
-
45
- sharedState.started = true
46
- this.debugLog("[system-test] beforeAll: starting dummy HTTP env")
47
- try {
48
- await this.dummyHttpServerEnvironment.start()
49
- await wait(1000)
50
-
51
- this.debugLog("[system-test] beforeAll: creating SystemTest")
52
- this.systemTest = SystemTest.current({
53
- debug: this.debug,
54
- host: "127.0.0.1",
55
- port: 3601,
56
- httpHost: "0.0.0.0",
57
- httpPort: 3602,
58
- errorFilter: (error) => {
59
- if (typeof error?.value?.[0] === "string" && error.value[0].includes("Uncaught Error: Minified React error #418; visit")) return false
60
- return true
61
- }
62
- })
63
- sharedState.systemTest = this.systemTest
64
- this.debugLog("[system-test] beforeAll: starting SystemTest")
65
- await this.systemTest.start()
66
- this.debugLog("[system-test] beforeAll: SystemTest started")
67
- } catch (error) {
68
- sharedState.started = false
69
- sharedState.refCount = Math.max(0, sharedState.refCount - 1)
70
- console.error("[system-test] beforeAll error", error)
71
- throw error
72
- }
73
- }
74
-
75
- /** @returns {Promise<void>} */
76
- async stop() {
77
- if (!sharedState.started) return
78
- sharedState.refCount = Math.max(0, sharedState.refCount - 1)
79
- if (sharedState.refCount > 0) return
80
-
81
- this.debugLog("[system-test] afterAll: stopping SystemTest and dummy HTTP env")
82
- try {
83
- await this.systemTest?.stop()
84
- await this.dummyHttpServerEnvironment.stop()
85
- this.debugLog("[system-test] afterAll: teardown complete")
86
- sharedState.started = false
87
- sharedState.systemTest = undefined
88
- } catch (error) {
89
- console.error("[system-test] afterAll error", error)
90
- throw error
91
- }
92
- }
93
-
94
- /** @returns {SystemTest} */
95
- getSystemTest() {
96
- if (!this.systemTest) throw new Error("SystemTest hasn't been started yet")
97
- return this.systemTest
98
- }
99
- }
@@ -1,10 +0,0 @@
1
- if (!globalThis.flashNotificationsConfiguration) {
2
- globalThis.flashNotificationsConfiguration = {
3
- debug: false,
4
- translate: (msgId, args) => args?.defaultValue || msgId
5
- }
6
- }
7
-
8
- const configuration = globalThis.flashNotificationsConfiguration
9
-
10
- export default configuration