Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(useTextDirection): new function #1678

Merged
merged 5 commits into from Jul 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/core/index.ts
Expand Up @@ -102,6 +102,7 @@ export * from './useStyleTag'
export * from './useSupported'
export * from './useSwipe'
export * from './useTemplateRefsList'
export * from './useTextDirection'
export * from './useTextSelection'
export * from './useTextareaAutosize'
export * from './useThrottledRefHistory'
Expand Down
41 changes: 41 additions & 0 deletions packages/core/useTextDirection/demo.vue
@@ -0,0 +1,41 @@
<script setup lang="ts">
import { computed, onUnmounted } from 'vue'

import { useTextDirection } from './index'

const dir = useTextDirection({
selector: '#_useTextDirectionDemo',
})
const text = computed(() =>
dir.value === 'ltr'
? 'This paragraph is in English and correctly goes left to right.'
: 'This paragraph is in English but incorrectly goes right to left.',
)

const handleOnClick = () => {
dir.value = dir.value === 'rtl' ? 'ltr' : 'rtl'
}
</script>

<template>
<div id="_useTextDirectionDemo">
<p>
{{ text }}
</p>
<hr>
<button @click="handleOnClick">
<span class="ml-2">{{ dir.toUpperCase() }}</span>
</button>
<span class="p-4 opacity-50">Click to change the direaction</span>
</div>
</template>

<style scoped>
#_useTextDirectionDemo[dir='rtl']
p {
color: red;
}
button {
margin-right: 0.5em;
}
</style>
35 changes: 35 additions & 0 deletions packages/core/useTextDirection/index.md
@@ -0,0 +1,35 @@
---
category: Browser
---

# useTextDirection

Reactive [dir](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir) of the element's text.

## Usage

```ts
import { useTextDirection } from '@vueuse/core'

const dir = useTextDirection() // Ref<'ltr' | 'rtl' | 'auto'>
```

By default, it returns `rlt` direction when dir `rtl` is applied to the `html` tag, for example:

```html
<!--ltr-->
<html> ... </html>

<!--rtl-->
<html dir="rtl"> ... </html>
```

## Options

```ts
import { useTextDirection } from '@vueuse/core'

const mode = useTextDirection({
selector: 'body'
}) // Ref<'ltr' | 'rtl' | 'auto'>
```
75 changes: 75 additions & 0 deletions packages/core/useTextDirection/index.ts
@@ -0,0 +1,75 @@
import { tryOnMounted } from '@vueuse/shared'
import { computed, ref } from 'vue-demi'

import type { MaybeElement } from '../unrefElement'
import { useMutationObserver } from '../useMutationObserver'
import type { ConfigurableDocument } from '../_configurable'
import { defaultDocument } from '../_configurable'

export type UseTextDirectionValue = 'ltr' | 'rtl' | 'auto'

export interface UseTextDirectionOptions extends ConfigurableDocument {
/**
* CSS Selector for the target element applying to
*
* @default 'html'
*/
selector?: string
/**
* Observe `document.querySelector(selector)` changes using MutationObserve
*
* @default false
*/
observe?: boolean
/**
* Initial value
*
* @default 'ltr'
*/
initialValue?: UseTextDirectionValue
}

/**
* Reactive dir of the element's text.
*
* @see https://vueuse.org/useTextDirection
*/
export function useTextDirection(options: UseTextDirectionOptions = {}) {
const {
document = defaultDocument,
selector = 'html',
observe = false,
initialValue = 'ltr',
} = options

function getValue() {
return document?.querySelector(selector)?.getAttribute('dir') as UseTextDirectionValue ?? initialValue
}

const dir = ref<UseTextDirectionValue>(getValue())

tryOnMounted(() => dir.value = getValue())

if (observe && document) {
useMutationObserver(
document.querySelector(selector) as MaybeElement,
() => dir.value = getValue(),
{ attributes: true },
)
}

return computed<UseTextDirectionValue>({
get() {
return dir.value
},
set(v) {
dir.value = v
if (!document)
return
if (dir.value)
document.querySelector(selector)?.setAttribute('dir', dir.value)
else
document.querySelector(selector)?.removeAttribute('dir')
},
})
}