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

@lasttrins/uniq-editor

v1.2.27

Published

A modern WYSIWYG text editor library for Vue 3 with TypeScript support and file upload capabilities

Readme

🚀 UniqEditor

Современный WYSIWYG текстовый редактор для Vue 3 с поддержкой TypeScript, современными браузерными API и возможностями загрузки файлов.

NPM Version License: MIT TypeScript Vue 3

✨ Основные особенности

  • 🎯 Полноценный WYSIWYG редактор с интуитивным интерфейсом
  • 🔧 Гибкая конфигурация тулбара и функций
  • 📁 Загрузка файлов и изображений с валидацией и прогрессом
  • 🎨 Богатое форматирование текста с поддержкой всех стилей
  • 📝 Множество типов списков (точки, кружки, квадраты, буквы, римские цифры)
  • 📐 Выравнивание текста (лево, центр, право, по ширине)
  • 📊 Создание таблиц с настраиваемыми размерами
  • 🔄 Отмена/повтор действий с полной историей изменений
  • 🌐 Поддержка Vue 3 и vanilla JavaScript
  • 📱 Адаптивный дизайн для мобильных устройств
  • TypeScript поддержка из коробки
  • 🚀 Высокая производительность с современными браузерными API
  • 🔌 Система плагинов для расширения функциональности
  • 🛡️ Безопасность с санитизацией HTML и защитой от XSS

🆕 Последние обновления (v1.2.23+)

  • Замена устаревшего document.execCommand на современные Selection/Range API
  • Исправлена типизация TypeScript - убраны все any типы
  • Устранены циклические зависимости в архитектуре
  • Добавлена санитизация HTML для предотвращения XSS атак
  • Улучшена производительность с дебаунсингом и MutationObserver
  • Восстановлены все функции загрузки файлов и создания таблиц
  • Правильная синхронизация между Model и View
  • Обработка ошибок и валидация входных данных

📦 Установка

npm install @lasttrins/uniq-editor
yarn add @lasttrins/uniq-editor
pnpm add @lasttrins/uniq-editor

🚀 Быстрый старт

Vue 3 Composition API

<template>
  <div>
    <UniqEditor
      v-model="content"
      :config="editorConfig"
      placeholder="Начните писать..."
      @ready="onEditorReady"
      @change="onContentChange"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { UniqEditor } from '@lasttrins/uniq-editor/vue'

const content = ref('<p>Добро пожаловать в UniqEditor!</p>')

const editorConfig = {
  readonly: false,
  toolbar: {
    items: [
      // Форматирование текста
      'bold', 'italic', 'underline', 'link',
      'fontSize', 'textColor', 'backgroundColor',
      
      // Заголовки
      'heading1', 'heading2', 'heading3',
      
      // Списки (все типы)
      'bulletList', 'bulletListCircle', 'bulletListSquare',
      'numberedList', 'numberedListAlpha', 'numberedListRoman',
      
      // Выравнивание
      'alignLeft', 'alignCenter', 'alignRight', 'alignJustify',
      
      // Медиа и файлы
      'insertImage', 'uploadImage', 'uploadFile', 'insertTable',
      
      // Действия
      'removeFormat', 'undo', 'redo'
    ]
  },
  upload: {
    uploadUrl: '/api/upload',
    maxFileSize: 10 * 1024 * 1024, // 10MB
    allowedTypes: ['image/*', '.pdf', '.doc', '.docx', '.txt'],
    headers: {
      'Authorization': 'Bearer your-token'
    },
    onSuccess: (response, file) => {
      console.log('Файл загружен:', response)
      return response.url || response.file_url
    },
    onError: (error, file) => {
      console.error('Ошибка загрузки:', error)
      alert('Ошибка при загрузке файла: ' + error.message)
    },
    onProgress: (progress, file) => {
      console.log(`Прогресс загрузки ${file.name}: ${progress}%`)
    }
  }
}

const onEditorReady = (editor) => {
  console.log('Редактор готов к работе:', editor)
}

const onContentChange = (newContent) => {
  console.log('Содержимое изменилось:', newContent)
}
</script>

Vue 3 Options API

