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

@yymojo-tec/mojo-ui

v1.10.0

Published

Mojo UI 是 YYmojo 旗下维护的 UI 组件库。

Readme

mojo-ui

mojo-ui 鏄竴涓熀浜?Vue 3銆乀ypeScript 鍜?Headless UI 灏佽鐨勭粍浠跺簱锛屾彁渚涙槑鏆椾袱濂椾富棰樻牱寮忋€?

瀹夎

pnpm add @yymojo-tec/mojo-ui

涔熷彲浠ヤ娇鐢?npm锛?

npm install @yymojo-tec/mojo-ui

鍏ㄩ噺寮曞叆

import { createApp } from "vue";
import MojoUi from "@yymojo-tec/mojo-ui";
import "@yymojo-tec/mojo-ui/style.css";
import App from "./App.vue";

createApp(App).use(MojoUi).mount("#app");

鎸夐渶寮曞叆

<script setup lang="ts">
import { MoButton } from "@yymojo-tec/mojo-ui";
import "@yymojo-tec/mojo-ui/style.css";
</script>

<template>
  <MoButton type="primary" theme="dark">鐢熸垚</MoButton>
</template>

涓婚

缁勪欢閫氳繃 theme 鍙傛暟鎺у埗浜壊鍜屾殫鑹诧細

<MoButton theme="light">Light</MoButton>
<MoButton theme="dark">Dark</MoButton>

缁勪欢

Button

<MoButton type="primary" round size="small">鐢熸垚闊宠壊</MoButton>

<MoButton theme="dark">
  <template #prefix>鉁?/template>
  閲嶆柊鐢熸垚
</MoButton>

<MoButton icon>
  <template #icon>鈫?/template>
</MoButton>

Row / Col

<MoRow :gutter="12">
  <MoCol :span="8">A</MoCol>
  <MoCol :span="8">B</MoCol>
  <MoCol :span="8">C</MoCol>
</MoRow>

Card

<MoCard theme="dark" shadow="hover" border-style="solid">
  鍗$墖鍐呭
</MoCard>

<MoCard theme="dark" selectable v-model:selected="selected">
  <template #selected-icon>鈾?/template>
  OrcaSlicer
</MoCard>

Form

<script setup lang="ts">
import { reactive } from "vue";
import { requiredRule, phoneRule } from "@yymojo-tec/mojo-ui";

