remove old files

This commit is contained in:
Benjamin Canac
2024-03-27 12:39:55 +01:00
parent f3fec877c5
commit 85c693e3ba
150 changed files with 0 additions and 12276 deletions

View File

@@ -1,164 +0,0 @@
import { ref, computed } from 'vue'
import type { ComputedRef, WatchSource } from 'vue'
import { logicAnd, logicNot } from '@vueuse/math'
import { useEventListener, useDebounceFn } from '@vueuse/core'
import { useShortcuts } from './useShortcuts'
export interface ShortcutConfig {
handler: Function
usingInput?: string | boolean
whenever?: WatchSource<boolean>[]
}
export interface ShortcutsConfig {
[key: string]: ShortcutConfig | Function
}
export interface ShortcutsOptions {
chainDelay?: number
}
interface Shortcut {
handler: Function
condition: ComputedRef<boolean>
chained: boolean
// KeyboardEvent attributes
key: string
ctrlKey: boolean
metaKey: boolean
shiftKey: boolean
altKey: boolean
// code?: string
// keyCode?: number
}
const chainedShortcutRegex = /^[^-]+.*-.*[^-]+$/
const combinedShortcutRegex = /^[^_]+.*_.*[^_]+$/
export const defineShortcuts = (config: ShortcutsConfig, options: ShortcutsOptions = {}) => {
const { macOS, usingInput } = useShortcuts()
let shortcuts: Shortcut[] = []
const chainedInputs = ref<string[]>([])
const clearChainedInput = () => {
chainedInputs.value.splice(0, chainedInputs.value.length)
}
const debouncedClearChainedInput = useDebounceFn(clearChainedInput, options.chainDelay ?? 800)
const onKeyDown = (e: KeyboardEvent) => {
// Input autocomplete triggers a keydown event
if (!e.key) { return }
const alphabeticalKey = /^[a-z]{1}$/i.test(e.key)
let chainedKey
chainedInputs.value.push(e.key)
// try matching a chained shortcut
if (chainedInputs.value.length >= 2) {
chainedKey = chainedInputs.value.slice(-2).join('-')
for (const shortcut of shortcuts.filter(s => s.chained)) {
if (shortcut.key !== chainedKey) { continue }
if (shortcut.condition.value) {
e.preventDefault()
shortcut.handler()
}
clearChainedInput()
return
}
}
// try matching a standard shortcut
for (const shortcut of shortcuts.filter(s => !s.chained)) {
if (e.key.toLowerCase() !== shortcut.key) { continue }
if (e.metaKey !== shortcut.metaKey) { continue }
if (e.ctrlKey !== shortcut.ctrlKey) { continue }
// shift modifier is only checked in combination with alphabetical keys
// (shift with non-alphabetical keys would change the key)
if (alphabeticalKey && e.shiftKey !== shortcut.shiftKey) { continue }
// alt modifier changes the combined key anyways
// if (e.altKey !== shortcut.altKey) { continue }
if (shortcut.condition.value) {
e.preventDefault()
shortcut.handler()
}
clearChainedInput()
return
}
debouncedClearChainedInput()
}
// Map config to full detailled shortcuts
shortcuts = Object.entries(config).map(([key, shortcutConfig]) => {
if (!shortcutConfig) {
return null
}
// Parse key and modifiers
let shortcut: Partial<Shortcut>
if (key.includes('-') && key !== '-' && !key.match(chainedShortcutRegex)?.length) {
console.trace(`[Shortcut] Invalid key: "${key}"`)
}
if (key.includes('_') && key !== '_' && !key.match(combinedShortcutRegex)?.length) {
console.trace(`[Shortcut] Invalid key: "${key}"`)
}
const chained = key.includes('-') && key !== '-'
if (chained) {
shortcut = {
key: key.toLowerCase(),
metaKey: false,
ctrlKey: false,
shiftKey: false,
altKey: false
}
} else {
const keySplit = key.toLowerCase().split('_').map(k => k)
shortcut = {
key: keySplit.filter(k => !['meta', 'ctrl', 'shift', 'alt'].includes(k)).join('_'),
metaKey: keySplit.includes('meta'),
ctrlKey: keySplit.includes('ctrl'),
shiftKey: keySplit.includes('shift'),
altKey: keySplit.includes('alt')
}
}
shortcut.chained = chained
// Convert Meta to Ctrl for non-MacOS
if (!macOS.value && shortcut.metaKey && !shortcut.ctrlKey) {
shortcut.metaKey = false
shortcut.ctrlKey = true
}
// Retrieve handler function
if (typeof shortcutConfig === 'function') {
shortcut.handler = shortcutConfig
} else if (typeof shortcutConfig === 'object') {
shortcut = { ...shortcut, handler: shortcutConfig.handler }
}
if (!shortcut.handler) {
console.trace('[Shortcut] Invalid value')
return null
}
// Create shortcut computed
const conditions: ComputedRef<boolean>[] = []
if (!(shortcutConfig as ShortcutConfig).usingInput) {
conditions.push(logicNot(usingInput))
} else if (typeof (shortcutConfig as ShortcutConfig).usingInput === 'string') {
conditions.push(computed(() => usingInput.value === (shortcutConfig as ShortcutConfig).usingInput))
}
shortcut.condition = logicAnd(...conditions, ...((shortcutConfig as ShortcutConfig).whenever || []))
return shortcut as Shortcut
}).filter(Boolean) as Shortcut[]
useEventListener('keydown', onKeyDown)
}

