caroso1222 / notyf

👻 A minimalistic, responsive, vanilla JavaScript library to show toast notifications.

Home Page:https://carlosroso.com/notyf/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature Request] Config option for a custom node to attach toast notifications

calebbergman opened this issue · comments

I have a vite project that utilizes postcss-scopify to scope styles to the application. This has the side effect of scoping 3rd party node_module package styles as well, such as notyf, which is generally ok. However, due to the fact that notyf defaults attaching the toast 'view' directly to the body, this leaves the toasts document fragment non-targetable by the postcss-scopify modified stylesheet selectors.

document.body.appendChild(docFrag);

One solution would be to have postcss-scopify ignore certain files, which I would love to be able to do, but alas I'm not that smart to figure out how to accomplish such a feat using the postcss.config.js file. One may be able to by some other means (such as in vite.config.ts) but I have not discovered this quite yet. See vite issue 4653

Another option would be to be allowed to manage where the toasts get attached to in the DOM, as this feature request suggests, either by passing a querySelector string or DOM Node. This would ensure that toasts get attached as a child to where they've been scoped to by postcss-scopify.

As a work around you can take advantage of dynamic module imports to re-create the original stylesheet at runtime. Not ideal, but works - while debugging, that is. See next comment for better solution.

import { Notyf } from 'notyf'
// import 'notyf/notyf.min.css'

import('notyf/notyf.min.css').then((module) => {
  // Remove scoped stylesheet from DOM
  const children = Array.from(document.head.childNodes)
  const scopedCss = children.reverse().find(c => c.textContent?.match(/notyf/))
  if (scopedCss)
    document.head.removeChild(scopedCss)
  
  // Remove scope from css
  const pattern = new RegExp('#my-custom-app-scope', 'gi')
  const css = module.default.replace(pattern, '')
  // Append updated stylesheet to DOM
  const style = document.createElement('style')
  style.setAttribute('type', 'text/css')
  style.setAttribute('id', 'notyf-stylesheet')
  style.innerText = css
  document.head.appendChild(style)
})

export default new Notyf({
  dismissible: true,
  duration: 5000,
})

The above worked fine while debugging. Post build, when everything was bundled up, not-so-much. After some more Rollup/Vite learning, I came up with the following plugin to selectively undo postcss-scopify's affects.

// rollup-plugin-postcss-unscopify.js
export default function postCssUnscopify(options = {}) {
  const { patterns, scope } = options
  return {
    name: 'postcss-unscopify',

    transform(src, id) {
      const match = patterns.reduce((result, cur) => result || !!cur.test(id), false)
      if (match) {
        const regex = new RegExp(scope, 'gi')
        return {
          code: src.replace(regex, ''),
          map: null
        }
      }
    }
  }
}
// vite.config.js
import postCssUnscopify from './rollup-plugin-postcss-unscopify'
export default defineConfig({
  plugins: [
    postCssUnscopify({
      scope: '#my-custom-scope',
      patterns: [/.*ignore-me.*css/]
    })
  ]
})