const model = reactive({ name: "", phone: "" });
const rules = {
  name: [requiredRule("璇疯緭鍏ュ悕绉?)],
  phone: [requiredRule("璇疯緭鍏ユ墜鏈哄彿"), phoneRule()]
};
</script>

<template>
  <MoForm :model="model" :rules="rules" label-position="top">
    <MoFormItem label="鍚嶇О" prop="name" required>
      <MoInput v-model="model.name" placeholder="杈撳叆鍚嶇О" />
    </MoFormItem>
  </MoForm>
</template>

Input

<MoInput v-model="name" :maxlength="15" show-word-limit placeholder="杈撳叆鍚嶇О" />

<MoInput
  v-model="intro"
  type="textarea"
  :rows="4"
  :maxlength="1000"
  show-word-limit
  placeholder="杈撳叆寮€鍦虹櫧"
/>

<MoInput
  v-model="keyword"
  v-model:tags="tags"
  taggable
  placeholder="杈撳叆鍚庢寜鍥炶溅娣诲姞"
/>

Tabs

<MoTabs v-model="active" :items="tabs" size="large">
  <template #label="{ item }">
    {{ item.label }}
  </template>

  <template #panel="{ item }">
    {{ item.value }}
  </template>
</MoTabs>

Select

<MoSelect v-model="value" :options="options" theme="dark" />

Menu

<MoMenu :items="items" theme="dark" @select="handleSelect">
  <template #trigger>
    <MoButton theme="dark">鍙戝竷</MoButton>
  </template>
</MoMenu>

Upload

<MoUpload
  theme="dark"
  accept="image/png,image/jpeg,image/webp"
  :limit="1"
  :max-size="10"
  crop
  crop-shape="circle"
  :crop-size="96"
  hint="PNG/JPG/WebP锛屾渶澶?0MB"
/>

鑷畾涔変笂浼犲尯鍩燂細

<MoUpload theme="dark">
  <template #dropzone>
    <div class="upload-icon">+</div>
    <div>鎷栨嫿鏂囦欢鍒拌繖閲?/div>
    <div>鎴栫偣鍑讳笂浼?/div>
  </template>
</MoUpload>

鐭╁舰瑁佸垏锛?

<MoUpload crop crop-shape="rect" :crop-width="320" :crop-height="180" />

鏈湴寮€鍙?

pnpm install
pnpm dev

鏋勫缓

pnpm build

鍙戝竷鍓嶆鏌?

pnpm release:dry

Upload SDK

MoUpload 默认只负责选择文件、预览、裁切和维护文件状态,不会在选择文件后自动上传,也不会执行模拟上传。需要上传时,由外部手动触发:

<script setup lang="ts">
import { ref } from "vue";
import type { UploadFileItem } from "@yymojo-tec/mojo-ui";

const uploadRef = ref<{ submit: () => Promise<unknown[]> }>();

function submitUpload() {
  uploadRef.value?.submit();
}

function handleSuccess(file: UploadFileItem, response: unknown) {
  console.log(file, response);
}
</script>

<template>
  <MoUpload
    ref="uploadRef"
    action="/api/upload"
    :headers="{ Authorization: `Bearer ${token}` }"
    :data="{ scene: 'avatar' }"
    name="file"
    @success="handleSuccess"
  />

  <MoButton @click="submitUpload">开始上传</MoButton>
</template>

如果业务需要完全接管上传请求,可以传 request

<MoUpload :request="customUpload" />
async function customUpload({ file, onProgress }) {
  const formData = new FormData();
  formData.append("file", file);

  await axios.post("/api/upload", formData, {
    onUploadProgress(event) {
      if (event.total) {
        onProgress((event.loaded / event.total) * 100);
      }
    }
  });
}

也可以独立使用上传 SDK:

import { uploadFile } from "@yymojo-tec/mojo-ui";

await uploadFile({
  file,
  action: "/api/upload",
  headers: { Authorization: `Bearer ${token}` },
  data: { scene: "avatar" },
  onProgress(percent) {
    console.log(percent);
  }
});

Scrollbar

MoScrollbar 绑定一个外部滚动容器,滚动条会显示在该容器右侧 border 内侧、padding 外侧,并使用外部容器的高度作为滚动轨道。

<script setup lang="ts">
import { ref } from "vue";

const panelRef = ref<HTMLElement>();
</script>

<template>
  <div ref="panelRef" class="panel">
    <div class="content">...</div>
  </div>

  <MoScrollbar :target="panelRef" theme="dark" />
</template>

<style scoped>
.panel {
  position: relative;
  height: 360px;
  overflow: auto;
  padding: 16px;
  border: 1px solid rgba(255, 255, 255, 0.12);
}
</style>

常用参数:

  • target: 外部滚动容器 ref 或元素
  • size: 滚动条宽度,默认 6
  • minThumbSize: 滑块最小高度,默认 28
  • offset: 距离右侧 border 的偏移量,默认 0
  • always: 是否常显
  • hideNative: 是否隐藏原生滚动条,默认 true

Dialog

MoDialog 基于 Headless UI Dialog 封装,使用 v-model 控制显示,默认带标题和关闭按钮。

<script setup lang="ts">
import { ref } from "vue";

const visible = ref(false);
</script>

<template>
  <MoButton @click="visible = true">打开弹窗</MoButton>

  <MoDialog v-model="visible" title="创建智能体" theme="dark" :padding="24">
    <p>这里放弹窗内容。</p>

    <template #footer>
      <MoButton theme="dark" type="ghost" @click="visible = false">取消</MoButton>
      <MoButton theme="dark" type="primary" @click="visible = false">确认</MoButton>
    </template>
  </MoDialog>
</template>

隐藏右上角关闭按钮:

<MoDialog v-model="visible" title="提示" :show-close="false">
  内容
</MoDialog>

常用参数:

  • v-model: 是否显示
  • title: 标题
  • theme: light | dark
  • width: 弹窗宽度,默认 520
  • padding: 内容和标题左右 padding,默认 24
  • showClose: 是否显示右上角关闭按钮,默认 true
  • closeOnOverlay: 点击遮罩或按 Esc 是否关闭,默认 true
  • lockScroll: 是否锁住页面滚动,默认 false

Tag

MoTag 目前提供实心样式,默认颜色有 purpletealorangerose,也可以传入自定义背景色。

<MoTag color="purple">默认</MoTag>
<MoTag color="teal">已发布</MoTag>
<MoTag color="orange">待审核</MoTag>
<MoTag color="rose">推荐</MoTag>

<MoTag background-color="#222222">自定义</MoTag>

常用参数:

  • color: purple | teal | orange | rose
  • backgroundColor: 自定义背景色
  • textColor: 自定义文字颜色,默认 #ffffff
  • size: small | default | large
  • round: 圆角胶囊样式

MoRadioGroup

MoRadioGroup 基于 Headless UI RadioGroup 封装,当前提供分段实心样式。可以通过 background-color 修改外层背景,通过 active-background-color 修改选中项背景,图标使用 icon 插槽传入。

<script setup lang="ts">
import { ref } from "vue";

const action = ref("publish");
const radioOptions = [
  { label: "发布", value: "publish" },
  { label: "收藏", value: "favorite" },
  { label: "分享", value: "share" },
  { label: "导出", value: "export" }
];
</script>

<template>
  <MoRadioGroup
    v-model="action"
    theme="dark"
    :options="radioOptions"
    background-color="#171b24"
    active-background-color="#2e2a48"
  >
    <template #icon="{ option }">
      <PhShareNetwork v-if="option.value === 'publish'" :size="14" />
      <PhStar v-else-if="option.value === 'favorite'" :size="14" />
      <PhUploadSimple v-else-if="option.value === 'share'" :size="14" />
      <PhDownloadSimple v-else :size="14" />
    </template>
  </MoRadioGroup>
</template>

常用参数:

  • v-model: 当前选中的值
  • options: { label, value, disabled? }[]
  • theme: light | dark
  • size: small | default | large
  • backgroundColor: 外层背景色
  • activeBackgroundColor: 选中项背景色
  • textColor: 默认文字和图标颜色
  • activeTextColor: 选中文字和图标颜色