<template>
  <div>
    <UniqEditor
      v-model="content"
      :config="editorConfig"
      :readonly="isReadonly"
      placeholder="Введите текст..."
      @ready="handleEditorReady"
      @change="handleContentChange"
      @focus="handleFocus"
      @blur="handleBlur"
    />
  </div>
</template>

<script>
import { UniqEditor } from '@lasttrins/uniq-editor/vue'

export default {
  components: {
    UniqEditor
  },
  data() {
    return {
      content: '',
      isReadonly: false,
      editorConfig: {
        toolbar: {
          items: [
            'bold', 'italic', 'underline', 'link',
            'heading1', 'heading2', 'bulletList', 'numberedList',
            'alignLeft', 'alignCenter', 'alignRight',
            'insertImage', 'uploadImage', 'removeFormat'
          ]
        }
      }
    }
  },
  methods: {
    handleEditorReady(editor) {
      this.editor = editor
    },
    handleContentChange(content) {
      // Автоматически обновляется через v-model
      console.log('Контент изменен')
    },
    handleFocus() {
      console.log('Редактор получил фокус')
    },
    handleBlur() {
      console.log('Редактор потерял фокус')
    }
  }
}
</script>

Vanilla JavaScript

<!DOCTYPE html>
<html>
<head>
    <title>UniqEditor Vanilla JS</title>
</head>
<body>
    <div id="editor"></div>

    <script type="module">
        import { Editor } from '@lasttrins/uniq-editor/core'

        const editor = new Editor(document.getElementById('editor'), {
            placeholder: 'Начните писать...',
            toolbar: {
                items: [
                    'bold', 'italic', 'underline', 'link',
                    'heading1', 'heading2', 'heading3',
                    'bulletList', 'numberedList', 'insertTable',
                    'alignLeft', 'alignCenter', 'alignRight',
                    'insertImage', 'uploadImage', 'uploadFile'
                ]
            },
            upload: {
                uploadUrl: '/api/upload',
                onSuccess: (response) => response.url
            }
        })

        // Слушаем изменения
        editor.model.onChange(() => {
            console.log('Содержимое изменилось:', editor.getData())
        })

        // Программное управление
        editor.setData('<p>Начальный контент</p>')
        editor.execute('bold')
        editor.focus()
    </script>
</body>
</html>

📋 Полный список команд тулбара

📝 Форматирование текста

  • bold - Жирный текст (Ctrl+B)
  • italic - Курсив (Ctrl+I)
  • underline - Подчеркнутый (Ctrl+U)
  • link - Создание ссылок (Ctrl+K)
  • fontSize - Размер шрифта
  • textColor - Цвет текста
  • backgroundColor - Цвет фона текста
  • removeFormat - Очистка форматирования

📰 Заголовки

  • heading1 - Заголовок 1 уровня
  • heading2 - Заголовок 2 уровня
  • heading3 - Заголовок 3 уровня

📝 Списки

  • bulletList - Маркированный список (точки •)
  • bulletListCircle - Маркированный список (кружки ○)
  • bulletListSquare - Маркированный список (квадраты ■)
  • numberedList - Нумерованный список (1, 2, 3...)
  • numberedListAlpha - Список с буквами (a, b, c...)
  • numberedListRoman - Список с римскими цифрами (i, ii, iii...)

📐 Выравнивание

  • alignLeft - По левому краю
  • alignCenter - По центру
  • alignRight - По правому краю
  • alignJustify - По ширине

📁 Медиа и файлы

  • insertImage - Вставка изображения по URL
  • uploadImage - Загрузка изображения с компьютера
  • uploadFile - Загрузка любого файла
  • insertTable - Создание таблицы

⏮️ История действий

  • undo - Отмена действия (Ctrl+Z)
  • redo - Повтор действия (Ctrl+Shift+Z)

⚙️ Конфигурация

Базовые настройки

const config = {
  readonly: false,                    // Режим только для чтения
  placeholder: 'Введите текст...',    // Текст-подсказка
  language: 'ru',                     // Язык интерфейса
  toolbar: {
    items: [...],                     // Элементы тулбара
    shouldGroupWhenFull: true         // Группировка при переполнении
  }
}

Настройка загрузки файлов

