feat(wip): 自定义编辑框
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
import { $ } from "mdui"
|
import { $ } from "mdui"
|
||||||
|
|
||||||
export default class MduiPatchedTextAreaElement extends HTMLElement {
|
export default class MduiPatchedTextAreaElement extends HTMLElement {
|
||||||
static observedAttributes = ['user-id']
|
static observedAttributes = ['value', 'placeholder']
|
||||||
declare inputDiv: HTMLDivElement
|
declare inputDiv?: HTMLDivElement
|
||||||
|
declare inputPlaceHolderDiv?: HTMLDivElement
|
||||||
|
declare inputContainerDiv?: HTMLDivElement
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
@@ -13,11 +15,51 @@ export default class MduiPatchedTextAreaElement extends HTMLElement {
|
|||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
const shadow = this.shadowRoot as ShadowRoot
|
const shadow = this.shadowRoot as ShadowRoot
|
||||||
|
|
||||||
this.inputDiv = new DOMParser().parseFromString(`
|
this.inputContainerDiv = new DOMParser().parseFromString(`
|
||||||
<div contentEditable="true" style="outline: none !important; color: rgb(var(--mdui-color-on-surface-variant)); display: inline-block; word-wrap: break-word; white-space: pre-wrap;"></div>
|
<div style="overflow-y: auto; height: 100%;">
|
||||||
`, 'text/html').body.firstChild as HTMLDivElement
|
<div role="textbox" aria-multiline="true" aria-labelledby="txtboxMultilineLabel" contentEditable="true" style="outline: none !important; color: rgb(var(--mdui-color-on-surface-variant)); display: inline-block; word-break: break-word; white-space: pre-wrap;"></div>
|
||||||
this.inputDiv.contentEditable = 'true'
|
<div style="display: none;"></div>
|
||||||
|
<style>
|
||||||
|
*::-webkit-scrollbar {
|
||||||
|
width: 7px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-track {
|
||||||
|
width: 6px;
|
||||||
|
background: rgba(#101f1c, 0.1);
|
||||||
|
-webkit-border-radius: 2em;
|
||||||
|
-moz-border-radius: 2em;
|
||||||
|
border-radius: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgba(144, 147, 153, 0.5);
|
||||||
|
background-clip: padding-box;
|
||||||
|
min-height: 28px;
|
||||||
|
-webkit-border-radius: 2em;
|
||||||
|
-moz-border-radius: 2em;
|
||||||
|
border-radius: 2em;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: rgba(144, 147, 153, 0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</div>
|
||||||
|
`, 'text/html').body.firstChild as HTMLDivElement
|
||||||
|
|
||||||
|
console.log(this.inputContainerDiv.children)
|
||||||
|
this.inputDiv = this.inputContainerDiv.children[0] as HTMLDivElement
|
||||||
|
this.inputPlaceHolderDiv = this.inputContainerDiv.children[1] as HTMLDivElement
|
||||||
|
|
||||||
|
this.inputDiv.addEventListener('input', () => {
|
||||||
|
// TODO: 修复 placeholder
|
||||||
|
this.inputPlaceHolderDiv!.style.display = this.value == '' ? '' : 'none'
|
||||||
|
this.inputDiv!.style.display = this.value == '' ? 'none' : ''
|
||||||
|
})
|
||||||
this.inputDiv.addEventListener('blur', () => {
|
this.inputDiv.addEventListener('blur', () => {
|
||||||
if (this._lastValue !== this.value) {
|
if (this._lastValue !== this.value) {
|
||||||
this._lastValue = this.value || ''
|
this._lastValue = this.value || ''
|
||||||
@@ -31,7 +73,7 @@ export default class MduiPatchedTextAreaElement extends HTMLElement {
|
|||||||
|
|
||||||
this.inputDiv.style.width = '100%'
|
this.inputDiv.style.width = '100%'
|
||||||
|
|
||||||
shadow.appendChild(this.inputDiv)
|
shadow.appendChild(this.inputContainerDiv)
|
||||||
}
|
}
|
||||||
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
|
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
@@ -39,19 +81,27 @@ export default class MduiPatchedTextAreaElement extends HTMLElement {
|
|||||||
this.value = newValue || ''
|
this.value = newValue || ''
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case 'placeholder': {
|
||||||
|
this.inputPlaceHolderDiv && (this.inputPlaceHolderDiv.innerText = newValue || '')
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
focus() {
|
focus() {
|
||||||
this.inputDiv.focus()
|
this.inputDiv?.focus()
|
||||||
}
|
}
|
||||||
blur() {
|
blur() {
|
||||||
this.inputDiv.blur()
|
this.inputDiv?.blur()
|
||||||
|
}
|
||||||
|
checkValidity() {
|
||||||
|
// TODO: implment this method
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
get value() {
|
get value() {
|
||||||
return this.inputDiv.textContent
|
return this.inputDiv?.textContent || ''
|
||||||
}
|
}
|
||||||
set value(v) {
|
set value(v) {
|
||||||
this.inputDiv.textContent = v
|
this.inputDiv && (this.inputDiv.textContent = v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export default function ChatFragment({
|
|||||||
}} onDrop={(e) => {
|
}} onDrop={(e) => {
|
||||||
// 文件拽入
|
// 文件拽入
|
||||||
}}>
|
}}>
|
||||||
<mdui-text-field variant="outlined" use-patched-textarea placeholder="(。・ω・。)" autosize ref={inputRef} /* max-rows={6} */ onChange={() => {
|
<mdui-text-field variant="outlined" use-patched-textarea placeholder="(。・ω・。)" autosize ref={inputRef} max-rows={6} onChange={() => {
|
||||||
if (inputRef.current?.value.trim() == '') {
|
if (inputRef.current?.value.trim() == '') {
|
||||||
// 清空缓存的文件
|
// 清空缓存的文件
|
||||||
}
|
}
|
||||||
|
|||||||
10
mdui_patched/components/text-field/index.js
vendored
10
mdui_patched/components/text-field/index.js
vendored
@@ -398,9 +398,15 @@ let TextField = class TextField extends FocusableMixin(MduiElement) {
|
|||||||
'is-firefox': navigator.userAgent.includes('Firefox'),
|
'is-firefox': navigator.userAgent.includes('Firefox'),
|
||||||
...invalidClassNameObj,
|
...invalidClassNameObj,
|
||||||
});
|
});
|
||||||
return html `<div part="container" class="${className}">${this.renderPrefix()}<div class="input-container">${this.renderLabel()} ${!hasInputSlot ? (this.isTextarea
|
return html`<div part="container" class="${className}">${this.renderPrefix()}<div class="input-container">${this.renderLabel()} ${!hasInputSlot ? (
|
||||||
|
this.getAttribute("use-patched-textarea")
|
||||||
|
? this.renderPatchedTextArea(hasInputSlot)
|
||||||
|
: (
|
||||||
|
this.isTextarea
|
||||||
? this.renderTextArea(hasInputSlot)
|
? this.renderTextArea(hasInputSlot)
|
||||||
: this.renderInput(hasInputSlot)) : ''} ${when(hasInputSlot, () => html `<slot name="input" class="input"></slot>`)}</div>${this.renderSuffix()}${this.renderClearButton(hasClearButton)} ${this.renderTogglePasswordButton(hasTogglePasswordButton)} ${this.renderRightIcon(hasErrorIcon)}</div>${when(hasError || hasHelper || hasCounter, () => html `<div part="supporting" class="${classMap({ supporting: true, ...invalidClassNameObj })}">${this.renderHelper(hasError, hasHelper)} ${this.renderCounter(hasCounter)}</div>`)}`;
|
: this.renderInput(hasInputSlot)
|
||||||
|
)
|
||||||
|
) : ''} ${when(hasInputSlot, () => html`<slot name="input" class="input"></slot>`)}</div>${this.renderSuffix()}${this.renderClearButton(hasClearButton)} ${this.renderTogglePasswordButton(hasTogglePasswordButton)} ${this.renderRightIcon(hasErrorIcon)}</div>${when(hasError || hasHelper || hasCounter, () => html`<div part="supporting" class="${classMap({ supporting: true, ...invalidClassNameObj })}">${this.renderHelper(hasError, hasHelper)} ${this.renderCounter(hasCounter)}</div>`)}`;
|
||||||
}
|
}
|
||||||
setCustomValidityInternal(message) {
|
setCustomValidityInternal(message) {
|
||||||
this.inputRef.value.setCustomValidity(message);
|
this.inputRef.value.setCustomValidity(message);
|
||||||
|
|||||||
Reference in New Issue
Block a user