Skip to content

Commit

Permalink
feat(visually-hidden): add visually hidden component (#239)
Browse files Browse the repository at this point in the history
* feat(visually-hidden): add visually hidden component

* chore: fix type

* chore: add to nuxt playground

* fix: package and demo
  • Loading branch information
dammy001 authored Jul 22, 2023
1 parent 3721780 commit b4f6cbf
Show file tree
Hide file tree
Showing 15 changed files with 318 additions and 9 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@oku-ui/provide": "workspace:^",
"@oku-ui/separator": "workspace:^",
"@oku-ui/switch": "workspace:^",
"@oku-ui/visually-hidden": "workspace:^",
"@oku-ui/toggle": "workspace:^",
"@oku-ui/use-composable": "workspace:^",
"@oku-ui/utils": "workspace:^",
Expand Down Expand Up @@ -102,7 +103,7 @@
},
"lint-staged": {
"*.{[jt]s?(x),vue}": [
"npx pnpm lint:fix"
"pnpm lint:fix"
]
}
}
10 changes: 10 additions & 0 deletions packages/components/visually-hidden/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# `@oku-ui/visually-hidden`

## Installation

```sh
$ pnpm add @oku-ui/visually-hidden
```

## Usage
...
12 changes: 12 additions & 0 deletions packages/components/visually-hidden/build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
entries: [
{
builder: 'mkdist',
input: './src/',
pattern: ['**/!(*.test|*.stories).ts'],
},
],
declaration: true,
})
48 changes: 48 additions & 0 deletions packages/components/visually-hidden/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@oku-ui/visually-hidden",
"type": "module",
"version": "0.0.0",
"license": "MIT",
"source": "src/index.ts",
"funding": "https://github.com/sponsors/productdevbook",
"homepage": "https://oku-ui.com/primitives",
"repository": {
"type": "git",
"url": "git+https://github.com/oku-ui/primitives.git",
"directory": "packages/components/visually-hidden"
},
"bugs": {
"url": "https://github.com/oku-ui/primitives/issues"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs"
}
},
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"engines": {
"node": ">=18"
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch"
},
"peerDependencies": {
"vue": "^3.3.0"
},
"dependencies": {
"@oku-ui/primitive": "latest",
"@oku-ui/use-composable": "latest"
},
"devDependencies": {
"tsconfig": "workspace:^"
},
"publishConfig": {
"access": "public"
}
}
68 changes: 68 additions & 0 deletions packages/components/visually-hidden/src/VisuallyHidden.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Primitive } from '@oku-ui/primitive'
import type {
ElementType,
MergeProps,
PrimitiveProps,
} from '@oku-ui/primitive'
import { useRef } from '@oku-ui/use-composable'
import type { CSSProperties } from 'vue'
import { defineComponent, h } from 'vue'

const NAME = 'OkuVisuallyHidden'

type VisuallyHiddenElement = ElementType<'button'>

interface VisuallyHiddenProps extends PrimitiveProps {}

const VisuallyHidden = defineComponent({
name: NAME,
inheritAttrs: false,
props: {
asChild: {
type: Boolean,
default: undefined,
},
},
setup(props, { attrs, expose }) {
const { ...visuallyHiddenAttrs } = attrs as VisuallyHiddenElement

const { $el, newRef } = useRef<VisuallyHiddenElement>()

expose({
innerRef: $el,
})

const originalReturn = () =>
h(Primitive.span, {
ref: newRef,
asChild: props.asChild,
...visuallyHiddenAttrs,
style: {
position: 'absolute',
border: 0,
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: 'hidden',
clip: 'rect(0, 0, 0, 0)',
whiteSpace: 'nowrap',
wordWrap: 'normal',
...(visuallyHiddenAttrs.style as CSSProperties),
},
})

return originalReturn as unknown as {
innerRef: VisuallyHiddenElement
}
},
})

type _VisuallyHidden = MergeProps<VisuallyHiddenProps, VisuallyHiddenElement>

const OkuVisuallyHidden = VisuallyHidden as typeof VisuallyHidden &
(new () => { $props: _VisuallyHidden })

export { OkuVisuallyHidden }

export type { VisuallyHiddenProps }
1 change: 1 addition & 0 deletions packages/components/visually-hidden/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './VisuallyHidden'
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { Meta, StoryObj } from '@storybook/vue3'
import type { IVisuallyHiddenProps } from './VisuallyHiddenDemo.vue'
import OkuVisuallyHiddenComponent from './VisuallyHiddenDemo.vue'

