solidjs / solid-docs-legacy

OLD documentation for SolidJS and related packages, replaced by https://github.com/solidjs/solid-docs-next
https://www.solidjs.com/
MIT License
188 stars 151 forks source link

Cursor position resets in contentEditable div #128

Open alivingspirit opened 2 years ago

alivingspirit commented 2 years ago

When you try to update the content of a contentEditable div or other element the cursor position resets to 0. This makes it impossible to type anything using signals. I'm pretty sure this is not the correct behavior although all my searching does not produce a workaround.

Here is the example. Try to type in the box. https://playground.solidjs.com/?hash=-1236695707&version=1.1.1

ryansolid commented 2 years ago

Hmm this is a tricky issue. There aren't any solutions that don't involve reading the DOM on set, which is terrible for performance. So it's hard to have that the default behavior for any text.

I checked, Svelte does do this check. (set_data looks at wholeText) Vue appears to as well: https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgaW5wdXQgPSByZWYoJ0hlbGxvIFdvcmxkIScpXG5cbmZ1bmN0aW9uIGluY3JlbWVudChlKSB7XG4gIGlucHV0LnZhbHVlID0gZS50YXJnZXQudGV4dENvbnRlbnQ7XG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8ZGl2IGNvbnRlbnRlZGl0YWJsZSBAaW5wdXQ9XCJpbmNyZW1lbnRcIj57e2lucHV0fX08L2Rpdj5cbiAgICA8ZGl2PlxuICAgICAge3tpbnB1dH19XG4gICAgPC9kaXY+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==

Preact doesn't do the check for children, but does for dangerouslySetInnerHTML: https://github.com/preactjs/preact/issues/2691 Inferno doesn't do the check for children, but does for dangerouslySetInnerHTML or if you set a special flag on the element. React doesn't do the check with children or dangerouslySetInnerHTML Solid doesn't do the check with children or innerHTML

All the VDOM libraries suggest doing some form of uncontrolled as it is the most performant. The simplest version with Solid is: https://playground.solidjs.com/?hash=-1000230651&version=1.3.9

It wouldn't be too hard.. to check innerHTML, and using that is already a de-opt so maybe it's fine. It also might be just worth documenting and leaving as is.

atk commented 2 years ago

That's actually the normal browser behavior. You can use the getSelectionRange/setSelectionRange API to fix the cursor position after input manually (be sure to calculate the correct position if you added something before the cursor).

alivingspirit commented 2 years ago

@atk @ryansolid Thank you for the detailed response. I think one of or a combination of these options will work for my use case.

ryansolid commented 2 years ago

Ok not sure what we do with this. But I think no action for now. This probably is worth documenting if there is a logical place. But it is really specific to contenteditable. Maybe this issue issue is enough until we find a home. @Jutanium any thoughts?

atk commented 2 years ago

I think a selection primitive might be a solution. It's on my todo list, but not too far up.

Jutanium commented 2 years ago

Yeah, I ran into this problem as a Solid beginner, and I think this is something we can add to the FAQ section, or into a guide on the new docs site.

atk commented 2 years ago

It might interest you that a PR for a selection primitive just landed in @solid-primitives, soon to be released. You'll be able to use it like this:

const [selection, setSelection] = createSelection();
createEffect(() => {
  // store selection
  const selected = selection();
  // writing html will break the selection
  div.innerHTML = html();
  // restore the selection
  setSelection(selected);
});
atk commented 2 years ago

@solid-primitives/selection is now published, so you can use it.

alivingspirit commented 2 years ago

Amazing! Thank you.

luijar commented 1 year ago

Do the solidJS selection primitives work around when a component resides within a Shadow Root? In the research/prototyping I did, browsers behave differently using the Selection API in these cases. Does SolidJS get around this somehow?

atk commented 1 year ago

I don't have a specific workaround. Can you provide a test case to make sure I'm not missing something?