diff --git a/packages/cms/src/ui.js b/packages/cms/src/ui.js index a84b8d0e411..3f5150061c9 100644 --- a/packages/cms/src/ui.js +++ b/packages/cms/src/ui.js @@ -17,6 +17,9 @@ export const { Combobox, CommandPaletteItem, ConfirmationModal, + ContentDirection, + useContentDirection, + useUiDirection, Context, ContextFooter, ContextHeader, diff --git a/resources/css/vendors/codemirror.css b/resources/css/vendors/codemirror.css index 3f742a9fbcd..7c1d0799aec 100644 --- a/resources/css/vendors/codemirror.css +++ b/resources/css/vendors/codemirror.css @@ -3,6 +3,7 @@ .CodeMirror { /* Set height, width, borders, and global font properties here */ @apply text-gray-900 dark:text-gray-300 leading-normal min-h-20; + direction: ltr; } /* CODEMIRROR / PADDING diff --git a/resources/js/bootstrap/cms/ui.js b/resources/js/bootstrap/cms/ui.js index 2b8a3e7cd1e..68653dd3746 100644 --- a/resources/js/bootstrap/cms/ui.js +++ b/resources/js/bootstrap/cms/ui.js @@ -17,6 +17,7 @@ export { Combobox, CommandPaletteItem, ConfirmationModal, + ContentDirection, Context, ContextFooter, ContextHeader, @@ -124,4 +125,6 @@ export { Widget, registerIconSet, registerIconSetFromStrings, + useContentDirection, + useUiDirection, } from '../../components/ui/index'; diff --git a/resources/js/components/fieldtypes/ArrayFieldtype.vue b/resources/js/components/fieldtypes/ArrayFieldtype.vue index 17cf585429a..5c4184576d1 100644 --- a/resources/js/components/fieldtypes/ArrayFieldtype.vue +++ b/resources/js/components/fieldtypes/ArrayFieldtype.vue @@ -24,6 +24,7 @@ :key="element._id" :id="fieldId + '__' + element.key" :readonly="isReadOnly" + :input-attrs="{ dir: contentDirection }" /> @@ -41,6 +42,7 @@ :id="fieldId + '__' + element.key" v-model="data[index].value" :readonly="isReadOnly" + :dir="contentDirection" /> @@ -71,12 +73,14 @@ @@ -107,6 +111,7 @@ import Fieldtype from './Fieldtype.vue'; import { SortableList, SortableHelpers } from '../sortable/Sortable'; import { Button } from '@/components/ui'; +import { useContentDirection } from '@/composables/content-direction'; export default { mixins: [Fieldtype, SortableHelpers], @@ -116,6 +121,12 @@ export default { Button, }, + setup() { + const { direction: contentDirection } = useContentDirection(); + + return { contentDirection }; + }, + data() { const keys = Object.keys(this.value || {}); const selectedKey = keys.length > 0 ? keys[0] : null; diff --git a/resources/js/components/fieldtypes/ListFieldtype.vue b/resources/js/components/fieldtypes/ListFieldtype.vue index 03be98e115a..56c250e9f6c 100644 --- a/resources/js/components/fieldtypes/ListFieldtype.vue +++ b/resources/js/components/fieldtypes/ListFieldtype.vue @@ -23,6 +23,7 @@ class="!inset-shadow-none focus:!inset-shadow-none" v-model="element.value" :readonly="isReadOnly" + :input-attrs="{ dir: contentDirection }" @blur="focused = false" @focus="editItemWithoutFocusing(index)" @keydown.enter.prevent="nextItem" @@ -58,6 +59,7 @@ import Fieldtype from './Fieldtype.vue'; import { SortableList, SortableHelpers } from '../sortable/Sortable'; import { Button } from '@/components/ui'; +import { useContentDirection } from '@/composables/content-direction'; export default { mixins: [Fieldtype, SortableHelpers], @@ -67,6 +69,12 @@ export default { Button, }, + setup() { + const { direction: contentDirection } = useContentDirection(); + + return { contentDirection }; + }, + data() { return { data: [], diff --git a/resources/js/components/fieldtypes/SlugFieldtype.vue b/resources/js/components/fieldtypes/SlugFieldtype.vue index 01f73e15e96..d9dda4158e7 100644 --- a/resources/js/components/fieldtypes/SlugFieldtype.vue +++ b/resources/js/components/fieldtypes/SlugFieldtype.vue @@ -19,6 +19,7 @@ :read-only="isReadOnly" :name="slug" :disabled="config.disabled" + :input-attrs="{ dir: contentDirection }" @focus="$emit('focus')" @blur="$emit('blur')" > @@ -40,6 +41,7 @@ import { data_get } from '../../bootstrap/globals'; import Fieldtype from './Fieldtype.vue'; import { Input, Button, Icon } from '@/components/ui'; +import { useContentDirection } from '@/composables/content-direction'; export default { mixins: [Fieldtype], @@ -50,6 +52,12 @@ export default { Icon, }, + setup() { + const { direction: contentDirection } = useContentDirection(); + + return { contentDirection }; + }, + data() { return { slug: this.value, diff --git a/resources/js/components/fieldtypes/TableFieldtype.vue b/resources/js/components/fieldtypes/TableFieldtype.vue index 088a14631a2..beec9ba869d 100644 --- a/resources/js/components/fieldtypes/TableFieldtype.vue +++ b/resources/js/components/fieldtypes/TableFieldtype.vue @@ -43,6 +43,7 @@ @@ -88,6 +89,7 @@ diff --git a/resources/js/components/fieldtypes/bard/BardFieldtype.vue b/resources/js/components/fieldtypes/bard/BardFieldtype.vue index c3f97383447..e682303b6f1 100644 --- a/resources/js/components/fieldtypes/bard/BardFieldtype.vue +++ b/resources/js/components/fieldtypes/bard/BardFieldtype.vue @@ -116,7 +116,7 @@
- + @@ -184,6 +185,7 @@ import AssetSelector from '../../assets/Selector.vue'; import Uploader from '../../assets/Uploader.vue'; import Uploads from '../../assets/Uploads.vue'; import MarkdownToolbar from './MarkdownToolbar.vue'; +import { useContentDirection } from '@/composables/content-direction'; // Keymaps import 'codemirror/keymap/sublime'; @@ -240,6 +242,12 @@ export default { Stack, }, + setup() { + const { direction: contentDirection } = useContentDirection(); + + return { contentDirection }; + }, + data() { return { data: this.value || '', @@ -654,7 +662,6 @@ export default { mode: 'gfm', dragDrop: false, keyMap: 'sublime', - direction: document.querySelector('html').getAttribute('dir') ?? 'ltr', lineWrapping: true, viewportMargin: Infinity, tabindex: 0, diff --git a/resources/js/components/ui/Field.vue b/resources/js/components/ui/Field.vue index f255d6be449..0b4b9b4db5c 100644 --- a/resources/js/components/ui/Field.vue +++ b/resources/js/components/ui/Field.vue @@ -16,6 +16,8 @@ const props = defineProps({ inline: { type: Boolean, default: false }, /** Badge text to display next to the label. */ badge: { type: String, default: '' }, + /** The reading direction of the field's label, instructions, and errors. */ + dir: { type: String, default: null }, disabled: { type: Boolean, default: false }, /** Error message to display below the field. */ error: { type: String }, @@ -80,7 +82,7 @@ const hasErrors = computed(() => {