View File

@@ -1,85 +0,0 @@
import { computed, ref, provide, inject, onMounted, onUnmounted, getCurrentInstance } from 'vue'
import type { Ref, ComponentInternalInstance } from 'vue'
import { buttonGroup } from '#ui/ui.config'
type ButtonGroupProps = {
orientation?: Ref<'horizontal' | 'vertical'>
size?: Ref<string>
ui?: Ref<Partial<typeof buttonGroup>>
rounded?: Ref<{ start: string, end: string }>
}
// make a ButtonGroupContext type for injection. Should include ButtonGroupProps
type ButtonGroupContext = {
children: ComponentInternalInstance[]
register (child: ComponentInternalInstance): void
unregister (child: ComponentInternalInstance): void
orientation: 'horizontal' | 'vertical'
size: string
ui: Partial<typeof buttonGroup>
rounded: { start: string, end: string }
}
export function useProvideButtonGroup (buttonGroupProps: ButtonGroupProps) {
const instance = getCurrentInstance()
const groupKey = `group-${instance.uid}`
const state = ref({
children: [],
register (child) {
this.children.push(child)
},
unregister (child) {
const index = this.children.indexOf(child)
if (index > -1) {
this.children.splice(index, 1)
}
},
...buttonGroupProps
})
provide(groupKey, state as Ref<ButtonGroupContext>)
}
export function useInjectButtonGroup ({ ui, props }: { ui: any, props: any }) {
const instance = getCurrentInstance()
provide('ButtonGroupContextConsumer', true)
const isParentPartOfGroup = inject('ButtonGroupContextConsumer', false)
// early return if a parent is already part of the group
if (isParentPartOfGroup) {
return {
size: computed(() => props.size),
rounded: computed(() => ui.value.rounded)
}
}
let parent = instance.parent
let groupContext: Ref<ButtonGroupContext> | undefined
// Traverse up the parent chain to find the nearest ButtonGroup
while (parent && !groupContext) {
if (parent.type.name === 'ButtonGroup') {
groupContext = inject(`group-${parent.uid}`)
break
}
parent = parent.parent
}
const positionInGroup = computed(() => groupContext?.value.children.indexOf(instance))
onMounted(() => {
groupContext?.value.register(instance)
})
onUnmounted(() => {
groupContext?.value.unregister(instance)
})
return {
size: computed(() => groupContext?.value.size || props.size),
rounded: computed(() => {
if (!groupContext || positionInGroup.value === -1) return ui.value.rounded
if (groupContext.value.children.length === 1) return groupContext.value.ui.rounded
if (positionInGroup.value === 0) return groupContext.value.rounded.start
if (positionInGroup.value === groupContext.value.children.length - 1) return groupContext.value.rounded.end
return 'rounded-none'
})
}
}

View File