interface StoryProps extends IVisuallyHiddenProps {}

const meta = {
title: 'Utilities/VisuallyHidden',
component: OkuVisuallyHiddenComponent,
args: {
template: '#1',
},
argTypes: {
template: {
control: 'text',
},
},
tags: ['autodocs'],
} satisfies Meta<typeof OkuVisuallyHiddenComponent> & {
args: StoryProps
}

export default meta
type Story = StoryObj<typeof meta> & {
args: StoryProps
}

export const Styled: Story = {
args: {
template: '#1',
// allShow: true,
},

render: (args: any) => ({
components: { OkuVisuallyHiddenComponent },
setup() {
return { args }
},
template: `
<OkuVisuallyHiddenComponent v-bind="args" />
`,
}),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script setup lang="ts">
import type { VisuallyHiddenProps } from '@oku-ui/visually-hidden'
import { OkuVisuallyHidden } from '@oku-ui/visually-hidden'
export interface IVisuallyHiddenProps extends VisuallyHiddenProps {
template?: '#1'
allshow?: boolean
}
defineProps<IVisuallyHiddenProps>()
</script>

<template>
<button class="bg-gray-200 w-10 h-10">
<OkuVisuallyHidden>Save the file</OkuVisuallyHidden>
<span aria-hidden>💾</span>
</button>
</template>
51 changes: 51 additions & 0 deletions packages/components/visually-hidden/src/visually-hidden.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import { OkuVisuallyHidden } from '.'

describe('OkuVisuallyHidden', () => {
it('renders correctly with default props', () => {
const wrapper = mount(OkuVisuallyHidden)
expect(wrapper.exists()).toBe(true)

expect(wrapper.element.tagName.toLowerCase()).toBe('span')

const style = wrapper.element.getAttribute('style')
expect(style).toBe(
'position: absolute; border: 0px; padding: 0px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; word-wrap: normal;',
)

// The component should have a ref named 'innerRef'
expect(wrapper.vm.innerRef).toBeDefined()
// @ts-expect-error "working"
expect(wrapper.vm.innerRef.tagName.toLowerCase()).toBe('span')
})

it('applies ref correctly', () => {
const wrapper = mount(OkuVisuallyHidden)
expect(wrapper.vm.innerRef).toBeDefined()
// @ts-expect-error "working"
expect(wrapper.vm.innerRef.tagName.toLowerCase()).toBe('span')
})

it('renders correctly with custom style', () => {
const style = {
background: 'red',
color: 'white',
}

const wrapper = mount(OkuVisuallyHidden, {
attrs: {
style,
},
})

const inlineStyle = wrapper.element.getAttribute('style')
expect(inlineStyle).toContain('position: absolute;')
expect(inlineStyle).toContain('border: 0px;')
expect(inlineStyle).toContain('overflow: hidden;')
expect(inlineStyle).toContain('white-space: nowrap;')
expect(inlineStyle).toContain('word-wrap: normal;')
expect(inlineStyle).toContain('background: red;')
expect(inlineStyle).toContain('color: white;')
})
})
10 changes: 10 additions & 0 deletions packages/components/visually-hidden/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "tsconfig/node16.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},
"include": [
"src"
]
}
22 changes: 22 additions & 0 deletions packages/components/visually-hidden/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { defineConfig } from 'tsup'
import pkg from './package.json'

const external = [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
]

export default defineConfig((options) => {
return [
{
...options,
entryPoints: ['src/index.ts'],
external,
dts: true,
clean: true,
target: 'node16',
format: ['esm'],
outExtension: () => ({ js: '.mjs' }),
},
]
})
3 changes: 2 additions & 1 deletion playground/nuxt3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"@oku-ui/label": "workspace:^",
"@oku-ui/progress": "workspace:^",
"@oku-ui/separator": "workspace:^",
"@oku-ui/switch": "workspace:^"
"@oku-ui/switch": "workspace:^",
"@oku-ui/visually-hidden": "workspace:^"
},
"devDependencies": {
"@nuxtjs/tailwindcss": "^6.8.0",
Expand Down
5 changes: 5 additions & 0 deletions playground/nuxt3/pages/visually-hidden.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script setup lang="ts"></script>

<template>
<VisuallyHiddenDemo template="#1" all-show />
</template>
Loading

0 comments on commit b4f6cbf

Please sign in to comment.