{
:bordered="false"
clear-icon
:show-search="!isMobileMode"
- :show-arrow="editAllowed && !(readOnly || isLockedMode)"
+ :show-arrow="editAllowed && !readOnly"
:open="isOpen && editAllowed"
- :disabled="readOnly || !editAllowed || isLockedMode"
+ :disabled="readOnly || !editAllowed"
:class="{ 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-multi-select-cell ${isOpen ? 'active' : ''}`"
@search="search"
diff --git a/packages/nc-gui/components/cell/RichText.vue b/packages/nc-gui/components/cell/RichText.vue
new file mode 100644
index 0000000000..7f48430ea8
--- /dev/null
+++ b/packages/nc-gui/components/cell/RichText.vue
@@ -0,0 +1,347 @@
+
+
+
+
+
+
+
diff --git a/packages/nc-gui/components/cell/RichText/LinkOptions.vue b/packages/nc-gui/components/cell/RichText/LinkOptions.vue
new file mode 100644
index 0000000000..ddae15f26b
--- /dev/null
+++ b/packages/nc-gui/components/cell/RichText/LinkOptions.vue
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/nc-gui/components/cell/RichText/SelectedBubbleMenu.vue b/packages/nc-gui/components/cell/RichText/SelectedBubbleMenu.vue
new file mode 100644
index 0000000000..51b939b264
--- /dev/null
+++ b/packages/nc-gui/components/cell/RichText/SelectedBubbleMenu.vue
@@ -0,0 +1,381 @@
+
+
+
+
+
+
+
diff --git a/packages/nc-gui/components/cell/RichText/SelectedBubbleMenuPopup.vue b/packages/nc-gui/components/cell/RichText/SelectedBubbleMenuPopup.vue
new file mode 100644
index 0000000000..63132a18f8
--- /dev/null
+++ b/packages/nc-gui/components/cell/RichText/SelectedBubbleMenuPopup.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue
index 6d132cf0b0..9acccd11e2 100644
--- a/packages/nc-gui/components/cell/SingleSelect.vue
+++ b/packages/nc-gui/components/cell/SingleSelect.vue
@@ -43,8 +43,6 @@ const column = inject(ColumnInj)!
const readOnly = inject(ReadonlyInj)!
-const isLockedMode = inject(IsLockedInj, ref(false))
-
const isEditable = inject(EditModeInj, ref(false))
const activeCell = inject(ActiveCellInj, ref(false))
@@ -104,7 +102,7 @@ const hasEditRoles = computed(() => isUIAllowed('dataEdit'))
const editAllowed = computed(() => (hasEditRoles.value || isForm.value) && active.value)
const vModel = computed({
- get: () => tempSelectedOptState.value ?? modelValue?.trim(),
+ get: () => tempSelectedOptState.value ?? modelValue,
set: (val) => {
if (val && isNewOptionCreateEnabled.value && (options.value ?? []).every((op) => op.title !== val)) {
tempSelectedOptState.value = val
@@ -259,16 +257,12 @@ const handleClose = (e: MouseEvent) => {
useEventListener(document, 'click', handleClose, true)
const selectedOpt = computed(() => {
- return options.value.find((o) => o.value === vModel.value)
+ return options.value.find((o) => o.value === vModel.value || o.value === vModel.value?.trim())
})
-
+
{
:allow-clear="!column.rqd && editAllowed"
:bordered="false"
:open="isOpen && editAllowed"
- :disabled="readOnly || !editAllowed || isLockedMode"
- :show-arrow="hasEditRoles && !(readOnly || isLockedMode) && active && vModel === null"
+ :disabled="readOnly || !editAllowed"
+ :show-arrow="hasEditRoles && !readOnly && active && vModel === null"
:dropdown-class-name="`nc-dropdown-single-select-cell ${isOpen && active ? 'active' : ''}`"
:show-search="!isMobileMode && isOpen && active"
@select="onSelect"
diff --git a/packages/nc-gui/components/cell/TextArea.vue b/packages/nc-gui/components/cell/TextArea.vue
index 826e76a7a1..b8c72401d0 100644
--- a/packages/nc-gui/components/cell/TextArea.vue
+++ b/packages/nc-gui/components/cell/TextArea.vue
@@ -16,6 +16,7 @@ import {
const props = defineProps<{
modelValue?: string | number
isFocus?: boolean
+ virtual?: boolean
}>()
const emits = defineEmits(['update:modelValue'])
@@ -32,19 +33,33 @@ const isForm = inject(IsFormInj, ref(false))
const { showNull } = useGlobal()
-const vModel = useVModel(props, 'modelValue', emits, { defaultValue: '' })
+const vModel = useVModel(props, 'modelValue', emits, { defaultValue: column?.value.cdf ? String(column?.value.cdf) : '' })
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
+const position = ref<
+ | {
+ top: number
+ left: number
+ }
+ | undefined
+>({
+ top: 200,
+ left: 600,
+})
+
+const isDragging = ref(false)
+
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLTextAreaElement)?.focus()
const height = computed(() => {
- if (!rowHeight.value) return 60
+ if (!rowHeight.value || rowHeight.value === 1) return 36
- return rowHeight.value * 60
+ return rowHeight.value * 36
})
const isVisible = ref(false)
+
const inputWrapperRef = ref(null)
const inputRef = ref(null)
@@ -65,10 +80,96 @@ onClickOutside(inputWrapperRef, (e) => {
isVisible.value = false
})
+
+const onTextClick = () => {
+ if (!props.virtual) return
+
+ isVisible.value = true
+ editEnabled.value = true
+}
+
+const isRichMode = computed(() => {
+ let meta: any = {}
+ if (typeof column?.value?.meta === 'string') {
+ meta = JSON.parse(column?.value?.meta)
+ } else {
+ meta = column?.value?.meta ?? {}
+ }
+
+ return meta?.richMode
+})
+
+const onExpand = () => {
+ isVisible.value = true
+
+ const { top, left } = inputWrapperRef.value?.getBoundingClientRect() ?? { top: 0, left: 0 }
+
+ position.value = {
+ top: top + 42,
+ left,
+ }
+}
+
+const onMouseMove = (e: MouseEvent) => {
+ if (!isDragging.value) return
+
+ e.stopPropagation()
+
+ position.value = {
+ top: e.clientY - 22,
+ left: e.clientX - 46,
+ }
+}
+
+const onMouseUp = (e: MouseEvent) => {
+ if (!isDragging.value) return
+
+ e.stopPropagation()
+
+ isDragging.value = false
+ position.value = undefined
+
+ document.removeEventListener('mousemove', onMouseMove)
+ document.removeEventListener('mouseup', onMouseUp)
+}
+
+watch(position, () => {
+ const dom = document.querySelector('.nc-textarea-dropdown-active') as HTMLElement
+ if (!dom) return
+
+ if (!position.value) return
+
+ // Set left and top of dom
+ setTimeout(() => {
+ if (!position.value) return
+
+ dom.style.left = `${position.value.left}px`
+ dom.style.top = `${position.value.top}px`
+ }, 100)
+})
+
+const dragStart = () => {
+ document.addEventListener('mousemove', onMouseMove)
+ document.addEventListener('mouseup', onMouseUp)
+
+ isDragging.value = true
+}
+
+watch(editEnabled, () => {
+ if (editEnabled.value) {
+ isVisible.value = true
+ }
+})
-
+
+
-