@@ -1,49 +0,0 @@
import { ref, type Ref, onMounted, onUnmounted } from 'vue'
export const useCarouselScroll = (el: Ref<HTMLElement>) => {
const x = ref<number>(0)
function onMouseDown (e) {
el.value.style.scrollSnapType = 'none'
el.value.style.scrollBehavior = 'auto'
x.value = e.pageX
window.addEventListener('mousemove', onMouseMove)
window.addEventListener('mouseup', onMouseUp)
}
function onMouseUp () {
el.value.style.removeProperty('scroll-behavior')
el.value.style.removeProperty('scroll-snap-type')
window.removeEventListener('mousemove', onMouseMove)
window.removeEventListener('mouseup', onMouseUp)
}
function onMouseMove (e) {
e.preventDefault()
const delta = e.pageX - x.value
x.value = e.pageX
el.value.scrollBy(-delta, 0)
}
onMounted(() => {
if (!el.value) {
return
}
el.value.addEventListener('mousedown', onMouseDown)
})
onUnmounted(() => {
if (!el.value) {
return
}
el.value.removeEventListener('mousedown', onMouseDown)
})
}

View File

@@ -1,32 +0,0 @@
import { useClipboard } from '@vueuse/core'
import type { Notification } from '../types/notification'
import { useToast } from './useToast'
export function useCopyToClipboard (options: Partial<Notification> = {}) {
const { copy: copyToClipboard, isSupported } = useClipboard()
const toast = useToast()
function copy (text: string, success: { title?: string, description?: string } = {}, failure: { title?: string, description?: string } = {}) {
if (!isSupported) {
return
}
copyToClipboard(text).then(() => {
if (!success.title && !success.description) {
return
}
toast.add({ ...success, ...options })
}, function (e) {
toast.add({
...failure,
description: failure.description || e.message,
...options
})
})
}
return {
copy
}
}

View File

@@ -1,65 +0,0 @@
import { inject, ref, computed } from 'vue'
import { type UseEventBusReturn, useDebounceFn } from '@vueuse/core'
import type { FormEvent, FormEventType, InjectedFormGroupValue } from '../types/form'
type InputProps = {
id?: string
size?: string | number | symbol
color?: string
name?: string
eagerValidation?: boolean
legend?: string | null
}
export const useFormGroup = (inputProps?: InputProps, config?: any) => {
const formBus = inject<UseEventBusReturn<FormEvent, string> | undefined>('form-events', undefined)
const formGroup = inject<InjectedFormGroupValue | undefined>('form-group', undefined)
const formInputs = inject<any>('form-inputs', undefined)
if (formGroup) {
if (inputProps?.id) {
// Updates for="..." attribute on label if inputProps.id is provided
formGroup.inputId.value = inputProps?.id
}
if (formInputs) {
formInputs.value[formGroup.name.value] = formGroup.inputId.value
}
}
const blurred = ref(false)
function emitFormEvent (type: FormEventType, path: string) {
if (formBus) {
formBus.emit({ type, path })
}
}
function emitFormBlur () {
emitFormEvent('blur', formGroup?.name.value as string)
blurred.value = true
}
function emitFormChange () {
emitFormEvent('change', formGroup?.name.value as string)
}
const emitFormInput = useDebounceFn(() => {
if (blurred.value || formGroup?.eagerValidation.value) {
emitFormEvent('input', formGroup?.name.value as string)
}
}, 300)
return {
inputId: computed(() => inputProps?.id ?? formGroup?.inputId.value),
name: computed(() => inputProps?.name ?? formGroup?.name.value),
size: computed(() => {
const formGroupSize = config.size[formGroup?.size.value as string] ? formGroup?.size.value : null
return inputProps?.size ?? formGroupSize ?? config?.default?.size
}),
color: computed(() => formGroup?.error?.value ? 'red' : inputProps?.color),
emitFormBlur,
emitFormInput,
emitFormChange
}
}

View File

@@ -1,51 +0,0 @@
import { ref, inject } from 'vue'
import type { ShallowRef, Component, InjectionKey } from 'vue'
import { createSharedComposable } from '@vueuse/core'
import type { ComponentProps } from '../types/component'
import type { Modal, ModalState } from '../types/modal'
export const modalInjectionKey: InjectionKey<ShallowRef<ModalState>> = Symbol('nuxt-ui.modal')
function _useModal () {
const modalState = inject(modalInjectionKey)
const isOpen = ref(false)
function open<T extends Component> (component: T, props?: Modal & ComponentProps<T>) {
modalState.value = {
component,
props: props ?? {}
}
isOpen.value = true
}
function close () {
isOpen.value = false
modalState.value = {
component: 'div',
props: {}
}
}
/**
* Allows updating the modal props
*/
function patch <T extends Component = {}> (props: Partial<Modal & ComponentProps<T>>) {
modalState.value = {
...modalState.value,
props: {
...modalState.value.props,
...props
}
}
}
return {
isOpen,
open,
close,
patch
}
}
export const useModal = createSharedComposable(_useModal)

View File

@@ -1,102 +0,0 @@
import { ref, onMounted, watchEffect } from 'vue'
import type { Ref } from 'vue'
import { popperGenerator, defaultModifiers } from '@popperjs/core/lib/popper-lite'
import type { VirtualElement } from '@popperjs/core/lib/popper-lite'
import type { Instance } from '@popperjs/core'
import flip from '@popperjs/core/lib/modifiers/flip'
import offset from '@popperjs/core/lib/modifiers/offset'
import preventOverflow from '@popperjs/core/lib/modifiers/preventOverflow'
import computeStyles from '@popperjs/core/lib/modifiers/computeStyles'
import eventListeners from '@popperjs/core/lib/modifiers/eventListeners'
import arrowModifier from '@popperjs/core/lib/modifiers/arrow'
import { unrefElement } from '@vueuse/core'
import type { MaybeElement } from '@vueuse/core'
import type { PopperOptions } from '../types/popper'
export const createPopper = popperGenerator({
defaultModifiers: [...defaultModifiers, offset, flip, preventOverflow, computeStyles, eventListeners, arrowModifier]
})
export function usePopper ({
locked = false,
overflowPadding = 8,
offsetDistance = 8,
offsetSkid = 0,
gpuAcceleration = true,
adaptive = true,
scroll = true,
resize = true,
arrow = false,
placement,
strategy
}: PopperOptions, virtualReference?: Ref<Element | VirtualElement>) {
const reference = ref<MaybeElement>(null)
const popper = ref<MaybeElement>(null)
const instance = ref<Instance | null>(null)
onMounted(() => {
watchEffect((onInvalidate) => {
if (!popper.value) { return }
if (!reference.value && !virtualReference?.value) { return }
const popperEl = unrefElement(popper)
const referenceEl = virtualReference?.value || unrefElement(reference)
// if (!(referenceEl instanceof HTMLElement)) { return }
if (!(popperEl instanceof HTMLElement)) { return }
if (!referenceEl) { return }
const config: Record<string, any> = {
modifiers: [
{
name: 'flip',
enabled: !locked
},
{
name: 'preventOverflow',
options: {
padding: overflowPadding
}
},
{
name: 'offset',
options: {
offset: [offsetSkid, offsetDistance]
}
},
{
name: 'computeStyles',
options: {
adaptive,
gpuAcceleration
}
},
{
name: 'eventListeners',
options: {
scroll,
resize
}
},
{
name: 'arrow',
enabled: arrow
}
]
}
if (placement) {
config.placement = placement
}
if (strategy) {
config.strategy = strategy
}
instance.value = createPopper(referenceEl, popperEl, config)
onInvalidate(instance.value.destroy)
})
})
return [reference, popper, instance] as const
}

View File

@@ -1,36 +0,0 @@
import { createSharedComposable, useActiveElement } from '@vueuse/core'
import { ref, computed, onMounted } from 'vue'
import type {} from '@vueuse/shared'
export const _useShortcuts = () => {
const macOS = computed(() => import.meta.client && navigator && navigator.userAgent && navigator.userAgent.match(/Macintosh;/))
const metaSymbol = ref(' ')
const activeElement = useActiveElement()
const usingInput = computed(() => {
const tagName = activeElement.value?.tagName
const contentEditable = activeElement.value?.contentEditable
const usingInput = !!(tagName === 'INPUT' || tagName === 'TEXTAREA' || contentEditable === 'true' || contentEditable === 'plaintext-only')
if (usingInput) {
return ((activeElement.value as any)?.name as string) || true
}
return false
})
onMounted(() => {
metaSymbol.value = macOS.value ? '⌘' : 'Ctrl'
})
return {
macOS,
metaSymbol,
activeElement,
usingInput
}
}
export const useShortcuts = createSharedComposable(_useShortcuts)

View File

@@ -1,55 +0,0 @@
import { ref, inject } from 'vue'
import { createSharedComposable } from '@vueuse/core'
import type { ShallowRef, Component, InjectionKey } from 'vue'
import type { ComponentProps } from '../types/component'
import type { Slideover, SlideoverState } from '../types/slideover'
export const slidOverInjectionKey: InjectionKey<ShallowRef<SlideoverState>> =
Symbol('nuxt-ui.slideover')
function _useSlideover () {
const slideoverState = inject(slidOverInjectionKey)
const isOpen = ref(false)
function open<T extends Component> (component: T, props?: Slideover & ComponentProps<T>) {
if (!slideoverState) {
throw new Error('useSlideover() is called without provider')
}
slideoverState.value = {
component,
props: props ?? {}
}
isOpen.value = true
}
function close () {
if (!slideoverState) return
isOpen.value = false
}
/**
* Allows updating the slideover props
*/
function patch<T extends Component = {}> (props: Partial<Slideover & ComponentProps<T>>) {
if (!slideoverState) return
slideoverState.value = {
...slideoverState.value,
props: {
...slideoverState.value.props,
...props
}
}
}
return {
open,
close,
patch,
isOpen
}
}
export const useSlideover = createSharedComposable(_useSlideover)

View File

@@ -1,63 +0,0 @@
import { ref, computed } from 'vue-demi'
import { useTimestamp } from '@vueuse/core'
import type { UseTimestampOptions } from '@vueuse/core'
export function useTimer (cb: (...args: unknown[]) => any, interval: number, options?: UseTimestampOptions<true>) {
let timer: number | null = null
const { pause: tPause, resume: tResume, timestamp } = useTimestamp({ ...(options || {}), controls: true })
const startTime = ref<number | null>(null)
const remaining = computed(() => {
if (!startTime.value) {
return 0
}
return interval - (timestamp.value - startTime.value)
})
function set (...args: unknown[]) {
timer = setTimeout(() => {
timer = null
startTime.value = null
cb(...args)
}, remaining.value) as unknown as number
}
function clear () {
if (timer) {
clearTimeout(timer)
timer = null
}
}
function start () {
startTime.value = Date.now()
set()
}
function stop () {
clear()
tPause()
}
function pause () {
clear()
tPause()
}
function resume () {
set()
tResume()
startTime.value = (startTime.value || 0) + (Date.now() - timestamp.value)
}
start()
return {
start,
stop,
pause,
resume,
remaining
}
}

View File

@@ -1,29 +0,0 @@
import type { Notification } from '../types/notification'
import { useState } from '#imports'
export function useToast () {
const notifications = useState<Notification[]>('notifications', () => [])
function add (notification: Partial<Notification>) {
const body = {
id: new Date().getTime().toString(),
...notification
}
const index = notifications.value.findIndex((n: Notification) => n.id === body.id)
if (index === -1) {
notifications.value.push(body as Notification)
}
return body
}
function remove (id: string) {
notifications.value = notifications.value.filter((n: Notification) => n.id !== id)
}
return {
add,
remove
}
}

View File

@@ -1,31 +0,0 @@
import { computed, toValue, useAttrs } from 'vue'
import type { Ref } from 'vue'
import { useAppConfig } from '#imports'
import { mergeConfig, omit, get } from '../utils'
import type { Strategy } from '../types'
export const useUI = <T>(key, $ui?: Ref<Partial<T> & { strategy?: Strategy } | undefined>, $config?: Ref<T> | T, $wrapperClass?: Ref<string>, withAppConfig: boolean = false) => {
const $attrs = useAttrs()
const appConfig = useAppConfig()
const ui = computed(() => {
const _ui = toValue($ui)
const _config = toValue($config)
const _wrapperClass = toValue($wrapperClass)
return mergeConfig<T>(
_ui?.strategy || (appConfig.ui?.strategy as Strategy),
_wrapperClass ? { wrapper: _wrapperClass } : {},
_ui || {},
(process.dev || withAppConfig) ? get(appConfig.ui, key, {}) : {},
_config || {}
)
})
const attrs = computed(() => omit($attrs, ['class']))
return {
ui,
attrs
}
}