Composables ​

Composables the kit's components are built on, for building your own components the same way. Each is imported from its own file under eco-vue-js/dist/utils/ or eco-vue-js/dist/composables/.

Clipboard ​

ts
import {doCopy, useCopy} from 'eco-vue-js/dist/utils/useCopy'

useCopy(value) copies a ref or getter to the clipboard and reports it with a notification: "Copied", "Nothing to copy" for an empty value, or "Copy failed" with a hint to allow clipboard access for the site. It returns doCopy, copied — true for a second after a copy — and iconCopy, the copy icon that turns into a check while copied. doCopy(text) is the same without the state, and resolves to whether the copy succeeded.

The notifications need WNotify mounted at the app root.

vue
<template>
  <div class="flex max-w-md items-end gap-2">
    <WInput
      v-model="code"
      title="Invite code"
      no-margin
      class="flex-1"
    />

    <WButton
      :semantic-type="SemanticType.SECONDARY"
      :aria-label="copied ? 'Copied' : 'Copy'"
      @click="doCopy"
    >
      <component
        :is="iconCopy"
        class="square-5"
      />
    </WButton>
  </div>
</template>

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

import {SemanticType} from 'eco-vue-js/dist/utils/SemanticType'
import {useCopy} from 'eco-vue-js/dist/utils/useCopy'

import WButton from 'eco-vue-js/dist/components/Button/WButton.vue'
import WInput from 'eco-vue-js/dist/components/Input/WInput.vue'

const code = ref<string | undefined>('GREEN-THUMB-2026')

const {copied, iconCopy, doCopy} = useCopy(code)
</script>

Component states ​

ts
import {useComponentStates, useComponentStatesButton, useComponentStatesSkeleton} from 'eco-vue-js/dist/utils/useComponentStates'
import {useProvideDisabled, useProvideReadonly, useProvideSkeleton} from 'eco-vue-js/dist/utils/provide'

The kit's controls take readonly, disabled and skeleton from the nearest parent that provides them, unless the prop is set — see Conventions. Your own components can do the same:

  • useComponentStates(props) returns isReadonly, isDisabled and isSkeleton: the prop when it is set, the provided state otherwise. Declare the props as optional booleans, so that unset stays undefined rather than false.
  • useComponentStatesButton(props) is the version for buttons, which have no readonly state: isDisabled is also true inside a readonly parent.
  • useComponentStatesSkeleton(props) returns only isSkeleton, for display components.
  • useProvideReadonly(value), useProvideDisabled(value) and useProvideSkeleton(value) provide a state — a boolean or a ref — to everything inside the calling component, and return the state provided above it. Called without a value they only read it.
vue
<template>
  <div class="grid max-w-md gap-4">
    <div class="flex flex-wrap gap-x-6">
      <WToggle
        v-model="readonly"
        title="Readonly"
      />

      <WToggle
        v-model="skeleton"
        title="Skeleton"
      />
    </div>

    <PlantShelf
      :readonly="readonly"
      :skeleton="skeleton"
    >
      <PlantBadge
        v-for="name in plants"
        :key="name"
        :name="name"
        @water="watered = name"
      />

      <PlantBadge
        name="Cactus"
        :readonly="false"
        @water="watered = 'Cactus'"
      />
    </PlantShelf>

    <span
      v-if="watered"
      class="text-description text-sm"
    >
      Watered {{ watered }}
    </span>
  </div>
</template>

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

import WToggle from 'eco-vue-js/dist/components/Toggle/WToggle.vue'

import PlantBadge from './parts/PlantBadge.vue'
import PlantShelf from './parts/PlantShelf.vue'

const plants = ['Basil', 'Fern']

const readonly = ref(false)
const skeleton = ref(false)
const watered = ref<string>()
</script>

Screen size ​

ts
import {getIsMobile, getIsTablet, getIsTouchDevice, setIsTouchDeviceInit, useIsMobile} from 'eco-vue-js/dist/utils/mobile'

useIsMobile() returns isMobile (below sm, 640px) and isTablet (below xl, 1280px) as computed refs, kept up to date on resize. Both are false until the component mounts, so the server render and the first client render match. getIsMobile() and getIsTablet() read the same once, without reactivity.

getIsTouchDevice() tells whether the device has a touch screen; tooltips with noTouch use it to stay closed. setIsTouchDeviceInit(value) overrides it, e.g. in tests.

Tab activation ​

ts
import {useTabActiveListener} from 'eco-vue-js/dist/utils/useTabActiveListener'

useTabActiveListener(listener) calls listener whenever the tab the component is in becomes active — for something to do once it is in view, such as focusing a field: inputs with autofocus use it to take focus when their tab opens. Outside tabs it does nothing.

Optional router ​

ts
import {useOptionalRoute, useOptionalRouter} from 'eco-vue-js/dist/composables/useOptionalRouter'

The kit works with or without vue-router. useOptionalRouter() returns the app's router when it has one, and otherwise a fallback with the same push, replace and resolve, which navigates by changing location. useOptionalRoute() likewise returns the current route, or one read from location — name is then the path. Both have noRouter: true when they are the fallback. Use them in components that should work in apps without vue-router, as WNavItem does.