-
Notifications
You must be signed in to change notification settings - Fork 7
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
Component which can be used to edit cells inline #844
Comments
I started thinking about this. I think, we can create a styled input like that : const Input = styled.input`
width: 100%;
background-color: inherit;
:hover,
:focus {
border: solid black 1px;
}
`; The input will take 100% width. Bad things, he will not grow with the text but, cannot take a larger width than parent div. export function Test() {
const [state, setState] = useState('');
return (
<div>
<div style={{ backgroundColor: 'red', maxWidth: 200 }}>
<Input onBlur={(event) => setState(event.currentTarget.value)} />
</div>
<div>{state}</div>
</div>
);
} Do we need something like that ? If yes, we do not have to create a new Input it looks ok ! |
With our latest meeting we said that : Ajouter une story avec un tableau qui contient des cellule éditable et le maximum de fonctionnalité pour ce tableau. On doit ajouter une action afin de supprimer une ligne (icon sur la droite) Pour l'édition inline :
Créer un composant utilisable n'importe ou qui peux faire un rendu conditionnelle.
On admet que pour sélectionner une ligne on doit avoir un radio ou une checkbox Voici la liste des composants possible pour faire le rendu :
Petit plus :
|
With theotime, we've been thinking about a proposal for input (and only input for the moment) import type { ReactNode } from 'react';
export interface InlineRendererEditableProps<T extends HTMLElement> {
isRendered: boolean;
ref: (node: T | null) => void;
onChange: (value: string) => void;
}
export interface InlineEditableRendererProps<T extends HTMLElement> {
renderEditable: (props: InlineRendererEditableProps<T>) => ReactNode;
children: ReactNode;
}
export function InlineEditableRenderer<T extends HTMLElement>(
props: InlineEditableRendererProps<T>,
) {
return null;
}
export function InputTest() {
return (
<InlineEditableRenderer
renderEditable={({ onChange, ...props }) => (
<input
{...props}
onBlur={(event) => {
onChange(event.currentTarget.value);
}}
/>
)}
>
Input
</InlineEditableRenderer>
);
}
|
export interface InlineRendererEditableProps<Element extends HTMLElement, Value> {
// ...
onChange: (value: Value, preventSwitch?: boolean) => void;
} |
Can you add state management to the example usage (with a simple |
Sure @targos ! import { useState } from 'react';
import type { ReactNode } from 'react';
export interface InlineRendererEditableProps<T extends HTMLElement> {
isRendered: boolean;
ref: (node: T | null) => void;
onChange: (value: string, preventSwitch?: boolean) => string;
}
export interface InlineEditableRendererProps<T extends HTMLElement> {
renderEditable: (props: InlineRendererEditableProps<T>) => ReactNode;
children: ReactNode;
}
export function InlineEditableRenderer<T extends HTMLElement>(
props: InlineEditableRendererProps<T>,
) {
return null;
}
export function InputTest() {
const [state, setState] = useState('Input');
return (
<InlineEditableRenderer
renderEditable={({ onChange, ...props }) => (
<input
{...props}
defaultValue={state}
onBlur={(event) => {
const value = onChange(event.currentTarget.value);
setState(value);
}}
/>
)}
>
{state}
</InlineEditableRenderer>
);
} I changed the code to add Is that ok ? |
In fact, renderProps props type could be: export interface InlineRendererEditableProps<Element extends HTMLElement, Value> {
isRendered: boolean;
ref: (node: T | null) => void;
toggle: () => void;
} |
The example looks wrong. You spread |
I agree props should not be spread inside input. |
yes my bad ! it can looks like that then : import type { ReactNode } from 'react';
import { useState } from 'react';
export interface InlineRendererEditableProps<T extends HTMLElement> {
isRendered: boolean;
ref: (node: T | null) => void;
toggle: () => string;
}
export interface InlineEditableRendererProps<T extends HTMLElement> {
renderEditable: (props: InlineRendererEditableProps<T>) => ReactNode;
children: ReactNode;
}
export function InlineEditableRenderer<T extends HTMLElement>(
props: InlineEditableRendererProps<T>,
) {
return null;
}
export function InputTest() {
const [state, setState] = useState('Input');
return (
<InlineEditableRenderer
renderEditable={({ toggle, isRendered, ref }) => (
<input
ref={ref}
defaultValue={state}
onBlur={(event) => {
toggle();
setState(event.currentTarget.value);
}}
/>
)}
>
{state}
</InlineEditableRenderer>
);
} |
In what case can |
This props is used to add "visibility" to input. isRendered is false, when the value (children) is rendered. true, when the input (in this example) will be rendered. MB the example is not good enough, i will add the style inside too, to make this more readable : <InlineEditableRenderer
renderEditable={({ toggle, isRendered, ref }) => (
<input
ref={ref}
defaultValue={state}
style={{
visibility: isRendered ? 'visible' : 'hidden',
}}
onBlur={(event) => {
toggle();
setState(event.currentTarget.value);
}}
/>
)}
>
{state}
</InlineEditableRenderer> |
But you should not render the input when the component is not in edit mode. You should render the |
Or we add another render prop, but |
I remember @Sebastien-Ahkrin need to render input with visibility hidden to avoid layout shifting in table. Like that it's always in DOM, but visible only when it's active. Maybe the default behavior should be call |
Another solution is to put |
|
yep ! its the best thing i think, because i have to render children everytime. (the editable is only render in front of the children) |
The only use case of this component is to be put somewhere inline (it's even in the name). We always want it to have a stable size I thikn. |
then are we ok with everything ? |
We are good to make a poc |
@targos we have a testable POC here: https://feat-editable-table.react-science.pages.dev/stories/?path=/story/components-editabletabletext--inline-editable Here is the code for this story : export function InlineEditable() {
const [state, setState] = useState('value');
return (
<div>
<span>State: {state}</span>
<InlineEditableRenderer
renderEditable={({ ref, toggle }) => (
<SwitchableInput
ref={ref}
defaultValue={state}
onBlur={(event) => {
toggle();
setState(event.currentTarget.value);
}}
/>
)}
>
{state}
</InlineEditableRenderer>
</div>
);
} |
@stropitek Can you have a look? |
I just found a "bug", when the main container (div on my example) has a specific width size (like 50). For explanation, the first 3 lines are "State: Hello, World!" its only a div with text (based on the state). Do the concept of an input with a little size like this, is possible ? This is now fixed! |
Can Otherwise API LGTM. |
@stropitek I renamed the component to be : export function BorderlessEditableInputExample() {
return (
<div
style={{
backgroundColor: 'lightblue',
height: 25,
width: 100,
position: 'relative',
}}
>
<BorderlessEditableInput defaultValue="Hello, World!" />
</div>
);
} Its the only way to use it (container with position: relative). We do this, because blueprint create a row with td who's have position: relative. and we use position on the Switchable to display text or input. Is this ok for you ? |
It's specifically for those reasons that I don't want the two components to have unrelated names. The name you suggested seems a bit specific ("borderless") and still not that much related to the Maybe change |
Ok ! i changed the component name. everything can be found here : #846 |
Integrate a simple input / text area within cells of a table which looks and behaves like inline editable cell.
Tab should focus the next editable cell.
Let's start by creating a story for this and later see if it would be worth making a component out of this.
The text was updated successfully, but these errors were encountered: