initial
This commit is contained in:
44
layers/ui/composables/use-checkbox.ts
Normal file
44
layers/ui/composables/use-checkbox.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { useField } from 'vee-validate'
|
||||
import { computed, ref, toRef } from 'vue'
|
||||
import type { ComponentInternalInstance } from 'vue'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
label?: string
|
||||
disabled?: boolean
|
||||
modelValue?: boolean | string | number
|
||||
trueValue?: boolean | string | number
|
||||
falseValue?: boolean | string | number
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export default (props: Props, slots: ComponentInternalInstance['slots']) => {
|
||||
const { checked, errorMessage, handleChange } = useField(
|
||||
toRef(props, 'id'),
|
||||
computed(() => ({
|
||||
required: props.required,
|
||||
})),
|
||||
{
|
||||
type: 'checkbox',
|
||||
initialValue: props.modelValue,
|
||||
checkedValue: props.trueValue ?? true,
|
||||
uncheckedValue: props.falseValue ?? false,
|
||||
syncVModel: true,
|
||||
},
|
||||
)
|
||||
|
||||
const focused = ref(false)
|
||||
|
||||
const active = computed(() => !props.disabled)
|
||||
const invalid = computed(() => active.value && !!errorMessage.value)
|
||||
const hasLabel = computed(() => !!props.label || slots.default)
|
||||
|
||||
return {
|
||||
focused,
|
||||
checked,
|
||||
active,
|
||||
invalid,
|
||||
hasLabel,
|
||||
handleChange,
|
||||
}
|
||||
}
|
||||
63
layers/ui/composables/use-classname.ts
Normal file
63
layers/ui/composables/use-classname.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
const namespace = 'ui'
|
||||
const statePrefix = 'is-'
|
||||
|
||||
function _bem(namespace: string, block: string, blockSuffix: string, element: string, modifier: string) {
|
||||
let cls = `${block}`
|
||||
if (blockSuffix)
|
||||
cls += `-${blockSuffix}`
|
||||
|
||||
if (element)
|
||||
cls += `__${element}`
|
||||
|
||||
if (modifier)
|
||||
cls += `--${modifier}`
|
||||
|
||||
return cls
|
||||
}
|
||||
|
||||
export default (block: string) => {
|
||||
const b = (blockSuffix: string = '') => _bem(namespace, block, blockSuffix, '', '')
|
||||
const e = (element: string) =>
|
||||
element ? _bem(namespace, block, '', element, '') : ''
|
||||
const m = (modifier: string) =>
|
||||
modifier ? _bem(namespace, block, '', '', modifier) : ''
|
||||
const be = (blockSuffix: string, element: string) =>
|
||||
blockSuffix && element
|
||||
? _bem(namespace, block, blockSuffix, element, '')
|
||||
: ''
|
||||
const em = (element: string, modifier: string) =>
|
||||
element && modifier ? _bem(namespace, block, '', element, modifier) : ''
|
||||
const bm = (blockSuffix: string, modifier: string) =>
|
||||
blockSuffix && modifier
|
||||
? _bem(namespace, block, blockSuffix, '', modifier)
|
||||
: ''
|
||||
const bem = (blockSuffix: string, element: string, modifier: string) =>
|
||||
blockSuffix && element && modifier
|
||||
? _bem(namespace, block, blockSuffix, element, modifier)
|
||||
: ''
|
||||
const is = (name: string, ...args: any[]) => {
|
||||
const state = args.length >= 1 ? args[0] : true
|
||||
return name && state ? `${statePrefix}${name}` : ''
|
||||
}
|
||||
const has = (name: string, ...args: any[]) => {
|
||||
const state = args.length >= 1 ? args[0] : true
|
||||
return name && state ? `has-${name}` : ''
|
||||
}
|
||||
const exp = (condition: boolean, trueState: string, falseState: string = '') => {
|
||||
return condition ? trueState : falseState
|
||||
}
|
||||
|
||||
return {
|
||||
namespace,
|
||||
b,
|
||||
e,
|
||||
m,
|
||||
be,
|
||||
em,
|
||||
bm,
|
||||
bem,
|
||||
is,
|
||||
has,
|
||||
exp,
|
||||
}
|
||||
}
|
||||
56
layers/ui/composables/use-fuse-search.js
Normal file
56
layers/ui/composables/use-fuse-search.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import Fuse from 'fuse.js'
|
||||
import { isRef, ref, unref, watch } from 'vue'
|
||||
|
||||
export default (items, options, term) => {
|
||||
const fuse = ref(null)
|
||||
const result = ref(unref(items))
|
||||
|
||||
watch(items, (value) => {
|
||||
if (fuse.value) {
|
||||
fuse.value.setCollection(unref(value))
|
||||
result.value = unref(items)
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => options,
|
||||
(value) => {
|
||||
fuse.value = new Fuse(unref(items), { minMatchCharLength: 2, ...value })
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
if (isRef(term)) {
|
||||
watch(term, (value) => {
|
||||
search(value)
|
||||
})
|
||||
}
|
||||
|
||||
const search = (term = '') => {
|
||||
if (!fuse.value)
|
||||
return
|
||||
|
||||
term = term.trim()
|
||||
|
||||
if (term.length < 2) {
|
||||
result.value = unref(items)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const documents = fuse.value.search(term)
|
||||
|
||||
result.value = documents.map(doc => doc.item)
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
result.value = unref(items)
|
||||
}
|
||||
|
||||
return {
|
||||
fuse,
|
||||
result,
|
||||
search,
|
||||
reset,
|
||||
}
|
||||
}
|
||||
27
layers/ui/composables/use-global-config.ts
Normal file
27
layers/ui/composables/use-global-config.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { computed, getCurrentInstance, inject, provide, unref } from 'vue'
|
||||
import type { MaybeRef, Ref } from 'vue'
|
||||
|
||||
export function useGlobalConfig(
|
||||
key: string,
|
||||
defaultValue: unknown = undefined,
|
||||
): Ref<unknown> {
|
||||
const config = inject('GLOBAL_CONFIG') as MaybeRef<unknown>
|
||||
|
||||
if (key)
|
||||
return computed(() => unref(config)?.[key] ?? defaultValue)
|
||||
else
|
||||
return config
|
||||
}
|
||||
|
||||
export function provideGlobalConfig(config, app) {
|
||||
const inSetup = !!getCurrentInstance()
|
||||
|
||||
const provideFn = app?.provide ?? (inSetup ? provide : undefined)
|
||||
|
||||
if (!provideFn)
|
||||
return
|
||||
|
||||
provideFn('GLOBAL_CONFIG', config)
|
||||
|
||||
return config
|
||||
}
|
||||
3
layers/ui/composables/use-notify.ts
Normal file
3
layers/ui/composables/use-notify.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import notify from '../components/notification/notify'
|
||||
|
||||
export default () => notify
|
||||
40
layers/ui/composables/use-radio.ts
Normal file
40
layers/ui/composables/use-radio.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { useField } from 'vee-validate'
|
||||
import { computed, ref, toRef } from 'vue'
|
||||
import type { ComponentInternalInstance } from 'vue'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
value: string | number
|
||||
label?: string
|
||||
disabled?: boolean
|
||||
modelValue?: string | number
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export default (props: Props, slots: ComponentInternalInstance['slots']) => {
|
||||
const { checked, handleChange } = useField(
|
||||
toRef(props, 'id'),
|
||||
computed(() => ({
|
||||
required: props.required,
|
||||
})),
|
||||
{
|
||||
type: 'radio',
|
||||
initialValue: props.modelValue,
|
||||
checkedValue: props.value,
|
||||
syncVModel: true,
|
||||
},
|
||||
)
|
||||
|
||||
const focused = ref(false)
|
||||
|
||||
const active = computed(() => !props.disabled)
|
||||
const hasLabel = computed(() => !!props.label || slots.default)
|
||||
|
||||
return {
|
||||
focused,
|
||||
active,
|
||||
checked,
|
||||
hasLabel,
|
||||
handleChange,
|
||||
}
|
||||
}
|
||||
61
layers/ui/composables/use-timer.js
Normal file
61
layers/ui/composables/use-timer.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import { computed, onMounted, onUnmounted, ref, unref, watch } from 'vue'
|
||||
|
||||
export default function useTimer(expirationTime) {
|
||||
const now = ref(Date.now())
|
||||
const remainingTime = ref(calcRemainingTime())
|
||||
const requestId = ref()
|
||||
|
||||
const isPaused = computed(() => !requestId.value)
|
||||
const isPassed = computed(() => remainingTime.value === 0)
|
||||
|
||||
function calcRemainingTime() {
|
||||
return Math.max(Math.ceil((unref(expirationTime) - now.value) / 1000), 0)
|
||||
}
|
||||
|
||||
function update() {
|
||||
now.value = Date.now()
|
||||
|
||||
const newRemainingTime = calcRemainingTime()
|
||||
|
||||
if (newRemainingTime !== remainingTime.value)
|
||||
remainingTime.value = newRemainingTime
|
||||
|
||||
if (remainingTime.value > 0)
|
||||
requestId.value = window.requestAnimationFrame(update)
|
||||
}
|
||||
|
||||
function start() {
|
||||
requestId.value = requestAnimationFrame(update)
|
||||
}
|
||||
|
||||
function stop() {
|
||||
cancelAnimationFrame(requestId.value)
|
||||
|
||||
requestId.value = null
|
||||
}
|
||||
|
||||
watch(expirationTime, () => {
|
||||
if (!isPaused.value) {
|
||||
remainingTime.value = calcRemainingTime()
|
||||
|
||||
stop()
|
||||
start()
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
start()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
stop()
|
||||
})
|
||||
|
||||
return {
|
||||
remainingTime,
|
||||
isPaused,
|
||||
isPassed,
|
||||
start,
|
||||
stop,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user