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 🙏

© 2026 – Pkg Stats / Ryan Hefner

lumen-tour

v0.3.0

Published

Lightweight zero-dependency product tour / onboarding guide. TypeScript + native CSS.

Readme

lumen-tour

轻量级、零依赖的产品引导(Product Tour / Onboarding Guide)库。TypeScript + 原生 CSS,不依赖任何框架,可在 Vanilla / React / Vue 等任意项目中使用。

特性

  • 🪶 零依赖:无运行时依赖,打包体积小
  • 🎯 自动定位:卡片自动选择目标下方/上方,放不下自动翻转,支持手动指定方向
  • ⌨️ 键盘导航:→ 下一步、← 上一步、Esc 跳过
  • 🎨 可定制:按钮文案、遮罩颜色、挖孔边距均可配置;支持完全自定义卡片内容
  • 🔄 跟随重定位:resize / scroll(含嵌套滚动容器)时自动跟随目标
  • 🧩 步骤自动跳过:target 无法解析的步骤自动跳过,不中断引导

安装

npm install lumen-tour

引入样式(引导卡片的默认样式):

import 'lumen-tour/style.css';

快速开始

import { createTour } from 'lumen-tour';
import 'lumen-tour/style.css';

const tour = createTour({
  steps: [
    {
      target: '#logo',               // CSS 选择器或 HTMLElement
      title: '欢迎来到 Lumen',
      description: '这里是 logo,点击可返回首页。',
      media: '/img/step1.png'        // 可选插图
    },
    {
      target: document.querySelector('#menu')!,
      title: '导航菜单',
      description: '在这里切换功能模块。',
      placement: 'right'             // 可选:手动指定卡片方向
    }
  ],
  onNext: async (ctx) => {
    // 异步校验示例:返回 false 阻止前进
    const ok = await validateStep(ctx.index);
    return ok;
  },
  onFinish: () => {
    console.log('引导完成');
  }
});

tour.start();

API

createTour(options: TourOptions): TourInstance

创建引导实例。

TourOptions

| 属性 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | steps | TourStep[] | (必填) | 引导步骤列表 | | texts | Partial<ButtonTexts> | 见下 | 覆盖按钮文案 | | overlayColor | string | rgba(0,0,0,0.5) | 遮罩颜色 | | padding | number \| number[] | 8 | 挖孔相对目标元素的内边距(px),CSS 风格简写:number/[v] 四周等距,[t, h] 上下 t、左右 h,[t, h, b] 上 t、左右 h、下 b,[t, r, b, l] 上/右/下/左独立控制 | | hideSkipOnLast | boolean | false | 到达最后一步时是否隐藏"跳过"按钮 | | keyboard | boolean | true | 是否启用键盘导航(→ 下一步、← 上一步、Esc 跳过) | | onNext | (ctx) => void \| boolean \| Promise<void \| boolean> | — | 点击"下一步"时触发;返回 false 可阻止前进(支持异步校验) | | onPrev | (ctx) => void | — | 点击"上一步"时触发 | | onSkip | (ctx) => void | — | 点击"跳过"或按 Esc 时触发 | | onFinish | (ctx) => void | — | 引导完成(最后一步点"完成")或所有步骤无效结束时触发 | | onStepChange | (ctx) => void | — | 每次切换到新步骤后触发 |

TourStep

