npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@darkui/popup

v0.0.7

Published

* 基于react弹窗组件 * 支持自定义进场离场动画 * 支持自定义弹窗背景效果 * 支持top,left,right,bottom方向弹出 * 支持Show命令式调用 * 支持弹窗队列功能 * 提供toast/dialog/actionSheet,ui组件 * 提供核心api,自定义拓展任意框架/ui 弹窗组件的Show/Queue功能

Downloads

4

Readme

Popup

  • 基于react弹窗组件
  • 支持自定义进场离场动画
  • 支持自定义弹窗背景效果
  • 支持top,left,right,bottom方向弹出
  • 支持Show命令式调用
  • 支持弹窗队列功能
  • 提供toast/dialog/actionSheet,ui组件
  • 提供核心api,自定义拓展任意框架/ui 弹窗组件的Show/Queue功能

中文文档

$ 中文文档

快速安装

npm i @darkui/popup --save

引入样式

// 引入样式文件
import "@darkui/popup/es/style.css";

## 基础模式调用
```tsx
import React, { useState } from 'react';

import { Popup } from '@darkui/popup';

export default () => {

  const [visibility, setVisibility] = useState(false)

  return <div>

    <button onClick={() => setVisibility(true)}>打开弹窗</button>
    <Popup
      visibility={visibility}
      onCancel={() => setVisibility(false)}
      borderRadius={10}
    >
      <div style={{padding:'20px 30px'}}>
        Hello,world
      </div>
    </Popup>
  </div>

}
自定义背景元素

Popup中接受一个bg字段,bg可以为一个颜色字符串,又或者为一个jsx函数 当遇到背景不只是颜色而参杂着元素时候,可以通过传入一个jsx函数形式替换Popup原有的背景

type bg = string | () => JSX.Element;

<Popup
  visibility={visibility}
  onCancel={() => {
    setVisibility(false);
  }}
  bg={() => <div style={{
    width: '100%',
    height: '100%',
    background: 'rgba(0,0,0,0.4)',
    backdropFilter: 'blur(10px)'
  }}>

  </div>}
  ></Popup>

当bg为函数时,会接受一个status('enter'|'leave')参数,status为进场或者立场状态

export default {
  bg: (status: 'enter'|'leave') => {
    const animation =
          status === 'enter' ? styles['bg-enter-animation'] : styles['bg-leave-animation'];
    return <div style={{ animation: `${animation} .4s linear forwards`, }} />
  }
}
自定义进场离场动画

Popup接收一个animation字段用于自定义进场离场动画功能 需注意:如果是队列queue模式下,只有最后一个会触发离场动画 bgDuration为背景的过滤时间,如果自定义了背景元素,此属性不在生效

interface Animate {
  animation?: string;
  bgDuration?: number;
}
<Popup
  visibility={false}
  onCancel={() => {
    // setVisibility(false);
  }}
  animate={{
    enter: {
      animation: styles['test-enter-animation']+' .3s forwards',
      bgDuration: 300,
    },
    leave: {
      animation: styles['test-leave-animation']+' .3s forwards',
      bgDuration: 4000,
    }
  }}
  ></Popup>
接入animate.css

animate.css地址https://animate.style/ Popup默认采用的是animation形式动画,animate.css默认是class绑定动画,如果要在Popup中使用animate动画,需要传入css库中的动画name

<Popup
  visibility={false}
  onCancel={() => {
    // setVisibility(false);
  }}
  animate={{
    enter: {
      animation: 'flipInX .3s',
      bgDuration: 300,
    },
    leave: {
      animation: 'flipOutX .3s',
      bgDuration: 4000,
    }
  }}
  ></Popup>

接收参数

Show 命令式 基础使用

Show方法返回一个promise对象,promise的值为instance

Show与常规弹窗不同,当通过此方法打开一个弹窗之后,如果再次调用Show方法,默认情况下第一个弹窗会缓存下来当关闭第二个弹窗时候,会从新打开第一个弹窗,这不是一个Bug,可以通过传递replacetrue来阻止此特征,或者第二个弹窗关闭时候调用interface.closeAll()

/* eslint-disable */
import React from 'react';

import { Show } from '@darkui/popup';

export default () => {

  const popup1 = async (direction?: any) => {
    const instance = await Show({
      direction,
      content: () => <h1 style={{color:'#666'}}>测试1-content</h1>,
      onCancel() {
        instance.close();
      },
    });
  };

  return <div>

    <button onClick={() => popup1()}>打开弹窗</button>
  </div>

}
自定义关闭弹窗行为

Show方式如果需要自定义关闭弹窗行为,可通过onCancel事件 onCancel接收instance参数,与Show返回的instance一致

Show({
  onCancel(instance) {
    alert('自定义弹窗')
    instance.close();
  },
  content: () => <div>自定义弹窗关闭</div>
})

instance

通过Show会返回一个instance对象,此对象为当前弹窗内容的实例,可以用来控制关闭当前弹窗

import React from 'react';
function createPopup(text: string) {
  return Show({
      content: <h1>{text}</h1>
    });
}
const instanceList = [];
instanceList.push(await createPopup('第一个弹窗'));
setTimeout(async () => {
  instanceList.push(await createPopup('第二个弹窗'));
}, 1000)
setTimeout(async () => {
  instanceList[1].close();
  // 此时弹窗3关闭时候,会返回到第一个弹窗
  instanceList.push(await createPopup('第三个弹窗'));
}, 2000)

关于instance的属性如下

export interface AlterInstance {
  /** 当前弹窗的key */
  key: string;
  /** 关闭当前弹窗 */
  close: () => void;
  /** 关闭某一个弹窗 */
  closeTo: (instance: AlterInstance) => void;
  /** 关闭所有弹窗 */
  closeAll: () => void;
  /** 当前弹窗的属性 */
  props: any;
  /**
   * 当前弹窗控制器
   */
  controller: ShowController;
}

Show接收第二个参数为当前弹窗的队列控制器

interface Options {
  controller?: ShowController;
  keep?: boolean;
}

默认情况下,所有的Show都还在同一个controller中运行,当已经打开一个弹窗,需要在从新打开一个新弹窗,但是又不关闭当前弹窗时候,可以通过传入一个新的controller形式调用

const controller = new ShowController();
Show({

}, { controller })

Options.keep表示是否后续的弹窗都运行在传日的控制器当中

接收参数

Show基本参数与Popup保持一致,但是不包含onConfirm/visibility

Queue 队列

队列形式,是基于Show的二次封装,通过传入多个参数形式,管理展示弹窗 适用于复杂弹窗队列显示,每个弹窗都可以获取到前面所有抛出的内容信息

import { getQueueInfo, Queue } from '@darkui/popup';
Queue([
      {
        options: {
          onCancel() {
            const instance = getQueueInfo();
            instance.$close('第一个弹窗发出的参数');
          },
        },
        render: () => {
          const instance = getQueueInfo();
          return (
            <div>
              <h1>aaaa</h1>
              <button
                onClick={() => {
                  instance.$jump(2, 222);
                }}
              >
                跳到ccc
              </button>
              <button
                onClick={() => {
                  toast('已添加,点击空白处,跳到下一个弹窗');
                  instance.$replace(() => <div>替换的弹窗</div>, 1);
                }}
              >
                替换二为新的弹窗
              </button>
              <button
                onClick={() => {
                  toast('已添加,点击空白处,跳到下一个弹窗');
                  instance.$append(() => <div>新的弹窗</div>, 1);
                }}
              >
                插入一个新的弹窗
              </button>
            </div>
          );
        },
      },
      () => {
        const instance = getQueueInfo();
        return (
          <div>
            <h1>bbbb</h1>
            <button
              onClick={() => {
                instance.$close();
              }}
            >
              手动调到下一个
            </button>
            <br />
            <button
              onClick={() => {
                instance.$closeAll();
              }}
            >
              关闭全部
            </button>
          </div>
        );
      },
      () => {
        const instance = getQueueInfo();
        console.log(instance);
        return <h1>cccc</h1>;
      },
      () => <h1>dddd</h1>,
    ]).then((result) => {
      console.log(result);
      toast('关闭了所有');
    });

Queue接收一个队列,并返回一个promise对象

type RenderFn = (props: any) => JSX.Element;
interface QueueItem {
  /** Popup.show的所选参数 */
  options?: Omit<PopupAlterInterface, 'content'>;
  props?: Record<string, any>;
  /**
   * 渲染函数
   */
  render: RenderFn;
}

useQueueInfo

在使用Popup.queue时候,Popup.queue对外抛出了一个useQueueInfo的钩子,通过useQueueInfo可以获取到当前弹窗的实例,以及上一个弹窗所返回的内容,同时可以指定传给下一个弹窗的内容 useQueueInfo并非完全意义上的react hook,它也可以被用在options的onCancel中 考虑到eslint问题,会导致useQueueInfo在普通fun报错,因此拓展了getQueueInfo函数以便使用

const useQueueInfo: () => {
  /** 当前弹窗的实例对象 */
  // instance: AlterInstance;
  /** key */
  $key: string;
  /** 上一个弹窗发出的信息 */
  message?: any[];
  /** 上一个弹窗的实例 */
  // prevInstance: AlterInstance;
  /** 向下一个弹窗传递参数 */
  $close: (data?: any) => void;
  $controller: ShowController;

  $append: (data, index) => void;
  /** 关闭当前弹窗 */
  $close: () => void;
  /** 关闭所有的弹窗 */
  $closeAll: () => void;
  $getCurrentQueue: () => any;
  /** 跳转到指定弹窗,message为下一个弹窗接收的消息 */
  $jump: (index, message) => void;
  /** 删除指定弹窗 */
  $remove: (index) => void;
  /** 替换指定弹窗,data为弹窗信息 */
  $replace: (index, data) => void;
  /** 停止弹窗队列,result为.catch接收的异常消息 */
  $stop: (result) => void;
  /** 虽有队列弹窗所抛出的信息 */
  message: any[];
  props: {options: any, render: () => JSX.Element}
}

自定义关闭处理

在队列中想要控制用户点击黑色背景部分逻辑时候可以通过添加options.onCancel方法来实现

const testDemo = Queue([
  {
    options: {
      onCancel() {
        const result = useQueueInfo();
        result.$close({
          // 传参数
          type: 'cancel',
          other: { xxx: 'xxx' }
        })
      }
    },
    render: () => <div></div>
  },
  () => {
    const info = useQueueInfo();
    return <div>{JSON.stringify(info.message)}</div>
  }
])

ShowController 控制器

ShowController是Show方法中最核心的逻辑,继承自ShowControllerCore,拓展ShowControllerCore实现了react框架下的Popup组件的命令式调用 Show方法的本质是,通过创建一个ShowController对象,调用ShowController内的append/replace方法,向控制器追加弹窗内容,以此形式来实现弹窗控制。

基础调用
import { ShowController, CreateRoot  } from ".."
const controller = new ShowController(
  CreateRoot(), 
  { destory: false }
);
controller.append({
  content: <div>Hello,world</div>
});

ShowController共接收两个参数,皆为可选参数,第一个参数为基础弹窗组件,第二个为控制器配置 CreateRoot是组件内置react版本的弹窗底层组件,可以通过CreateRoot来兼容市面上其他的react 弹窗ui库 第二个参数暂时只有destory字段,用于设置控制器是否自动销毁

demo: 通过ShowControllerCore兼容vue3框架的modal

这里选择的是vue3版本的vant ui

import { CreateRoot } from '@maui/popup/es/show/vue';
import { ShowControllerCore } from '@maui/popup/es/show';
// 继承核心控制器,写入vue3框架核心创建于销毁方法
class VueShowController extends ShowControllerCore {
  unmount() {
    this.$other.$app.unmount();
  }
  createRoot() {
    const { createApp, h } = Vue;
    this.$other.$app = createApp(
      h(this.Root, {
        controller: this,
        onDestory: () => {
          if (this.options.destory !== false) {
            this.destory();
          }
        },
      }),
    );
    this.$other.$app.mount(this.$el);
    return this;
  }
}

// 通过CreateRoot以及createShow创建vue3+vant modal的命令方法
function createVueShow() {
  // 需要注意vue3版本与react版本使用不同的CreateRoot
  const Root = CreateRoot({
    visibilityName: 'show',
    cancelEventName: 'onClickOverlay',
    destoryEventName: 'onClosed',
    component: vant.Popup as any,
  });
  return createShow<{
    round?: boolean;
    transition?: string;
    style?: any;
    content: any;
  }>(Root, VueShowController);
}

CreateRoot

CreateRoot作为一个中转站,处理了不同ui 之前变量以及事件名各不相同的弊端,通过传入当前ui的变量名称,内部会进行重新调整,以保证符合Popup的运行 以下为CreateRoot所接受的参数

export interface ShowPopupProps {
  format?: (props: any) => any;
  controller?: ShowController;
  onDestory?: () => void;
  component?: ReactElement<any, any>;
  cancelEventName?: string;
  destoryEventName?: string;
  visibilityName?: string;
  other?: any;
}
const Root = CreateRoot(props: ShowPopupProps);
const controller = new ShowController(Root);

当前项目中暂时只有react以及vue3版本,其他版本会在后续中补充