From bdd9d94a46898997b63f9c5f81a7822f62e9dcdc Mon Sep 17 00:00:00 2001 From: smastrom Date: Tue, 24 Mar 2026 17:21:45 +0100 Subject: [PATCH 01/68] Pkg - Upgrade monorepo stack (tsdown, Nuxt 4, Astro 5, oxfmt) * Core - Refactor createStore; Nuxt module compatibility for v4 * Pkg - Build notivue with tsdown; watch keeps dist for workspace consumers * Pkg - Refresh devDependencies and exports; remove Vite lib config * Root - pnpm 9, oxfmt, lint-staged; remove Prettier; ignore .cursor * Playground - Nuxt 4, luxon optimizeDeps, Vite build options * Tests - Cypress 15; Vite 7 for component testing with Astro/Vite toolchain * Astro - Astro 5.18, integrations v5, vite ssr.noExternal for notivue Co-authored-by: Cursor --- .gitignore | 1 + .oxfmtrc.json | 13 +++ .prettierrc | 24 ----- CODE_OF_CONDUCT.md | 30 +++---- README.md | 98 ++++++++++----------- astro-playground/astro.config.mjs | 5 +- astro-playground/package.json | 20 ++--- astro-playground/src/styles/reset.css | 3 +- package.json | 33 +++---- packages/notivue/core/createStore.ts | 19 ++-- packages/notivue/nuxt/README.md | 88 +++++++++--------- packages/notivue/nuxt/module.mjs | 2 +- packages/notivue/package.json | 69 +++++++-------- packages/notivue/tsconfig.json | 2 +- packages/notivue/tsdown.config.ts | 66 ++++++++++++++ packages/notivue/vite.config.ts | 77 ---------------- playground/nuxt.config.ts | 21 ++--- playground/package.json | 18 ++-- tests/Notivue/config-pause-on-hover.cy.ts | 6 -- tests/Notivue/config-pause-on-touch.cy.ts | 6 -- tests/NotivueKeyboard/actions.cy.ts | 4 - tests/NotivueKeyboard/entering-stream.cy.ts | 1 - tests/NotivueKeyboard/leaving-stream.cy.ts | 1 - tests/NotivueKeyboard/queue.cy.ts | 2 - tests/package.json | 25 +++--- tests/tsconfig.json | 2 +- 26 files changed, 300 insertions(+), 336 deletions(-) create mode 100644 .oxfmtrc.json delete mode 100644 .prettierrc create mode 100644 packages/notivue/tsdown.config.ts delete mode 100644 packages/notivue/vite.config.ts diff --git a/.gitignore b/.gitignore index 00e1d7a7..97af418e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ pnpm-debug.log* .vscode .idea +.cursor .DS_Store node_modules diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 00000000..71b1e70c --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,13 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "printWidth": 100, + "semi": false, + "singleQuote": true, + "tabWidth": 3, + "trailingComma": "es5", + "useTabs": false, + "ignorePatterns": [".vscode/**", "node_modules/**", "dist/**", "target/**"], + "sortPackageJson": { + "sortScripts": true + } +} diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 192e0d23..00000000 --- a/.prettierrc +++ /dev/null @@ -1,24 +0,0 @@ -{ - "printWidth": 100, - "semi": false, - "singleQuote": true, - "tabWidth": 3, - "trailingComma": "es5", - "useTabs": false, - "plugins": ["prettier-plugin-astro"], - "overrides": [ - { - "files": "README.md", - "options": { - "tabWidth": 2, - "trailingComma": "none", - "printWidth": 90 - } - }, { - "files": "*.astro", - "options": { - "parser": "astro" - } - } - ] -} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 96a930ba..2e5d313c 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -17,24 +17,24 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -- Demonstrating empathy and kindness toward other people -- Being respectful of differing opinions, viewpoints, and experiences -- Giving and gracefully accepting constructive feedback -- Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -- Focusing on what is best not just for us as individuals, but for the - overall community +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the + overall community Examples of unacceptable behavior include: -- The use of sexualized language or imagery, and sexual attention or - advances of any kind -- Trolling, insulting or derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or email - address, without their explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery, and sexual attention or + advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email + address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Enforcement Responsibilities diff --git a/README.md b/README.md index 1fbb5bf9..ab57b461 100644 --- a/README.md +++ b/README.md @@ -92,13 +92,13 @@ import { Notivue, Notification, push } from 'notivue' ``` @@ -111,37 +111,37 @@ import { Notivue, push } from 'notivue' ``` @@ -155,14 +155,14 @@ import { Notivue, push } from 'notivue' ```ts export default defineNuxtConfig({ - modules: ['notivue/nuxt'], - css: [ - 'notivue/notification.css', // Only needed if using built-in - 'notivue/animations.css' // Only needed if using default animations - ], - notivue: { - // Options - } + modules: ['notivue/nuxt'], + css: [ + 'notivue/notification.css', // Only needed if using built-in + 'notivue/animations.css', // Only needed if using default animations + ], + notivue: { + // Options + }, }) ``` @@ -170,13 +170,13 @@ export default defineNuxtConfig({ ```vue ``` diff --git a/astro-playground/astro.config.mjs b/astro-playground/astro.config.mjs index c662b2b3..d8fad88a 100644 --- a/astro-playground/astro.config.mjs +++ b/astro-playground/astro.config.mjs @@ -13,7 +13,10 @@ export default defineConfig({ ], vite: { optimizeDeps: { - include: ['notivue'], + include: ['notivue', 'notivue/astro'], + }, + ssr: { + noExternal: ['notivue'], }, }, }) diff --git a/astro-playground/package.json b/astro-playground/package.json index d6cf642c..79c0f674 100644 --- a/astro-playground/package.json +++ b/astro-playground/package.json @@ -1,25 +1,25 @@ { "name": "notivue-astro-playground", - "type": "module", "private": true, + "type": "module", "scripts": { - "dev": "astro dev", - "start": "astro dev", + "astro": "astro", "build": "astro build", + "dev": "astro dev", "preview": "astro preview", - "astro": "astro" + "start": "astro dev" }, "dependencies": { - "@astrojs/react": "^3.6.2", - "@astrojs/vue": "^4.5.0", - "astro": "^4.15.1", + "@astrojs/react": "^5.0.1", + "@astrojs/vue": "^5.1.4", + "astro": "^5.18.1", "notivue": "workspace:*", "react": "^18.3.1", "react-dom": "^18.3.1", - "vue": "^3.4.30" + "vue": "^3.5.30" }, "devDependencies": { - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0" + "@types/react": "^18.3.28", + "@types/react-dom": "^18.3.7" } } diff --git a/astro-playground/src/styles/reset.css b/astro-playground/src/styles/reset.css index ded5d7de..7e3fc53f 100644 --- a/astro-playground/src/styles/reset.css +++ b/astro-playground/src/styles/reset.css @@ -8,7 +8,8 @@ } html { - font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', + font-family: + system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; } diff --git a/package.json b/package.json index b7c6044c..d5e957d3 100644 --- a/package.json +++ b/package.json @@ -1,28 +1,29 @@ { "name": "notivue-monorepo", "private": true, - "packageManager": "pnpm@8.14.3", - "engines": { - "node": ">=20.0.0" - }, "scripts": { - "dev": "pnpm build && concurrently \"pnpm -C packages/notivue run watch\" \"pnpm -C playground install && pnpm -C playground run dev --host\"", - "dev:astro": "pnpm build && concurrently \"pnpm -C packages/notivue run watch\" \"pnpm -C astro-playground install && pnpm -C astro-playground run dev --host\"", "build": "pnpm -C packages/notivue run build", "build:playground": "pnpm build && pnpm install && pnpm -C playground run build", + "dev": "pnpm build && concurrently \"pnpm -C packages/notivue run watch\" \"pnpm -C playground run dev --host\"", + "dev:astro": "pnpm build && concurrently \"pnpm -C packages/notivue run watch\" \"pnpm -C astro-playground run dev --host\"", + "format": "oxfmt .", + "format:check": "oxfmt --check .", + "prepare": "husky", "test": "pnpm build && pnpm install && pnpm -C tests run test", - "test:gui": "pnpm build && concurrently \"pnpm -C packages/notivue run watch\" \"pnpm -C tests install && pnpm -C tests run test:gui\"", - "test:unit": "pnpm -C tests run test:unit", - "prepare": "husky" + "test:gui": "pnpm build && concurrently \"pnpm -C packages/notivue run watch\" \"pnpm -C tests run test:gui\"", + "test:unit": "pnpm -C tests run test:unit" }, "devDependencies": { - "concurrently": "^8.2.2", - "husky": "^9.1.5", - "lint-staged": "^15.2.9", - "prettier": "^3.3.3", - "prettier-plugin-astro": "^0.14.1" + "concurrently": "^9.1.2", + "husky": "^9.1.7", + "lint-staged": "^15.4.3", + "oxfmt": "^0.42.0" }, "lint-staged": { - "*.{js,ts,vue,json,css,md}": "prettier --write" - } + "*.{js,ts,mts,cts,mjs,cjs,vue,json,css,md}": "oxfmt --write" + }, + "engines": { + "node": ">=20.19.0" + }, + "packageManager": "pnpm@9.15.9" } diff --git a/packages/notivue/core/createStore.ts b/packages/notivue/core/createStore.ts index b42c8d80..d5c750c1 100644 --- a/packages/notivue/core/createStore.ts +++ b/packages/notivue/core/createStore.ts @@ -56,7 +56,9 @@ export function createConfig(userConfig: NotivueConfig, isRunning: Readonly - unref(e.message).replace(/\uFEFF/g, '') === unref(item.message).replace(/\uFEFF/g, '') && // prettier-ignore - unref(e.title) === unref(item.title) && - e.type === item.type - ) + return this.entries.value.find((e) => { + const sameMessage = + unref(e.message).replace(/\uFEFF/g, '') === + unref(item.message).replace(/\uFEFF/g, '') + return sameMessage && unref(e.title) === unref(item.title) && e.type === item.type + }) }, get(id: string) { return this.entries.value.find((e) => e.id === id) @@ -256,7 +258,8 @@ export function createAnimations( const id = el.dataset.notivueItem! const item = items.get(id) - if (!el || !item || item.animationAttrs.class === leaveClass) continue // prettier-ignore + if (!el || !item) continue + if (item.animationAttrs.class === leaveClass) continue items.update(id, { positionStyles: { diff --git a/packages/notivue/nuxt/README.md b/packages/notivue/nuxt/README.md index 92610e44..def00063 100644 --- a/packages/notivue/nuxt/README.md +++ b/packages/notivue/nuxt/README.md @@ -65,14 +65,14 @@ pnpm add notivue ```ts export default defineNuxtConfig({ - modules: ['notivue/nuxt'], - css: [ - 'notivue/notification.css', // Only needed if using built-in - 'notivue/animations.css' // Only needed if using default animations - ], - notivue: { - // Options - } + modules: ['notivue/nuxt'], + css: [ + 'notivue/notification.css', // Only needed if using built-in + 'notivue/animations.css', // Only needed if using default animations + ], + notivue: { + // Options + }, }) ``` @@ -90,13 +90,13 @@ import type { NotivueConfig, NotivueItem /*, ... */ } from 'notivue' ```vue ``` @@ -105,37 +105,37 @@ import type { NotivueConfig, NotivueItem /*, ... */ } from 'notivue' ```vue ``` diff --git a/packages/notivue/nuxt/module.mjs b/packages/notivue/nuxt/module.mjs index a9cf2435..9a95a85b 100644 --- a/packages/notivue/nuxt/module.mjs +++ b/packages/notivue/nuxt/module.mjs @@ -8,7 +8,7 @@ const module = defineNuxtModule({ name: 'nuxt/notivue', configKey: 'notivue', compatibility: { - nuxt: '>=3.5.0', + nuxt: '>=3.5.0 || ^4.0.0', }, }, diff --git a/packages/notivue/package.json b/packages/notivue/package.json index 98e22fc1..abff63d1 100644 --- a/packages/notivue/package.json +++ b/packages/notivue/package.json @@ -4,41 +4,48 @@ "private": false, "description": "Powerful toast notification system for Vue and Nuxt", "keywords": [ - "vue", - "vuejs", - "notification", - "notifications", "alert", "alerts", + "notification", + "notifications", + "notivue", "toast", "toasts", - "notivue" + "vue", + "vuejs" ], "homepage": "https://notivue.smastrom.io/", "bugs": { "url": "https://github.com/smastrom/notivue/issues" }, - "repository": { - "type": "git", - "url": "https://github.com/smastrom/notivue.git", - "directory": "packages/notivue" - }, "license": "MIT", "author": { "name": "Simone Mastromattei", "email": "smastrom@proton.me" }, - "sideEffects": false, + "repository": { + "type": "git", + "url": "https://github.com/smastrom/notivue.git", + "directory": "packages/notivue" + }, + "files": [ + "dist/*", + "nuxt/*", + "shared/exports.js" + ], "type": "module", + "sideEffects": false, + "module": "dist/index.js", + "types": "dist/index.d.ts", "exports": { ".": { "import": "./dist/index.js", "types": "./dist/index.d.ts" }, "./nuxt": { + "types": "./nuxt/index.d.ts", "import": "./nuxt/module.mjs", - "require": "./nuxt/module.cjs", - "types": "./nuxt/index.d.ts" + "require": "./nuxt/module.cjs" }, "./astro": { "import": "./dist/astro.js", @@ -55,33 +62,25 @@ "./astro/notification-progress.css": "./dist/Notifications/notifications-progress.css", "./astro/animations.css": "./dist/core/animations.css" }, - "module": "dist/index.js", - "types": "dist/index.d.ts", - "files": [ - "dist/*", - "nuxt/*", - "shared/exports.js" - ], "scripts": { - "prebuild": "cp ../../README.md ../../LICENSE .", - "build": "rm -rf dist && vue-tsc && vite build && pnpm build:css", - "postbuild": "rm -rf *.tgz && npm pack && ./scripts/verify-tarball.sh && node ./scripts/verify-exports.js", + "build": "rm -rf dist && vue-tsc --noEmit && tsdown && pnpm build:css", "build:css": "esbuild ./Notifications/notifications.css ./Notifications/notifications-progress.css ./core/animations.css --bundle --outdir=dist --minify --target=chrome58,edge16,firefox57,node12,safari11", - "watch": "rm -rf dist && concurrently \"vite build --watch\" \"pnpm build:css --watch\"" + "postbuild": "rm -rf *.tgz && npm pack && ./scripts/verify-tarball.sh && node ./scripts/verify-exports.js", + "prebuild": "cp ../../README.md ../../LICENSE .", + "watch": "concurrently \"tsdown --watch\" \"pnpm build:css --watch\"" }, "devDependencies": { - "@nuxt/kit": "^3.13.0", - "@nuxt/schema": "^3.13.0", - "@types/node": "^22.5.2", - "@vitejs/plugin-vue": "5.1.3", - "concurrently": "^8.2.2", + "@nuxt/kit": "^4.4.2", + "@nuxt/schema": "^4.4.2", + "@types/node": "^22.13.1", + "@vitejs/plugin-vue": "6.0.5", + "concurrently": "^9.1.2", "defu": "^6.1.4", - "esbuild": "^0.23.1", - "typescript": "^5.5.4", - "vite": "^5.4.2", - "vite-plugin-dts": "^4.1.0", - "vue": "3.4.38", - "vue-tsc": "^2.1.4" + "esbuild": "^0.25.12", + "tsdown": "^0.21.4", + "typescript": "^5.7.3", + "vue": "3.5.13", + "vue-tsc": "^3.2.6" }, "peerDependencies": { "@nuxt/kit": ">=3.5.0", diff --git a/packages/notivue/tsconfig.json b/packages/notivue/tsconfig.json index f69d0129..12ab1090 100644 --- a/packages/notivue/tsconfig.json +++ b/packages/notivue/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES2015", "module": "ES2020", - "moduleResolution": "Node", + "moduleResolution": "Bundler", "strict": true, "resolveJsonModule": true, "isolatedModules": true, diff --git a/packages/notivue/tsdown.config.ts b/packages/notivue/tsdown.config.ts new file mode 100644 index 00000000..1d21bfe7 --- /dev/null +++ b/packages/notivue/tsdown.config.ts @@ -0,0 +1,66 @@ +import { writeFileSync } from 'node:fs' +import { createRequire } from 'node:module' +import { fileURLToPath } from 'node:url' + +import vue from '@vitejs/plugin-vue' +import { defineConfig } from 'tsdown/config' + +const require = createRequire(import.meta.url) +const { getFunctions, getObjects, getComponents } = require('./shared/exports.js') as { + getFunctions: (o?: { omit?: string[] }) => string[] + getObjects: (o?: { omit?: string[] }) => string[] + getComponents: (o?: { omit?: string[] }) => string[] +} + +const path = (url: string) => fileURLToPath(new URL(url, import.meta.url)) + +const isWatch = process.argv.includes('--watch') + +export default defineConfig({ + entry: 'index.ts', + platform: 'browser', + target: 'es2015', + minify: isWatch + ? false + : { + compress: { + dropConsole: true, + }, + }, + // Watch must not wipe dist (e.g. monorepo dev:astro); production build still cleans via `pnpm build`. + clean: !isWatch, + outDir: 'dist', + dts: { vue: true }, + deps: { + neverBundle: ['vue'], + }, + alias: { + '@/core': path('./core'), + '@/shared': path('./shared'), + '@/Notivue': path('./Notivue'), + '@/NotivueSwipe': path('./NotivueSwipe'), + '@/NotivueKeyboard': path('./NotivueKeyboard'), + '@/Notifications': path('./Notifications'), + '@/astro': path('./astro'), + notivue: path('./index.ts'), + }, + plugins: [vue()], + hooks: { + 'build:done'() { + const astroReExports = [ + ...getFunctions({ omit: ['push', 'createNotivue'] }), + ...getComponents({ omit: ['Notivue'] }), + ...getObjects(), + ] + writeFileSync( + 'dist/astro.js', + [ + 'export { pushAstro as push } from "./index.js";', + 'export { NotivueAstro as Notivue } from "./index.js";', + 'export { createNotivueAstro as createNotivue } from "./index.js";', + ...astroReExports.map((name) => `export { ${name} } from "./index.js";`), + ].join('\n') + ) + }, + }, +}) diff --git a/packages/notivue/vite.config.ts b/packages/notivue/vite.config.ts deleted file mode 100644 index 9b40ce0d..00000000 --- a/packages/notivue/vite.config.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { defineConfig } from 'vite' -import { fileURLToPath } from 'url' -import { writeFileSync } from 'fs' - -import vue from '@vitejs/plugin-vue' -import dts from 'vite-plugin-dts' - -// @ts-ignore -import { getFunctions, getObjects, getComponents } from './shared/exports' - -const path = (url: string) => fileURLToPath(new URL(url, import.meta.url)) - -const isFinalBundle = !process.argv.includes('--watch') - -export default defineConfig({ - resolve: { - alias: { - '@/core': path('./core'), - '@/shared': path('./shared'), - '@/Notivue': path('./Notivue'), - '@/NotivueSwipe': path('./NotivueSwipe'), - '@/NotivueKeyboard': path('./NotivueKeyboard'), - '@/Notifications': path('./Notifications'), - '@/astro': path('./astro'), - notivue: path('./index.ts'), - }, - }, - esbuild: { - drop: isFinalBundle ? ['console'] : [], - minifyIdentifiers: false, - minifySyntax: false, - }, - build: { - emptyOutDir: isFinalBundle, - target: 'es2015', - minify: false, - lib: { - entry: 'index.ts', - fileName: 'index', - formats: ['es'], - }, - rollupOptions: { - external: ['vue'], - output: { - globals: { - vue: 'Vue', - }, - }, - }, - }, - plugins: [ - dts({ - rollupTypes: true, - }), - vue(), - { - name: 'write-astro-entry', - closeBundle() { - const astroReExports = [ - ...getFunctions({ omit: ['push', 'createNotivue'] }), - ...getComponents({ omit: ['Notivue'] }), - ...getObjects(), - ] - - writeFileSync( - 'dist/astro.js', - [ - 'export { pushAstro as push } from "./index.js";', - 'export { NotivueAstro as Notivue } from "./index.js";', - 'export { createNotivueAstro as createNotivue } from "./index.js";', - ...astroReExports.map((name) => `export { ${name} } from "./index.js";`), - ].join('\n') - ) - }, - }, - ], -}) diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 3109e3cb..b04277b6 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -1,6 +1,8 @@ import { getHead } from './utils/head' export default defineNuxtConfig({ + // Nuxt 4 defaults to srcDir `app/`; keep sources at project root + srcDir: '.', modules: ['notivue/nuxt'], ssr: true, devtools: { @@ -10,12 +12,8 @@ export default defineNuxtConfig({ componentIslands: true, }, notivue: { - // addPlugin: true, - // startOnCreation: true, notifications: { - global: { - // duration: Infinity, - }, + global: {}, }, }, nitro: { @@ -25,17 +23,16 @@ export default defineNuxtConfig({ head: getHead(), }, vite: { - esbuild: { - minifyIdentifiers: !import.meta.env.DEV, - minifySyntax: !import.meta.env.DEV, - }, - build: { - minify: import.meta.env.DEV ? false : 'esbuild', - cssMinify: 'lightningcss', + optimizeDeps: { + include: ['luxon'], }, css: { transformer: 'lightningcss', }, + build: { + minify: import.meta.env.DEV ? false : 'oxc', + cssMinify: 'lightningcss', + }, }, css: [ 'assets/style.css', diff --git a/playground/package.json b/playground/package.json index b6f58ca5..9ac6f7f6 100644 --- a/playground/package.json +++ b/playground/package.json @@ -5,18 +5,18 @@ "build": "nuxt build", "dev": "nuxi cleanup && nuxt dev --port=5173", "generate": "nuxt generate", - "preview": "nuxt preview", - "postinstall": "nuxt prepare" - }, - "devDependencies": { - "@types/luxon": "^3.4.2", - "@types/node": "^22.5.1", - "lightningcss": "^1.26.0", - "nuxt": "^3.13.0", - "vue": "^3.4.38" + "postinstall": "nuxt prepare", + "preview": "nuxt preview" }, "dependencies": { "luxon": "^3.5.0", "notivue": "workspace:*" + }, + "devDependencies": { + "@types/luxon": "^3.4.2", + "@types/node": "^22.13.1", + "lightningcss": "^1.29.3", + "nuxt": "^4.4.2", + "vue": "^3.5.13" } } diff --git a/tests/Notivue/config-pause-on-hover.cy.ts b/tests/Notivue/config-pause-on-hover.cy.ts index 6363cc95..ba55be98 100644 --- a/tests/Notivue/config-pause-on-hover.cy.ts +++ b/tests/Notivue/config-pause-on-hover.cy.ts @@ -10,11 +10,9 @@ describe('Pause on hover', () => { .clickRandomStatic() .wait(4000) // Remaining time 2000ms - .get('.Notification') .realMouseMove(0, 0, { position: 'center' }) .wait(4000) // Any value greater than the remaining time - .get('.Notification') .should('exist') @@ -31,11 +29,9 @@ describe('Pause on hover', () => { .clickRandomStatic() .wait(4000) // Remaining: 2000ms - .get('.Notification') .realMouseMove(0, 0, { position: 'center' }) .wait(4000) // Any value greater than the remaining time - .get('.Notification') .should('not.exist') }) @@ -48,11 +44,9 @@ describe('Pause on hover', () => { .clickRandomStatic() .wait(4000) // Remaining time 2000ms - .get('.Notification') .realMouseMove(0, 0, { position: 'center' }) .wait(4000) // Any value greater than the remaining time - .get('.Notification') .should('exist') }) diff --git a/tests/Notivue/config-pause-on-touch.cy.ts b/tests/Notivue/config-pause-on-touch.cy.ts index f57c4de5..0a432dae 100644 --- a/tests/Notivue/config-pause-on-touch.cy.ts +++ b/tests/Notivue/config-pause-on-touch.cy.ts @@ -10,11 +10,9 @@ describe('Pause on touch', () => { .clickRandomStatic() .wait(5000) // Remaining: 1000ms - .get('.Notification') .trigger('pointerdown', { pointerType: 'touch' }) .wait(2000) // More than the remaining time - .get('.Notification') .should('exist') }) @@ -24,11 +22,9 @@ describe('Pause on touch', () => { .clickRandomStatic() .wait(5000) // Remaining: 1000ms - .get('.Notification') .trigger('pointerdown', { pointerType: 'touch' }) .wait(2000) // More than the remaining time - .get('.Notification') .should('not.exist') }) @@ -41,11 +37,9 @@ describe('Pause on touch', () => { .clickRandomStatic() .wait(5000) // Remaining: 1000ms - .get('.Notification') .trigger('pointerdown', { pointerType: 'touch' }) .wait(2000) // More than the remaining time - .get('.Notification') .should('exist') }) diff --git a/tests/NotivueKeyboard/actions.cy.ts b/tests/NotivueKeyboard/actions.cy.ts index 0d8edbb9..852d6b5f 100644 --- a/tests/NotivueKeyboard/actions.cy.ts +++ b/tests/NotivueKeyboard/actions.cy.ts @@ -10,7 +10,6 @@ describe('Actions', () => { .realPress('Tab') // Go last action of first container .pushCandidateSilently() // id: 3 - .focused() .should('have.data', 'notivueContainer', 3) }) @@ -27,7 +26,6 @@ describe('Actions', () => { .realPress('Tab') .realPress('Tab') // Go to action of 2nd container (id: 1) - .realPress(Math.random() > 0.5 ? 'Space' : 'Enter') .focused() @@ -47,7 +45,6 @@ describe('Actions', () => { .realPress('Tab') .realPress('Tab') // Go to action of last container - .realPress(Math.random() > 0.5 ? 'Space' : 'Enter') cy.get('@relatedTarget').should('be.focused').checkLeaveAnnouncement() @@ -67,7 +64,6 @@ describe('Actions', () => { .realPress('Tab') .realPress('Tab') // Go to action of 2nd container - .focused() .realClick() diff --git a/tests/NotivueKeyboard/entering-stream.cy.ts b/tests/NotivueKeyboard/entering-stream.cy.ts index 38679149..5649acb3 100644 --- a/tests/NotivueKeyboard/entering-stream.cy.ts +++ b/tests/NotivueKeyboard/entering-stream.cy.ts @@ -91,7 +91,6 @@ describe('Entering the stream', () => { cy.realPress('Tab') // Leave the stream .realPress('Tab') // Try to enter again - .get('@relatedTarget') .should('be.focused') }) diff --git a/tests/NotivueKeyboard/leaving-stream.cy.ts b/tests/NotivueKeyboard/leaving-stream.cy.ts index 93130d3d..1d3f669c 100644 --- a/tests/NotivueKeyboard/leaving-stream.cy.ts +++ b/tests/NotivueKeyboard/leaving-stream.cy.ts @@ -41,7 +41,6 @@ describe('Leaving the stream', () => { } cy.realPress('Tab') // Leave the stream - .get('@relatedTarget') .should('be.focused') .checkLeaveAnnouncement() diff --git a/tests/NotivueKeyboard/queue.cy.ts b/tests/NotivueKeyboard/queue.cy.ts index 8896d8db..3e2d68ed 100644 --- a/tests/NotivueKeyboard/queue.cy.ts +++ b/tests/NotivueKeyboard/queue.cy.ts @@ -8,7 +8,6 @@ describe('Queue', () => { .realPress('Tab') .realPress('Tab') .realPress('Space') // Dismiss first candidate (id: 0) - .focused() .and('have.data', 'notivueContainer', 1) }) @@ -23,7 +22,6 @@ describe('Queue', () => { .realPress('Tab') .realPress('Tab') .realPress('Space') // Dismiss last candidate (id: 1) - .focused() .and('have.data', 'notivueContainer', 0) }) diff --git a/tests/package.json b/tests/package.json index 81ba3f9b..4b826b47 100644 --- a/tests/package.json +++ b/tests/package.json @@ -2,25 +2,26 @@ "name": "notivue-tests", "private": true, "scripts": { + "cypress:install": "cypress install", "test": "cypress run --component --browser chrome", "test:gui": "cypress open --component --browser chrome", - "test:unit": "npx vitest run" + "test:unit": "vitest run" }, "dependencies": { "notivue": "workspace:*" }, "devDependencies": { - "@types/node": "^22.5.1", - "@vitejs/plugin-vue": "^5.1.3", + "@types/node": "^22.13.1", + "@vitejs/plugin-vue": "^6.0.5", "@vue/test-utils": "^2.4.6", - "axe-core": "^4.10.0", - "cypress": "^13.14.1", - "cypress-axe": "^1.5.0", - "cypress-real-events": "^1.13.0", - "typescript": "^5.5.4", - "vite": "^5.4.2", - "vitest": "^2.0.5", - "vue": "^3.4.38", - "vue-tsc": "^2.1.4" + "axe-core": "^4.10.2", + "cypress": "^15.12.0", + "cypress-axe": "^1.6.0", + "cypress-real-events": "^1.14.0", + "typescript": "^5.7.3", + "vite": "^7.3.1", + "vitest": "^3.0.8", + "vue": "^3.5.13", + "vue-tsc": "^3.2.6" } } diff --git a/tests/tsconfig.json b/tests/tsconfig.json index d6c2911d..adc5bde2 100644 --- a/tests/tsconfig.json +++ b/tests/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES2018", "module": "ESNext", - "moduleResolution": "Node", + "moduleResolution": "Bundler", "strict": true, "resolveJsonModule": true, "isolatedModules": true, From 08223e1a887825eee9c42be4d481cd7a60aa23ac Mon Sep 17 00:00:00 2001 From: smastrom Date: Tue, 24 Mar 2026 18:02:08 +0100 Subject: [PATCH 02/68] Notification - Tip accent and progress corners (#76, #78) * CSS - Draw `--nv-tip-width` with a `::before` border instead of an inset box-shadow so radius and rounding stay clean (#78). * CSS - Use full `border-radius` when a progress bar is present and `overflow: hidden` on the card so the bar and tip stay inside the rounded shape (#76). Co-authored-by: Cursor --- .../Notifications/notifications-progress.css | 8 -------- .../notivue/Notifications/notifications.css | 20 ++++++++++--------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/packages/notivue/Notifications/notifications-progress.css b/packages/notivue/Notifications/notifications-progress.css index 53a6ba25..db5af81b 100644 --- a/packages/notivue/Notifications/notifications-progress.css +++ b/packages/notivue/Notifications/notifications-progress.css @@ -1,7 +1,5 @@ @media (prefers-reduced-motion: no-preference) { .Notivue__notification:has(.Notivue__progress) { - border-radius: var(--nv-radius, 0) var(--nv-radius, 0) var(--nv-radius, 0) 0; - & .Notivue__content-message { margin-bottom: var(--nv-progress-height, 4px); } @@ -16,17 +14,11 @@ background-color: var(--nv-accent); animation: Notivue__progress-kf var(--nv-anim-dur) linear forwards; transform-origin: left; - border-radius: 0 var(--nv-radius, 0) var(--nv-radius, 0) 0; } [dir='rtl'] { & .Notivue__progress { transform-origin: right; - border-radius: var(--nv-radius, 0) 0 0 var(--nv-radius, 0); - } - - & .Notivue__notification:has(.Notivue__progress) { - border-radius: var(--nv-radius, 0) var(--nv-radius, 0) 0 var(--nv-radius, 0); } } diff --git a/packages/notivue/Notifications/notifications.css b/packages/notivue/Notifications/notifications.css index 42b15308..b1b907d7 100644 --- a/packages/notivue/Notifications/notifications.css +++ b/packages/notivue/Notifications/notifications.css @@ -36,8 +36,6 @@ } .Notivue__notification { - --tip-width: calc(var(--tip-width-fx, 1) * var(--nv-tip-width, 0px)); - box-sizing: border-box; position: relative; width: var(--nv-min-width, auto); @@ -47,10 +45,18 @@ align-items: var(--nv-y-align); border-radius: var(--nv-radius, 0); border: var(--nv-border-width, 0) solid var(--nv-border, var(--nv-global-border)); + overflow: hidden; - box-shadow: - var(--nv-shadow, 0 0 rgba(0, 0, 0, 0)), - inset var(--tip-width) 0 0 var(--nv-accent); + box-shadow: var(--nv-shadow, 0 0 rgba(0, 0, 0, 0)); + + &::before { + content: ''; + flex-shrink: 0; + align-self: stretch; + box-sizing: border-box; + width: 0; + border-inline-start: var(--nv-tip-width, 0px) solid var(--nv-accent); + } & * { box-sizing: border-box; @@ -207,10 +213,6 @@ } [dir='rtl'] { - & .Notivue__notification { - --tip-width-fx: -1; - } - & .Notivue__icon { margin: var(--nv-spacing) var(--nv-spacing) var(--nv-spacing) 0; } From 666706eb187024bdacb3ee500bd1a0a98b558603 Mon Sep 17 00:00:00 2001 From: smastrom Date: Tue, 24 Mar 2026 18:12:00 +0100 Subject: [PATCH 03/68] Pkg - Expand README with Astro, headless example, docs pointer * Mention Astro in the tagline; add Installation callout linking to full docs. * Surface headless custom markup example outside a details block. * Add Astro section with import/CSS paths and Astro 6 not supported note. Co-authored-by: Cursor --- README.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ab57b461..e792e30a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ # Notivue -### Powerful toast notification system for Vue and Nuxt +### Powerful toast notification system for Vue, Nuxt and Astro [Live Demo](https://notivue.smastrom.io) - [Documentation](https://docs.notivue.smastrom.io) @@ -60,11 +60,13 @@ pnpm add notivue # bun i notivue ``` +> :bulb: Beyond this quick start — Nuxt/Astro setup, `push` and callbacks, stream config, built-in styling, headless mode, full API — lives in the [documentation](https://docs.notivue.smastrom.io). +
## Vite -> :bulb: See [↓ below](#nuxt) for **Nuxt** +> :bulb: See [↓ below](#nuxt) for **Nuxt** and [↓ Astro](#astro). **main.js/ts** @@ -102,8 +104,8 @@ import { Notivue, Notification, push } from 'notivue' ``` -
-Headless, with custom components +**App.vue (headless — your own markup)** +_No `notification.css` needed; wire `aria-live` / `role` and `item.clear` yourself._ ```vue