| 属性 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | target | string \| HTMLElement | (必填) | 目标元素,CSS 选择器或元素本身 | | title | string | — | 卡片标题,支持受限 HTML(经白名单清洗,见下) | | description | string | — | 卡片描述文本,支持受限 HTML(经白名单清洗,见下) | | media | string | — | 卡片顶部插图 URL | | placement | Placement | 自动 | 卡片相对目标的方向,共 12 个:基础方向 'bottom' \| 'top' \| 'left' \| 'right'(贴边 + 交叉轴居中);组合方向 'topLeft' \| 'topRight' \| 'bottomLeft' \| 'bottomRight'(贴上/下边,左/右缘对齐目标)与 'leftTop' \| 'leftBottom' \| 'rightTop' \| 'rightBottom'(贴左/右边,上/下缘对齐目标)。不传则自动(下方优先,放不下翻转上方);指定方向主轴放不下时回退自动策略 | | renderMedia | (container, ctx) => void | — | 传入则完全接管卡片插图区(替代 media 图片),可渲染视频等任意 HTML | | renderContent | (container, ctx) => void | — | 传入则完全接管卡片内容区(按钮区除外),可渲染任意 HTML |

注意:media / title / description 仅在未传 renderContent 时生效;renderContent 优先级最高;renderMedia 优先于 media,且不受 renderContent 影响(需接管整个卡片请用 renderContent)。

title / description 的富文本与 XSS 防护

title 与 description 支持直接渲染 HTML(可加粗、插图、超链接等),但在渲染前会经过白名单消毒,剥离脚本与攻击向量:

  • 允许的标签:a b strong i em u ins s del strike code kbd pre span div p br hr ul ol li blockquote q cite h1-h6 img sub sup mark small abbr figure figcaption 等;其余标签解包保留文本,script/iframe/object/embed/svg/template/form 等危险标签连同内容一并删除。
  • 允许的属性:href src alt title class style target rel width height 等;所有 on* 事件处理器属性一律移除。
  • 协议白名单:href/src 仅放行 http(s)、相对路径、锚点、mailto/tel;javascript:/vbscript:/file:、data:text/、data:image/svg 等危险协议清空(img 的 data:image/png|jpeg|gif|webp 放行)。
  • 内联 style 清洗:阻断 expression()、-moz-binding、behavior、url(javascript:) 等 CSS 注入;外链 <a target="_blank"> 自动补 noopener noreferrer。

若需渲染不受限的 HTML,请改用 renderContent 自行控制(注意自行处理 XSS)。

ButtonTexts

| 属性 | 默认值 | | --- | --- | | prev | '上一步' | | next | '下一步' | | skip | '跳过' | | finish | '完成' |

StepContext

传给所有回调与 renderContent 的上下文:

| 属性 | 类型 | 说明 | | --- | --- | --- | | index | number | 当前步索引(从 0 开始) | | total | number | 总步数 | | step | TourStep | 当前步骤配置 |

TourInstance 方法

| 方法 | 说明 | | --- | --- | | start() | 启动引导(从第一个有效步骤开始;可重复调用,已启动则忽略) | | next() | 前进到下一步(受 onNext 校验约束) | | prev() | 返回上一步 | | skip() | 跳过引导并触发 onSkip | | finish() | 结束引导并触发 onFinish | | goTo(index) | 跳转到指定步骤(越界忽略) | | destroy() | 销毁实例并移除 DOM;之后不可再用,需重新 createTour() |

事件与回调说明

  • onNext 拦截:返回 false(或 Promise<false>)时停留在当前步。等待异步结果期间重复点击会被防重入,且用户若已 skip/finish/导航离开则不再前进。
  • 步骤自动跳过:某步 target 在文档中找不到时会跳到下一个有效步骤;所有步骤都无效时直接结束并触发 onFinish。
  • destroy 后调用:任何实例方法都会抛错,提示重新 createTour()。

自定义卡片内容

const tour = createTour({
  steps: [
    {
      target: '#upload',
      renderContent(container, ctx) {
        container.innerHTML = `
          <h3>上传文件(${ctx.index + 1}/${ctx.total})</h3>
          <p>支持拖拽上传,单文件不超过 100MB。</p>
          <video src="/demo.mp4" controls></video>
        `;
      }
    }
  ]
});

开发

npm run dev      # 启动 demo 页
npm test         # 运行测试(vitest)
npm run build    # 构建产物到 dist/

License

MIT