const uploadConfig = {
  uploadUrl: '/api/upload',           // URL для загрузки (обязательно!)
  fieldName: 'file',                  // Имя поля в FormData
  maxFileSize: 10 * 1024 * 1024,     // Максимальный размер (10MB)
  allowedTypes: [                     // Разрешенные типы файлов
    'image/*',                        // Все изображения
    'image/jpeg',                     // Конкретные MIME типы
    '.pdf', '.doc', '.docx', '.txt'   // По расширениям
  ],
  headers: {                          // Дополнительные заголовки
    'Authorization': 'Bearer token',
    'X-Custom-Header': 'value'
  },
  
  // Callback функции
  onSuccess: (response, file) => {
    // Обработка успешной загрузки
    console.log('Загружен файл:', file.name)
    // ВАЖНО: Верните URL для вставки в редактор
    return response.url || response.file_url || response.path
  },
  
  onError: (error, file) => {
    // Обработка ошибок
    console.error('Ошибка загрузки файла:', file.name, error)
    alert('Не удалось загрузить файл: ' + error.message)
  },
  
  onProgress: (progress, file) => {
    // Отслеживание прогресса (0-100)
    console.log(`Загрузка ${file.name}: ${progress}%`)
  }
}

Пример API сервера для загрузки

// Express.js пример
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })

app.post('/api/upload', upload.single('file'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'Файл не найден' })
  }
  
  const fileUrl = `/uploads/${req.file.filename}`
  
  res.json({
    success: true,
    url: fileUrl,           // Основное поле для URL
    file_url: fileUrl,      // Альтернативное поле
    filename: req.file.originalname,
    size: req.file.size
  })
})

🎨 Кастомизация стилей

CSS переменные

:root {
  --uniq-editor-border-color: #e5e7eb;
  --uniq-editor-toolbar-bg: #f9fafb;
  --uniq-editor-button-hover: #f3f4f6;
  --uniq-editor-button-active: #3b82f6;
  --uniq-editor-text-color: #374151;
  --uniq-editor-placeholder-color: #9ca3af;
}

Кастомные стили

/* Стилизация тулбара */
.uniq-editor-toolbar {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 8px;
  padding: 12px;
}

/* Стилизация кнопок */
.toolbar-button {
  border-radius: 6px;
  transition: all 0.2s ease;
}

.toolbar-button:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}

/* Стилизация контента */
.uniq-editor-content {
  font-family: 'Georgia', serif;
  line-height: 1.6;
  color: #2d3748;
}

/* Стилизация таблиц */
.uniq-editor-content table {
  border: 2px solid #e2e8f0;
  border-radius: 8px;
  overflow: hidden;
}

