@voicenter-team/voicenter-ui-plus 3.3.3 → 3.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +502 -502
- package/library/assets/assets/sass/main.css +1 -1
- package/library/assets/components/VcSoundplayer/VcSoundPlayerMarker.css +1 -0
- package/library/assets/components/VcSoundplayer/VcSoundPlayerProgress.css +1 -1
- package/library/components/VcSoundplayer/VcSoundPlayer.vue.mjs +54 -14
- package/library/components/VcSoundplayer/VcSoundPlayerMarker.vue.mjs +131 -0
- package/library/components/VcSoundplayer/VcSoundPlayerMarker.vue3.mjs +5 -0
- package/library/components/VcSoundplayer/VcSoundPlayerMarkers.vue.mjs +49 -0
- package/library/components/VcSoundplayer/VcSoundPlayerMarkers.vue2.mjs +4 -0
- package/library/components/VcSoundplayer/VcSoundPlayerProgress.vue.mjs +13 -3
- package/library/components/VcSoundplayer/VcSoundPlayerWrapper.vue.mjs +17 -1
- package/library/index.mjs +53 -48
- package/library/index.mjs.br +0 -0
- package/library/index.mjs.gz +0 -0
- package/library/localization/index.mjs.gz +0 -0
- package/library/plugin-components.gen.mjs +47 -42
- package/library/plugin.mjs +53 -48
- package/library/plugin.mjs.br +0 -0
- package/library/plugin.mjs.gz +0 -0
- package/library/style.css +4 -2
- package/library/style.css.br +0 -0
- package/library/style.css.gz +0 -0
- package/library/theme/index.mjs.gz +0 -0
- package/library/types/components/VcModal/VcModal.vue.d.ts +1 -1
- package/library/types/components/VcNotification/VcNotification.vue.d.ts +1 -1
- package/library/types/components/VcRadioTabs/UiComponents/VcRadioTabsNav.vue.d.ts +3 -3
- package/library/types/components/VcSoundplayer/VcSoundPlayer.vue.d.ts +43 -3
- package/library/types/components/VcSoundplayer/VcSoundPlayerMarker.vue.d.ts +95 -0
- package/library/types/components/VcSoundplayer/VcSoundPlayerMarkers.vue.d.ts +52 -0
- package/library/types/components/VcSoundplayer/VcSoundPlayerProgress.vue.d.ts +10 -2
- package/library/types/components/VcSoundplayer/VcSoundPlayerWrapper.vue.d.ts +2 -0
- package/library/types/components/VcSoundplayer/soundPlayerParts.d.ts +3 -1
- package/library/types/components/exports.d.ts +5 -1
- package/library/types/components.gen.d.ts +2 -0
- package/library/types/types/VcSoundPlayer.types.d.ts +36 -1
- package/library/utils/jsonSchema/index.mjs.gz +0 -0
- package/package.json +185 -185
- package/tailwind.config.js +192 -192
package/README.md
CHANGED
|
@@ -1,502 +1,502 @@
|
|
|
1
|
-
# Voicenter UI library for Vue
|
|
2
|
-
This is Vue 3.x + Typescript component library made for Voicenter systems.
|
|
3
|
-
|
|
4
|
-
> **v3.0.0 is a tree-shaking release with breaking changes.** See [`MIGRATION_v3.md`](./MIGRATION_v3.md). The separate `*-extended` package is gone — every component lives in this package now.
|
|
5
|
-
|
|
6
|
-
## Installation
|
|
7
|
-
|
|
8
|
-
```bash
|
|
9
|
-
npm i @voicenter-team/voicenter-ui-plus
|
|
10
|
-
npm i vue@^3.5 element-plus @vueuse/core dayjs lodash-es libphonenumber-js maska
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
### Sass compiler (build-time)
|
|
14
|
-
|
|
15
|
-
This library customizes element-plus theming via SCSS variable injection at build time. Your bundler needs to be able to compile SCSS. If your project doesn't already use Sass, add it as a dev dependency:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npm i -D sass-embedded
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
This is a **build-time only** requirement — it doesn't add anything to your runtime bundle. Most Vue 3 / Vite projects already have it.
|
|
22
|
-
|
|
23
|
-
Optional peer deps — install only for the heavy components you use:
|
|
24
|
-
|
|
25
|
-
| Component | Peer deps |
|
|
26
|
-
|---|---|
|
|
27
|
-
| `VcPdfDocument` | `pdfjs-dist@^2.9.359` |
|
|
28
|
-
| `VcSoundPlayer` | `wavesurfer.js` |
|
|
29
|
-
| `VcExcelFileUploader` | `xlsx` |
|
|
30
|
-
| `VcImageUploader` | `vue-advanced-cropper` |
|
|
31
|
-
| `VcHtmlEditor` / `VcJsonSchema` | `codemirror @codemirror/lang-html @codemirror/lang-json @codemirror/lang-markdown vue-codemirror6` |
|
|
32
|
-
| `VcMdEditor` | `@milkdown/crepe @milkdown/kit @milkdown/vue @prosemirror-adapter/vue` |
|
|
33
|
-
|
|
34
|
-
### If you're on Vite 8 / rolldown (and skipping some optional peers)
|
|
35
|
-
|
|
36
|
-
Vite 8's rolldown-based bundler validates named imports against optional-peer-dep stubs and fails the build with `MISSING_EXPORT` errors when a heavy component's peer is uninstalled — even when you don't use that component. Add the unused optional peers to `build.rollupOptions.external` in your `vite.config.ts`:
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
// vite.config.ts
|
|
40
|
-
import { defineConfig } from 'vite'
|
|
41
|
-
import vue from '@vitejs/plugin-vue'
|
|
42
|
-
|
|
43
|
-
export default defineConfig({
|
|
44
|
-
plugins: [ vue() ],
|
|
45
|
-
build: {
|
|
46
|
-
rollupOptions: {
|
|
47
|
-
external: [
|
|
48
|
-
// List only the heavy peers you DON'T install
|
|
49
|
-
/^@milkdown\//, /^@prosemirror/, /^@codemirror\//, /^codemirror/,
|
|
50
|
-
/^vue-codemirror6/, /^vue-advanced-cropper/,
|
|
51
|
-
'wavesurfer.js', 'xlsx', 'pdfjs-dist', /^pdfjs-dist\//
|
|
52
|
-
]
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Earlier Vite versions (5, 6, 7 with rollup) and webpack 5+ don't require this — the older rollup variant warns but doesn't error on optional-peer named imports.
|
|
59
|
-
|
|
60
|
-
## Usage
|
|
61
|
-
|
|
62
|
-
### Tree-shake mode (recommended)
|
|
63
|
-
```ts
|
|
64
|
-
import { VcButton, VcInput } from '@voicenter-team/voicenter-ui-plus'
|
|
65
|
-
// Use as local components — no app.use() needed.
|
|
66
|
-
```
|
|
67
|
-
Bundlers drop unused components and their CSS. A consumer importing only `VcButton` ships ~50–150 KB JS + ~10–30 KB CSS.
|
|
68
|
-
|
|
69
|
-
If you use `useConfirmModal`, `useConfirmPopup`, or `NotifyService`, mount global overlays in `App.vue`:
|
|
70
|
-
|
|
71
|
-
```vue
|
|
72
|
-
<script setup lang="ts">
|
|
73
|
-
import { VcPluginOverlays } from '@voicenter-team/voicenter-ui-plus'
|
|
74
|
-
</script>
|
|
75
|
-
|
|
76
|
-
<template>
|
|
77
|
-
<RouterView />
|
|
78
|
-
<VcPluginOverlays />
|
|
79
|
-
</template>
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Plugin mode (global registration)
|
|
83
|
-
```ts
|
|
84
|
-
import VoicenterUI from '@voicenter-team/voicenter-ui-plus/plugin'
|
|
85
|
-
import '@voicenter-team/voicenter-ui-plus/style.css'
|
|
86
|
-
|
|
87
|
-
// Overlay composables can be imported from the same entry:
|
|
88
|
-
// import { useConfirmModal, useConfirmPopup, VcPluginOverlays } from '@voicenter-team/voicenter-ui-plus/plugin'
|
|
89
|
-
|
|
90
|
-
app.use(VoicenterUI, {
|
|
91
|
-
themeConfig, // theme config (see below)
|
|
92
|
-
lang: 'en', // localization
|
|
93
|
-
injectIconFont: true // inject icon-font <link> tags into <head>
|
|
94
|
-
})
|
|
95
|
-
// Confirm modals/popovers/notifications: auto-mounted via VcPluginOverlays
|
|
96
|
-
// (mountOverlays: true by default). Opt out with mountOverlays: false and
|
|
97
|
-
// add <VcPluginOverlays /> to App.vue — also registered globally by the plugin.
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Global overlays
|
|
101
|
-
|
|
102
|
-
Several APIs are **state-only** — they update global reactive singletons but do not render UI by themselves:
|
|
103
|
-
|
|
104
|
-
| API | Overlay component |
|
|
105
|
-
|---|---|
|
|
106
|
-
| `useConfirmModal` | `VcConfirmModal` |
|
|
107
|
-
| `useConfirmPopup` | `VcConfirmPopover` |
|
|
108
|
-
| `NotifyService` / `$notify` | `VcNotification` |
|
|
109
|
-
|
|
110
|
-
**Plugin mode:** mounted automatically on `app.use()` (default). Pass `mountOverlays: false` to mount manually.
|
|
111
|
-
|
|
112
|
-
**Notifications:** one top-right host by default. For multiple positions, use `overlayNotifications` in plugin config or mount your own:
|
|
113
|
-
|
|
114
|
-
```ts
|
|
115
|
-
app.use(VoicenterUI, {
|
|
116
|
-
overlayNotifications: [
|
|
117
|
-
{ group: 'top-right', position: 'top-right' },
|
|
118
|
-
{ group: 'bottom-right', position: 'bottom-right' },
|
|
119
|
-
],
|
|
120
|
-
})
|
|
121
|
-
// NotifyService.add({ group: 'bottom-right', ... })
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Or `overlayNotifications: 'none'` and put `<VcNotification />` in App.vue (confirms still auto-mount).
|
|
125
|
-
|
|
126
|
-
**Tree-shake mode:** add `<VcPluginOverlays />` to `App.vue` (bundles confirm hosts; configure via `notifications` prop).
|
|
127
|
-
|
|
128
|
-
Entity components such as `VcEntityListTable` call `useConfirmModal` internally — delete confirmations require overlays to be mounted.
|
|
129
|
-
|
|
130
|
-
2.1. If you are using tailwind update your `tailwind.config.js` with:
|
|
131
|
-
```js
|
|
132
|
-
const voiceTailwindScheme = require('@voicenter-team/voicenter-ui-plus/src/theme/tailwindScheme')
|
|
133
|
-
|
|
134
|
-
module.exports = {
|
|
135
|
-
...yourConfiguration,
|
|
136
|
-
theme: {
|
|
137
|
-
colors: {
|
|
138
|
-
...voiceTailwindScheme
|
|
139
|
-
},
|
|
140
|
-
borderColor: {
|
|
141
|
-
...voiceTailwindScheme
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Theming specification
|
|
148
|
-
The `themeConfig` which is passed as options to the VoicenterUI `vue.use` data could have the following specifications:
|
|
149
|
-
|
|
150
|
-
### Local
|
|
151
|
-
**Config:**
|
|
152
|
-
```js
|
|
153
|
-
{
|
|
154
|
-
type: 'local'
|
|
155
|
-
themeName: 'red' | 'blue' | '...'
|
|
156
|
-
onSetupCallback: () => {
|
|
157
|
-
console.log('Loaded!')
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
**Description:**
|
|
162
|
-
|
|
163
|
-
Such configuration will append to the document element the CSS variables from one of the configuration passed in `themeName` parameter which it will get from theme specification delivered alongside with library
|
|
164
|
-
|
|
165
|
-
**Params:**
|
|
166
|
-
- **themeName**
|
|
167
|
-
- The name of the theme to be injected
|
|
168
|
-
- **onSetupCallback**
|
|
169
|
-
- The function which will be called right after the variables will be injected into the document element. First parameter of which is the theme object which was set up
|
|
170
|
-
|
|
171
|
-
### Remote
|
|
172
|
-
**Config:**
|
|
173
|
-
```js
|
|
174
|
-
{
|
|
175
|
-
type: 'remote'
|
|
176
|
-
brandingSectionName: 'someName'
|
|
177
|
-
apiUrl: 'someUrl'
|
|
178
|
-
brandingSectionName: {
|
|
179
|
-
property: 'data'
|
|
180
|
-
}
|
|
181
|
-
onSetupCallback: () => {
|
|
182
|
-
console.log('Loaded!')
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
**Description:**
|
|
187
|
-
|
|
188
|
-
Such configuration will initiate the call to the specified apiUrl in order to retrieve the JSON object with key-value properties of the CSS variables to inject to document element
|
|
189
|
-
|
|
190
|
-
**Params:**
|
|
191
|
-
- **brandingSectionName**
|
|
192
|
-
- [Optional] The name of the section (tagSection) in the database configuration which will be passed to the API in payload and on response retrieved replaced from resulted values
|
|
193
|
-
- **apiUrl**
|
|
194
|
-
- The API url to which the POST request will be initiated
|
|
195
|
-
- **onSetupCallback**
|
|
196
|
-
- The function which will be called right after the variables will be injected into the document element. First parameter of which is the theme object which was set up
|
|
197
|
-
- **brandingSectionName**
|
|
198
|
-
- [Optional] The payload data that will be sent to the request
|
|
199
|
-
|
|
200
|
-
### Custom JSON
|
|
201
|
-
**Config:**
|
|
202
|
-
```js
|
|
203
|
-
{
|
|
204
|
-
type: 'customJson'
|
|
205
|
-
config: {
|
|
206
|
-
black: '#000000'
|
|
207
|
-
}
|
|
208
|
-
onSetupCallback: () => {
|
|
209
|
-
console.log('Loaded!')
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
**Description:**
|
|
214
|
-
|
|
215
|
-
Such configuration will initiate the styling with custom provided theme
|
|
216
|
-
|
|
217
|
-
**Params:**
|
|
218
|
-
- **config**
|
|
219
|
-
- The object where the key is the variable to be set and the value is the variable value. Check the [themes object](https://github.com/VoicenterTeam/voicenter-ui-plus/blob/master/src/theme/themes.json) to check existing variables
|
|
220
|
-
- **onSetupCallback**
|
|
221
|
-
- The function which will be called right after the variables will be injected into the document element. First parameter of which is the theme object which was set up
|
|
222
|
-
|
|
223
|
-
## Date Handling
|
|
224
|
-
|
|
225
|
-
This library uses **dayjs** for all date operations and formatting. When working with date-related components, use dayjs format tokens (NOT date-fns format tokens).
|
|
226
|
-
|
|
227
|
-
### Format Tokens
|
|
228
|
-
|
|
229
|
-
**Important**: Use dayjs format tokens:
|
|
230
|
-
- `DD` - Day of month (2 digits) - **NOT** `dd`
|
|
231
|
-
- `YYYY` - 4-digit year - **NOT** `yyyy`
|
|
232
|
-
- `MM` - Month (2 digits)
|
|
233
|
-
- `HH` - 24-hour format
|
|
234
|
-
- `mm` - Minutes
|
|
235
|
-
- `ss` - Seconds
|
|
236
|
-
|
|
237
|
-
### Common Formats
|
|
238
|
-
|
|
239
|
-
```typescript
|
|
240
|
-
'DD/MM/YYYY' // 31/12/2024
|
|
241
|
-
'DD-MM-YYYY' // 31-12-2024
|
|
242
|
-
'YYYY-MM-DD' // 2024-12-31
|
|
243
|
-
'DD/MM/YYYY, HH:mm' // 31/12/2024, 14:30
|
|
244
|
-
'DD/MM/YYYY HH:mm:ss' // 31/12/2024 14:30:45
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### Usage Example
|
|
248
|
-
|
|
249
|
-
```vue
|
|
250
|
-
<VcDatePicker
|
|
251
|
-
v-model="date"
|
|
252
|
-
format="DD/MM/YYYY"
|
|
253
|
-
input-date-format="DD/MM/YYYY"
|
|
254
|
-
input-time-format="HH:mm"
|
|
255
|
-
/>
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
## Date Utility Functions
|
|
259
|
-
|
|
260
|
-
The library provides a comprehensive set of date utility functions built on dayjs. These utilities are available for use in external projects.
|
|
261
|
-
|
|
262
|
-
### Import Date Utilities
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
import {
|
|
266
|
-
formatDate,
|
|
267
|
-
parseDate,
|
|
268
|
-
addDays,
|
|
269
|
-
subtractDays,
|
|
270
|
-
getHours,
|
|
271
|
-
getMinutes,
|
|
272
|
-
getSeconds,
|
|
273
|
-
setTime,
|
|
274
|
-
isAfter,
|
|
275
|
-
isSameAfter,
|
|
276
|
-
isBefore,
|
|
277
|
-
isSameBefore,
|
|
278
|
-
format,
|
|
279
|
-
add,
|
|
280
|
-
sub,
|
|
281
|
-
addFp,
|
|
282
|
-
subFp
|
|
283
|
-
} from '@voicenter-team/voicenter-ui-plus'
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
### Basic Date Operations
|
|
287
|
-
|
|
288
|
-
#### Formatting Dates
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
// Format a date with default format (YYYY-MM-DD)
|
|
292
|
-
const formatted = formatDate(new Date())
|
|
293
|
-
// Result: "2024-12-31"
|
|
294
|
-
|
|
295
|
-
// Format with custom format
|
|
296
|
-
const custom = formatDate(new Date(), 'DD/MM/YYYY')
|
|
297
|
-
// Result: "31/12/2024"
|
|
298
|
-
|
|
299
|
-
// Using format function (alias)
|
|
300
|
-
const formatted2 = format(new Date(), 'DD/MM/YYYY HH:mm')
|
|
301
|
-
// Result: "31/12/2024 14:30"
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
#### Parsing Dates
|
|
305
|
-
|
|
306
|
-
```typescript
|
|
307
|
-
// Parse a date string with format
|
|
308
|
-
const date = parseDate('31/12/2024', 'DD/MM/YYYY')
|
|
309
|
-
// Returns: Date object
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### Date Arithmetic
|
|
313
|
-
|
|
314
|
-
#### Adding/Subtracting Days
|
|
315
|
-
|
|
316
|
-
```typescript
|
|
317
|
-
// Add days
|
|
318
|
-
const futureDate = addDays(new Date(), 7)
|
|
319
|
-
// Returns: Date 7 days from now
|
|
320
|
-
|
|
321
|
-
// Subtract days
|
|
322
|
-
const pastDate = subtractDays(new Date(), 5)
|
|
323
|
-
// Returns: Date 5 days ago
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
#### Adding/Subtracting Time Units
|
|
327
|
-
|
|
328
|
-
```typescript
|
|
329
|
-
// Add multiple time units
|
|
330
|
-
const newDate = add(new Date(), {
|
|
331
|
-
years: 1,
|
|
332
|
-
months: 2,
|
|
333
|
-
days: 5,
|
|
334
|
-
hours: 3,
|
|
335
|
-
minutes: 30
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
// Subtract multiple time units
|
|
339
|
-
const earlierDate = sub(new Date(), {
|
|
340
|
-
weeks: 2,
|
|
341
|
-
days: 3,
|
|
342
|
-
hours: 12
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
// Functional programming style (reversed arguments)
|
|
346
|
-
const fpDate = addFp({ days: 7 }, new Date())
|
|
347
|
-
const fpDate2 = subFp({ hours: 5 }, new Date())
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
### Time Operations
|
|
351
|
-
|
|
352
|
-
#### Getting Time Components
|
|
353
|
-
|
|
354
|
-
```typescript
|
|
355
|
-
const date = new Date('2024-12-31T14:30:45')
|
|
356
|
-
|
|
357
|
-
const hours = getHours(date) // 14
|
|
358
|
-
const minutes = getMinutes(date) // 30
|
|
359
|
-
const seconds = getSeconds(date) // 45
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
#### Setting Time
|
|
363
|
-
|
|
364
|
-
```typescript
|
|
365
|
-
// Set time on a date (returns new Date object)
|
|
366
|
-
const newDate = setTime(new Date(), {
|
|
367
|
-
hours: 14,
|
|
368
|
-
minutes: 30,
|
|
369
|
-
seconds: 0
|
|
370
|
-
})
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### Date Comparisons
|
|
374
|
-
|
|
375
|
-
```typescript
|
|
376
|
-
const date1 = new Date('2024-12-31')
|
|
377
|
-
const date2 = new Date('2025-01-01')
|
|
378
|
-
|
|
379
|
-
// Check if date1 is after date2
|
|
380
|
-
const isLater = isAfter(date1, date2, 'day')
|
|
381
|
-
// Returns: false
|
|
382
|
-
|
|
383
|
-
// Check if date1 is same or after date2
|
|
384
|
-
const isSameOrLater = isSameAfter(date1, date2, 'day')
|
|
385
|
-
// Returns: false
|
|
386
|
-
|
|
387
|
-
// Check if date1 is before date2
|
|
388
|
-
const isEarlier = isBefore(date1, date2, 'day')
|
|
389
|
-
// Returns: true
|
|
390
|
-
|
|
391
|
-
// Check if date1 is same or before date2
|
|
392
|
-
const isSameOrEarlier = isSameBefore(date1, date2, 'day')
|
|
393
|
-
// Returns: true
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
**Comparison Units**: The comparison functions accept a `units` parameter (default: `'minute'`). Valid units:
|
|
397
|
-
- `'year'`, `'month'`, `'week'`, `'day'`
|
|
398
|
-
- `'hour'`, `'minute'`, `'second'`
|
|
399
|
-
|
|
400
|
-
### Complete Usage Example
|
|
401
|
-
|
|
402
|
-
```typescript
|
|
403
|
-
import {
|
|
404
|
-
formatDate,
|
|
405
|
-
addDays,
|
|
406
|
-
isAfter,
|
|
407
|
-
format,
|
|
408
|
-
add,
|
|
409
|
-
getHours,
|
|
410
|
-
setTime
|
|
411
|
-
} from '@voicenter-team/voicenter-ui-plus'
|
|
412
|
-
|
|
413
|
-
// Format today's date
|
|
414
|
-
const today = formatDate(new Date(), 'DD/MM/YYYY')
|
|
415
|
-
|
|
416
|
-
// Get date 30 days from now
|
|
417
|
-
const futureDate = addDays(new Date(), 30)
|
|
418
|
-
|
|
419
|
-
// Check if a date is in the future
|
|
420
|
-
const isFuture = isAfter(futureDate, new Date(), 'day')
|
|
421
|
-
|
|
422
|
-
// Add 2 weeks and 3 days
|
|
423
|
-
const deadline = add(new Date(), {
|
|
424
|
-
weeks: 2,
|
|
425
|
-
days: 3
|
|
426
|
-
})
|
|
427
|
-
|
|
428
|
-
// Get current hour
|
|
429
|
-
const currentHour = getHours(new Date())
|
|
430
|
-
|
|
431
|
-
// Set specific time
|
|
432
|
-
const meetingTime = setTime(new Date(), {
|
|
433
|
-
hours: 14,
|
|
434
|
-
minutes: 30
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
// Format the result
|
|
438
|
-
const formattedDeadline = format(deadline, 'DD/MM/YYYY HH:mm')
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
### Notes
|
|
442
|
-
|
|
443
|
-
- All functions accept `Date`, `string`, or `number` as date input
|
|
444
|
-
- All date manipulation functions return new `Date` objects (immutable)
|
|
445
|
-
- Format strings use dayjs format tokens (see Format Tokens section above)
|
|
446
|
-
- These utilities are built on dayjs and maintain compatibility with dayjs format patterns
|
|
447
|
-
|
|
448
|
-
## Contributing: adding a new component
|
|
449
|
-
|
|
450
|
-
The public component surface is defined in **one place**: [`script/components-manifest.mjs`](./script/components-manifest.mjs) — one line per component.
|
|
451
|
-
|
|
452
|
-
```js
|
|
453
|
-
{ name: 'VcMyThing', path: 'components/VcMyThing/VcMyThing.vue' },
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
`npm run generate:entries` materializes the manifest into three fully
|
|
457
|
-
generated files (never edit them by hand — the next generator run
|
|
458
|
-
overwrites them, and the verifier fails the build until they match):
|
|
459
|
-
|
|
460
|
-
- `src/components.gen.ts` — named exports, re-exported by `src/index.ts`
|
|
461
|
-
(tree-shake mode);
|
|
462
|
-
- `src/plugin-components.gen.ts` — `registerComponents(app)`, called by
|
|
463
|
-
the plugin's install (global registration mode);
|
|
464
|
-
- `src/components/exports.ts` — the `GlobalComponents` template typing.
|
|
465
|
-
|
|
466
|
-
`src/index.ts` and `src/plugin.ts` themselves stay hand-written and small.
|
|
467
|
-
The `.gen` modules are safe to route through only because
|
|
468
|
-
`rewriteCssImports()` in `vite.config.ts` strips the CSS imports that
|
|
469
|
-
`vite-plugin-lib-inject-css` aggregates onto them — each component's CSS
|
|
470
|
-
stays in its own chunk, so per-component CSS tree-shaking survives. Don't
|
|
471
|
-
rename the `.gen` files without updating that strip list (the verifier
|
|
472
|
-
guards this wiring too).
|
|
473
|
-
|
|
474
|
-
Typical flows:
|
|
475
|
-
|
|
476
|
-
- **New component**: `node script/create-component.mjs` — scaffolds the
|
|
477
|
-
component folder, adds the manifest line, and regenerates all entries.
|
|
478
|
-
- **Existing .vue file**: add one line to the manifest, then
|
|
479
|
-
`npm run generate:entries`.
|
|
480
|
-
|
|
481
|
-
Every manifest entry is exported from the package root AND registered
|
|
482
|
-
globally in plugin mode — there are no partial modes.
|
|
483
|
-
|
|
484
|
-
`npm run verify:entries` is the safety net: it independently cross-checks
|
|
485
|
-
the manifest, the three generated files and the filesystem (a component
|
|
486
|
-
file that exists but is missing from the manifest fails too). It runs in
|
|
487
|
-
the pre-commit hook (together with `lint-staged` and `ts-check`; hooks are
|
|
488
|
-
installed automatically by `npm install` via husky) and in CI, so an
|
|
489
|
-
inconsistent component surface cannot reach `master`.
|
|
490
|
-
|
|
491
|
-
## Documentation
|
|
492
|
-
|
|
493
|
-
### Live Documentation
|
|
494
|
-
Visit [documentation](https://voicenter-ui.netlify.app/) for interactive component examples and demos.
|
|
495
|
-
|
|
496
|
-
## Project Documentation
|
|
497
|
-
For detailed technical documentation, see the [`docs/`](./docs/) directory:
|
|
498
|
-
|
|
499
|
-
- **[Quick Start Guide](./docs/AGENTS_QUICK_START.md)** - For developers working on the library
|
|
500
|
-
- **[Integration Guide](./docs/AGENTS_INTEGRATION_GUIDE.md)** - For using the library in other projects
|
|
501
|
-
- **[Architecture Overview](./docs/ARCHITECTURE.md)** - Project structure and technical details
|
|
502
|
-
- **[Documentation Guide](./docs/DOCUMENTATION_GUIDE.md)** - Working with the documentation system
|
|
1
|
+
# Voicenter UI library for Vue
|
|
2
|
+
This is Vue 3.x + Typescript component library made for Voicenter systems.
|
|
3
|
+
|
|
4
|
+
> **v3.0.0 is a tree-shaking release with breaking changes.** See [`MIGRATION_v3.md`](./MIGRATION_v3.md). The separate `*-extended` package is gone — every component lives in this package now.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm i @voicenter-team/voicenter-ui-plus
|
|
10
|
+
npm i vue@^3.5 element-plus @vueuse/core dayjs lodash-es libphonenumber-js maska
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Sass compiler (build-time)
|
|
14
|
+
|
|
15
|
+
This library customizes element-plus theming via SCSS variable injection at build time. Your bundler needs to be able to compile SCSS. If your project doesn't already use Sass, add it as a dev dependency:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i -D sass-embedded
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This is a **build-time only** requirement — it doesn't add anything to your runtime bundle. Most Vue 3 / Vite projects already have it.
|
|
22
|
+
|
|
23
|
+
Optional peer deps — install only for the heavy components you use:
|
|
24
|
+
|
|
25
|
+
| Component | Peer deps |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `VcPdfDocument` | `pdfjs-dist@^2.9.359` |
|
|
28
|
+
| `VcSoundPlayer` | `wavesurfer.js` |
|
|
29
|
+
| `VcExcelFileUploader` | `xlsx` |
|
|
30
|
+
| `VcImageUploader` | `vue-advanced-cropper` |
|
|
31
|
+
| `VcHtmlEditor` / `VcJsonSchema` | `codemirror @codemirror/lang-html @codemirror/lang-json @codemirror/lang-markdown vue-codemirror6` |
|
|
32
|
+
| `VcMdEditor` | `@milkdown/crepe @milkdown/kit @milkdown/vue @prosemirror-adapter/vue` |
|
|
33
|
+
|
|
34
|
+
### If you're on Vite 8 / rolldown (and skipping some optional peers)
|
|
35
|
+
|
|
36
|
+
Vite 8's rolldown-based bundler validates named imports against optional-peer-dep stubs and fails the build with `MISSING_EXPORT` errors when a heavy component's peer is uninstalled — even when you don't use that component. Add the unused optional peers to `build.rollupOptions.external` in your `vite.config.ts`:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// vite.config.ts
|
|
40
|
+
import { defineConfig } from 'vite'
|
|
41
|
+
import vue from '@vitejs/plugin-vue'
|
|
42
|
+
|
|
43
|
+
export default defineConfig({
|
|
44
|
+
plugins: [ vue() ],
|
|
45
|
+
build: {
|
|
46
|
+
rollupOptions: {
|
|
47
|
+
external: [
|
|
48
|
+
// List only the heavy peers you DON'T install
|
|
49
|
+
/^@milkdown\//, /^@prosemirror/, /^@codemirror\//, /^codemirror/,
|
|
50
|
+
/^vue-codemirror6/, /^vue-advanced-cropper/,
|
|
51
|
+
'wavesurfer.js', 'xlsx', 'pdfjs-dist', /^pdfjs-dist\//
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Earlier Vite versions (5, 6, 7 with rollup) and webpack 5+ don't require this — the older rollup variant warns but doesn't error on optional-peer named imports.
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
### Tree-shake mode (recommended)
|
|
63
|
+
```ts
|
|
64
|
+
import { VcButton, VcInput } from '@voicenter-team/voicenter-ui-plus'
|
|
65
|
+
// Use as local components — no app.use() needed.
|
|
66
|
+
```
|
|
67
|
+
Bundlers drop unused components and their CSS. A consumer importing only `VcButton` ships ~50–150 KB JS + ~10–30 KB CSS.
|
|
68
|
+
|
|
69
|
+
If you use `useConfirmModal`, `useConfirmPopup`, or `NotifyService`, mount global overlays in `App.vue`:
|
|
70
|
+
|
|
71
|
+
```vue
|
|
72
|
+
<script setup lang="ts">
|
|
73
|
+
import { VcPluginOverlays } from '@voicenter-team/voicenter-ui-plus'
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<RouterView />
|
|
78
|
+
<VcPluginOverlays />
|
|
79
|
+
</template>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Plugin mode (global registration)
|
|
83
|
+
```ts
|
|
84
|
+
import VoicenterUI from '@voicenter-team/voicenter-ui-plus/plugin'
|
|
85
|
+
import '@voicenter-team/voicenter-ui-plus/style.css'
|
|
86
|
+
|
|
87
|
+
// Overlay composables can be imported from the same entry:
|
|
88
|
+
// import { useConfirmModal, useConfirmPopup, VcPluginOverlays } from '@voicenter-team/voicenter-ui-plus/plugin'
|
|
89
|
+
|
|
90
|
+
app.use(VoicenterUI, {
|
|
91
|
+
themeConfig, // theme config (see below)
|
|
92
|
+
lang: 'en', // localization
|
|
93
|
+
injectIconFont: true // inject icon-font <link> tags into <head>
|
|
94
|
+
})
|
|
95
|
+
// Confirm modals/popovers/notifications: auto-mounted via VcPluginOverlays
|
|
96
|
+
// (mountOverlays: true by default). Opt out with mountOverlays: false and
|
|
97
|
+
// add <VcPluginOverlays /> to App.vue — also registered globally by the plugin.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Global overlays
|
|
101
|
+
|
|
102
|
+
Several APIs are **state-only** — they update global reactive singletons but do not render UI by themselves:
|
|
103
|
+
|
|
104
|
+
| API | Overlay component |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `useConfirmModal` | `VcConfirmModal` |
|
|
107
|
+
| `useConfirmPopup` | `VcConfirmPopover` |
|
|
108
|
+
| `NotifyService` / `$notify` | `VcNotification` |
|
|
109
|
+
|
|
110
|
+
**Plugin mode:** mounted automatically on `app.use()` (default). Pass `mountOverlays: false` to mount manually.
|
|
111
|
+
|
|
112
|
+
**Notifications:** one top-right host by default. For multiple positions, use `overlayNotifications` in plugin config or mount your own:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
app.use(VoicenterUI, {
|
|
116
|
+
overlayNotifications: [
|
|
117
|
+
{ group: 'top-right', position: 'top-right' },
|
|
118
|
+
{ group: 'bottom-right', position: 'bottom-right' },
|
|
119
|
+
],
|
|
120
|
+
})
|
|
121
|
+
// NotifyService.add({ group: 'bottom-right', ... })
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Or `overlayNotifications: 'none'` and put `<VcNotification />` in App.vue (confirms still auto-mount).
|
|
125
|
+
|
|
126
|
+
**Tree-shake mode:** add `<VcPluginOverlays />` to `App.vue` (bundles confirm hosts; configure via `notifications` prop).
|
|
127
|
+
|
|
128
|
+
Entity components such as `VcEntityListTable` call `useConfirmModal` internally — delete confirmations require overlays to be mounted.
|
|
129
|
+
|
|
130
|
+
2.1. If you are using tailwind update your `tailwind.config.js` with:
|
|
131
|
+
```js
|
|
132
|
+
const voiceTailwindScheme = require('@voicenter-team/voicenter-ui-plus/src/theme/tailwindScheme')
|
|
133
|
+
|
|
134
|
+
module.exports = {
|
|
135
|
+
...yourConfiguration,
|
|
136
|
+
theme: {
|
|
137
|
+
colors: {
|
|
138
|
+
...voiceTailwindScheme
|
|
139
|
+
},
|
|
140
|
+
borderColor: {
|
|
141
|
+
...voiceTailwindScheme
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Theming specification
|
|
148
|
+
The `themeConfig` which is passed as options to the VoicenterUI `vue.use` data could have the following specifications:
|
|
149
|
+
|
|
150
|
+
### Local
|
|
151
|
+
**Config:**
|
|
152
|
+
```js
|
|
153
|
+
{
|
|
154
|
+
type: 'local'
|
|
155
|
+
themeName: 'red' | 'blue' | '...'
|
|
156
|
+
onSetupCallback: () => {
|
|
157
|
+
console.log('Loaded!')
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
**Description:**
|
|
162
|
+
|
|
163
|
+
Such configuration will append to the document element the CSS variables from one of the configuration passed in `themeName` parameter which it will get from theme specification delivered alongside with library
|
|
164
|
+
|
|
165
|
+
**Params:**
|
|
166
|
+
- **themeName**
|
|
167
|
+
- The name of the theme to be injected
|
|
168
|
+
- **onSetupCallback**
|
|
169
|
+
- The function which will be called right after the variables will be injected into the document element. First parameter of which is the theme object which was set up
|
|
170
|
+
|
|
171
|
+
### Remote
|
|
172
|
+
**Config:**
|
|
173
|
+
```js
|
|
174
|
+
{
|
|
175
|
+
type: 'remote'
|
|
176
|
+
brandingSectionName: 'someName'
|
|
177
|
+
apiUrl: 'someUrl'
|
|
178
|
+
brandingSectionName: {
|
|
179
|
+
property: 'data'
|
|
180
|
+
}
|
|
181
|
+
onSetupCallback: () => {
|
|
182
|
+
console.log('Loaded!')
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
**Description:**
|
|
187
|
+
|
|
188
|
+
Such configuration will initiate the call to the specified apiUrl in order to retrieve the JSON object with key-value properties of the CSS variables to inject to document element
|
|
189
|
+
|
|
190
|
+
**Params:**
|
|
191
|
+
- **brandingSectionName**
|
|
192
|
+
- [Optional] The name of the section (tagSection) in the database configuration which will be passed to the API in payload and on response retrieved replaced from resulted values
|
|
193
|
+
- **apiUrl**
|
|
194
|
+
- The API url to which the POST request will be initiated
|
|
195
|
+
- **onSetupCallback**
|
|
196
|
+
- The function which will be called right after the variables will be injected into the document element. First parameter of which is the theme object which was set up
|
|
197
|
+
- **brandingSectionName**
|
|
198
|
+
- [Optional] The payload data that will be sent to the request
|
|
199
|
+
|
|
200
|
+
### Custom JSON
|
|
201
|
+
**Config:**
|
|
202
|
+
```js
|
|
203
|
+
{
|
|
204
|
+
type: 'customJson'
|
|
205
|
+
config: {
|
|
206
|
+
black: '#000000'
|
|
207
|
+
}
|
|
208
|
+
onSetupCallback: () => {
|
|
209
|
+
console.log('Loaded!')
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
**Description:**
|
|
214
|
+
|
|
215
|
+
Such configuration will initiate the styling with custom provided theme
|
|
216
|
+
|
|
217
|
+
**Params:**
|
|
218
|
+
- **config**
|
|
219
|
+
- The object where the key is the variable to be set and the value is the variable value. Check the [themes object](https://github.com/VoicenterTeam/voicenter-ui-plus/blob/master/src/theme/themes.json) to check existing variables
|
|
220
|
+
- **onSetupCallback**
|
|
221
|
+
- The function which will be called right after the variables will be injected into the document element. First parameter of which is the theme object which was set up
|
|
222
|
+
|
|
223
|
+
## Date Handling
|
|
224
|
+
|
|
225
|
+
This library uses **dayjs** for all date operations and formatting. When working with date-related components, use dayjs format tokens (NOT date-fns format tokens).
|
|
226
|
+
|
|
227
|
+
### Format Tokens
|
|
228
|
+
|
|
229
|
+
**Important**: Use dayjs format tokens:
|
|
230
|
+
- `DD` - Day of month (2 digits) - **NOT** `dd`
|
|
231
|
+
- `YYYY` - 4-digit year - **NOT** `yyyy`
|
|
232
|
+
- `MM` - Month (2 digits)
|
|
233
|
+
- `HH` - 24-hour format
|
|
234
|
+
- `mm` - Minutes
|
|
235
|
+
- `ss` - Seconds
|
|
236
|
+
|
|
237
|
+
### Common Formats
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
'DD/MM/YYYY' // 31/12/2024
|
|
241
|
+
'DD-MM-YYYY' // 31-12-2024
|
|
242
|
+
'YYYY-MM-DD' // 2024-12-31
|
|
243
|
+
'DD/MM/YYYY, HH:mm' // 31/12/2024, 14:30
|
|
244
|
+
'DD/MM/YYYY HH:mm:ss' // 31/12/2024 14:30:45
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Usage Example
|
|
248
|
+
|
|
249
|
+
```vue
|
|
250
|
+
<VcDatePicker
|
|
251
|
+
v-model="date"
|
|
252
|
+
format="DD/MM/YYYY"
|
|
253
|
+
input-date-format="DD/MM/YYYY"
|
|
254
|
+
input-time-format="HH:mm"
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Date Utility Functions
|
|
259
|
+
|
|
260
|
+
The library provides a comprehensive set of date utility functions built on dayjs. These utilities are available for use in external projects.
|
|
261
|
+
|
|
262
|
+
### Import Date Utilities
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import {
|
|
266
|
+
formatDate,
|
|
267
|
+
parseDate,
|
|
268
|
+
addDays,
|
|
269
|
+
subtractDays,
|
|
270
|
+
getHours,
|
|
271
|
+
getMinutes,
|
|
272
|
+
getSeconds,
|
|
273
|
+
setTime,
|
|
274
|
+
isAfter,
|
|
275
|
+
isSameAfter,
|
|
276
|
+
isBefore,
|
|
277
|
+
isSameBefore,
|
|
278
|
+
format,
|
|
279
|
+
add,
|
|
280
|
+
sub,
|
|
281
|
+
addFp,
|
|
282
|
+
subFp
|
|
283
|
+
} from '@voicenter-team/voicenter-ui-plus'
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Basic Date Operations
|
|
287
|
+
|
|
288
|
+
#### Formatting Dates
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
// Format a date with default format (YYYY-MM-DD)
|
|
292
|
+
const formatted = formatDate(new Date())
|
|
293
|
+
// Result: "2024-12-31"
|
|
294
|
+
|
|
295
|
+
// Format with custom format
|
|
296
|
+
const custom = formatDate(new Date(), 'DD/MM/YYYY')
|
|
297
|
+
// Result: "31/12/2024"
|
|
298
|
+
|
|
299
|
+
// Using format function (alias)
|
|
300
|
+
const formatted2 = format(new Date(), 'DD/MM/YYYY HH:mm')
|
|
301
|
+
// Result: "31/12/2024 14:30"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Parsing Dates
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
// Parse a date string with format
|
|
308
|
+
const date = parseDate('31/12/2024', 'DD/MM/YYYY')
|
|
309
|
+
// Returns: Date object
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Date Arithmetic
|
|
313
|
+
|
|
314
|
+
#### Adding/Subtracting Days
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// Add days
|
|
318
|
+
const futureDate = addDays(new Date(), 7)
|
|
319
|
+
// Returns: Date 7 days from now
|
|
320
|
+
|
|
321
|
+
// Subtract days
|
|
322
|
+
const pastDate = subtractDays(new Date(), 5)
|
|
323
|
+
// Returns: Date 5 days ago
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### Adding/Subtracting Time Units
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// Add multiple time units
|
|
330
|
+
const newDate = add(new Date(), {
|
|
331
|
+
years: 1,
|
|
332
|
+
months: 2,
|
|
333
|
+
days: 5,
|
|
334
|
+
hours: 3,
|
|
335
|
+
minutes: 30
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
// Subtract multiple time units
|
|
339
|
+
const earlierDate = sub(new Date(), {
|
|
340
|
+
weeks: 2,
|
|
341
|
+
days: 3,
|
|
342
|
+
hours: 12
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
// Functional programming style (reversed arguments)
|
|
346
|
+
const fpDate = addFp({ days: 7 }, new Date())
|
|
347
|
+
const fpDate2 = subFp({ hours: 5 }, new Date())
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Time Operations
|
|
351
|
+
|
|
352
|
+
#### Getting Time Components
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
const date = new Date('2024-12-31T14:30:45')
|
|
356
|
+
|
|
357
|
+
const hours = getHours(date) // 14
|
|
358
|
+
const minutes = getMinutes(date) // 30
|
|
359
|
+
const seconds = getSeconds(date) // 45
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
#### Setting Time
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
// Set time on a date (returns new Date object)
|
|
366
|
+
const newDate = setTime(new Date(), {
|
|
367
|
+
hours: 14,
|
|
368
|
+
minutes: 30,
|
|
369
|
+
seconds: 0
|
|
370
|
+
})
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Date Comparisons
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
const date1 = new Date('2024-12-31')
|
|
377
|
+
const date2 = new Date('2025-01-01')
|
|
378
|
+
|
|
379
|
+
// Check if date1 is after date2
|
|
380
|
+
const isLater = isAfter(date1, date2, 'day')
|
|
381
|
+
// Returns: false
|
|
382
|
+
|
|
383
|
+
// Check if date1 is same or after date2
|
|
384
|
+
const isSameOrLater = isSameAfter(date1, date2, 'day')
|
|
385
|
+
// Returns: false
|
|
386
|
+
|
|
387
|
+
// Check if date1 is before date2
|
|
388
|
+
const isEarlier = isBefore(date1, date2, 'day')
|
|
389
|
+
// Returns: true
|
|
390
|
+
|
|
391
|
+
// Check if date1 is same or before date2
|
|
392
|
+
const isSameOrEarlier = isSameBefore(date1, date2, 'day')
|
|
393
|
+
// Returns: true
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Comparison Units**: The comparison functions accept a `units` parameter (default: `'minute'`). Valid units:
|
|
397
|
+
- `'year'`, `'month'`, `'week'`, `'day'`
|
|
398
|
+
- `'hour'`, `'minute'`, `'second'`
|
|
399
|
+
|
|
400
|
+
### Complete Usage Example
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import {
|
|
404
|
+
formatDate,
|
|
405
|
+
addDays,
|
|
406
|
+
isAfter,
|
|
407
|
+
format,
|
|
408
|
+
add,
|
|
409
|
+
getHours,
|
|
410
|
+
setTime
|
|
411
|
+
} from '@voicenter-team/voicenter-ui-plus'
|
|
412
|
+
|
|
413
|
+
// Format today's date
|
|
414
|
+
const today = formatDate(new Date(), 'DD/MM/YYYY')
|
|
415
|
+
|
|
416
|
+
// Get date 30 days from now
|
|
417
|
+
const futureDate = addDays(new Date(), 30)
|
|
418
|
+
|
|
419
|
+
// Check if a date is in the future
|
|
420
|
+
const isFuture = isAfter(futureDate, new Date(), 'day')
|
|
421
|
+
|
|
422
|
+
// Add 2 weeks and 3 days
|
|
423
|
+
const deadline = add(new Date(), {
|
|
424
|
+
weeks: 2,
|
|
425
|
+
days: 3
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
// Get current hour
|
|
429
|
+
const currentHour = getHours(new Date())
|
|
430
|
+
|
|
431
|
+
// Set specific time
|
|
432
|
+
const meetingTime = setTime(new Date(), {
|
|
433
|
+
hours: 14,
|
|
434
|
+
minutes: 30
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
// Format the result
|
|
438
|
+
const formattedDeadline = format(deadline, 'DD/MM/YYYY HH:mm')
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Notes
|
|
442
|
+
|
|
443
|
+
- All functions accept `Date`, `string`, or `number` as date input
|
|
444
|
+
- All date manipulation functions return new `Date` objects (immutable)
|
|
445
|
+
- Format strings use dayjs format tokens (see Format Tokens section above)
|
|
446
|
+
- These utilities are built on dayjs and maintain compatibility with dayjs format patterns
|
|
447
|
+
|
|
448
|
+
## Contributing: adding a new component
|
|
449
|
+
|
|
450
|
+
The public component surface is defined in **one place**: [`script/components-manifest.mjs`](./script/components-manifest.mjs) — one line per component.
|
|
451
|
+
|
|
452
|
+
```js
|
|
453
|
+
{ name: 'VcMyThing', path: 'components/VcMyThing/VcMyThing.vue' },
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
`npm run generate:entries` materializes the manifest into three fully
|
|
457
|
+
generated files (never edit them by hand — the next generator run
|
|
458
|
+
overwrites them, and the verifier fails the build until they match):
|
|
459
|
+
|
|
460
|
+
- `src/components.gen.ts` — named exports, re-exported by `src/index.ts`
|
|
461
|
+
(tree-shake mode);
|
|
462
|
+
- `src/plugin-components.gen.ts` — `registerComponents(app)`, called by
|
|
463
|
+
the plugin's install (global registration mode);
|
|
464
|
+
- `src/components/exports.ts` — the `GlobalComponents` template typing.
|
|
465
|
+
|
|
466
|
+
`src/index.ts` and `src/plugin.ts` themselves stay hand-written and small.
|
|
467
|
+
The `.gen` modules are safe to route through only because
|
|
468
|
+
`rewriteCssImports()` in `vite.config.ts` strips the CSS imports that
|
|
469
|
+
`vite-plugin-lib-inject-css` aggregates onto them — each component's CSS
|
|
470
|
+
stays in its own chunk, so per-component CSS tree-shaking survives. Don't
|
|
471
|
+
rename the `.gen` files without updating that strip list (the verifier
|
|
472
|
+
guards this wiring too).
|
|
473
|
+
|
|
474
|
+
Typical flows:
|
|
475
|
+
|
|
476
|
+
- **New component**: `node script/create-component.mjs` — scaffolds the
|
|
477
|
+
component folder, adds the manifest line, and regenerates all entries.
|
|
478
|
+
- **Existing .vue file**: add one line to the manifest, then
|
|
479
|
+
`npm run generate:entries`.
|
|
480
|
+
|
|
481
|
+
Every manifest entry is exported from the package root AND registered
|
|
482
|
+
globally in plugin mode — there are no partial modes.
|
|
483
|
+
|
|
484
|
+
`npm run verify:entries` is the safety net: it independently cross-checks
|
|
485
|
+
the manifest, the three generated files and the filesystem (a component
|
|
486
|
+
file that exists but is missing from the manifest fails too). It runs in
|
|
487
|
+
the pre-commit hook (together with `lint-staged` and `ts-check`; hooks are
|
|
488
|
+
installed automatically by `npm install` via husky) and in CI, so an
|
|
489
|
+
inconsistent component surface cannot reach `master`.
|
|
490
|
+
|
|
491
|
+
## Documentation
|
|
492
|
+
|
|
493
|
+
### Live Documentation
|
|
494
|
+
Visit [documentation](https://voicenter-ui.netlify.app/) for interactive component examples and demos.
|
|
495
|
+
|
|
496
|
+
## Project Documentation
|
|
497
|
+
For detailed technical documentation, see the [`docs/`](./docs/) directory:
|
|
498
|
+
|
|
499
|
+
- **[Quick Start Guide](./docs/AGENTS_QUICK_START.md)** - For developers working on the library
|
|
500
|
+
- **[Integration Guide](./docs/AGENTS_INTEGRATION_GUIDE.md)** - For using the library in other projects
|
|
501
|
+
- **[Architecture Overview](./docs/ARCHITECTURE.md)** - Project structure and technical details
|
|
502
|
+
- **[Documentation Guide](./docs/DOCUMENTATION_GUIDE.md)** - Working with the documentation system
|