.uniq-editor-content th {
  background: linear-gradient(135deg, #4299e1 0%, #3182ce 100%);
  color: white;
  font-weight: 600;
}

🔌 API и методы

Основные методы редактора

// Создание редактора
const editor = new Editor(element, config)

// Управление содержимым
editor.setData('<p>HTML контент</p>')
const content = editor.getData()

// Выполнение команд
editor.execute('bold')
editor.execute('insertTable', 3, 4)  // 3 строки, 4 столбца
editor.execute('insertImage', 'https://example.com/image.jpg')

// Управление фокусом
editor.focus()
editor.blur()

// Очистка ресурсов
editor.destroy()

// Проверка возможности выполнения команды
if (editor.commands.canExecute('bold')) {
  editor.execute('bold')
}

События

// Vue компонент
<UniqEditor
  @ready="onReady"        // Редактор готов
  @change="onChange"      // Изменение контента
  @focus="onFocus"        // Получение фокуса
  @blur="onBlur"          // Потеря фокуса
/>

// Vanilla JS
editor.model.onChange(() => {
  console.log('Контент изменен')
})

🧪 Тестирование

Проект включает несколько тестовых файлов для проверки функциональности:

# Сборка проекта
npm run build

# Запуск тестов
npm test

# Проверка типов
npm run type-check

Тестовые файлы

  • test/test-full-toolbar.html - Полное тестирование всех функций
  • test/test-vue.html - Тестирование Vue компонента
  • test/test-vanilla.html - Тестирование vanilla JS версии
  • test/quick-test.js - Быстрые автоматические тесты

🏗️ Архитектура

UniqEditor построен по модульной архитектуре:

src/
├── core/                    # Основная логика
│   ├── Editor.ts           # Главный класс редактора
│   ├── DocumentModel.ts    # Модель документа
│   ├── EditorView.ts       # Представление редактора
│   ├── SelectionUtils.ts   # Современные Selection API
│   ├── CommandManager.ts   # Менеджер команд
│   ├── PluginManager.ts    # Менеджер плагинов
│   └── UploadService.ts    # Сервис загрузки файлов
├── vue/                    # Vue 3 интеграция
│   ├── UniqEditor.vue     # Основной Vue компонент
│   └── index.ts           # Экспорты для Vue
├── plugins/               # Система плагинов
│   └── ToolbarPlugin.ts   # Плагин тулбара
└── types/                 # TypeScript типы
    └── index.ts           # Определения типов

🤝 Поддержка браузеров

  • ✅ Chrome 88+
  • ✅ Firefox 87+
  • ✅ Safari 14+
  • ✅ Edge 88+

Редактор использует современные браузерные API:

  • Selection API
  • Range API
  • MutationObserver
  • ES2020 модули

📝 Примеры использования

Простой блог-редактор

<template>
  <div class="blog-editor">
    <h2>Написать статью</h2>
    <input v-model="title" placeholder="Заголовок статьи" class="title-input" />
    <UniqEditor
      v-model="content"
      :config="blogConfig"
      placeholder="Содержание статьи..."
    />
    <button @click="saveArticle">Опубликовать</button>
  </div>
</template>

<script setup>
const blogConfig = {
  toolbar: {
    items: [
      'heading1', 'heading2', 'heading3',
      'bold', 'italic', 'underline',
      'bulletList', 'numberedList',
      'link', 'insertImage', 'uploadImage',
      'alignLeft', 'alignCenter', 'alignRight'
    ]
  },
  upload: {
    uploadUrl: '/api/blog/upload-image',
    allowedTypes: ['image/*'],
    maxFileSize: 5 * 1024 * 1024
  }
}
</script>

Редактор документов

<template>
  <UniqEditor
    v-model="document"
    :config="documentConfig"
    placeholder="Создайте документ..."
  />
</template>

<script setup>
const documentConfig = {
  toolbar: {
    items: [
      'bold', 'italic', 'underline', 'fontSize', 'textColor',
      'heading1', 'heading2', 'heading3',
      'bulletList', 'numberedList', 'bulletListCircle',
      'alignLeft', 'alignCenter', 'alignRight', 'alignJustify',
      'insertTable', 'insertImage', 'uploadFile',
      'undo', 'redo'
    ]
  },
  upload: {
    uploadUrl: '/api/documents/upload',
    allowedTypes: ['image/*', '.pdf', '.doc', '.docx'],
    maxFileSize: 50 * 1024 * 1024 // 50MB для документов
  }
}
</script>

🚀 Производительность

  • Дебаунсинг - обновления контента с задержкой для снижения нагрузки
  • MutationObserver - эффективное отслеживание изменений DOM
  • Lazy Loading - плагины загружаются по требованию
  • Кэширование - данные модели кэшируются для быстрого доступа
  • Санитизация - безопасная очистка HTML с минимальным влиянием на производительность

🛡️ Безопасность

  • XSS защита - автоматическая санитизация HTML
  • Валидация файлов - проверка типов, размеров и имен файлов
  • Безопасные URL - фильтрация опасных протоколов
  • CSRF защита - поддержка токенов в заголовках загрузки

📄 Лицензия

MIT License. Подробности в файле LICENSE.

🤝 Вклад в проект

Мы приветствуем ваш вклад в развитие проекта!

  1. Форкните репозиторий
  2. Создайте ветку для новой функции (git checkout -b feature/amazing-feature)
  3. Зафиксируйте изменения (git commit -m 'Add amazing feature')
  4. Отправьте в ветку (git push origin feature/amazing-feature)
  5. Откройте Pull Request

🐛 Сообщения об ошибках

Если вы нашли ошибку, пожалуйста, создайте issue с:

  • Описанием проблемы
  • Шагами для воспроизведения
  • Ожидаемым поведением
  • Скриншотами (если применимо)
  • Информацией о браузере и версии

📞 Поддержка

🎉 Благодарности

Спасибо всем, кто вносит вклад в развитие проекта!


UniqEditor - делаем редактирование текста простым и мощным! 🚀