Skip to content

Commit

Permalink
fix AutoLine
Browse files Browse the repository at this point in the history
  • Loading branch information
JafarMirzaie committed Oct 19, 2023
1 parent 1d83bed commit 44ca21e
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 71 deletions.
4 changes: 2 additions & 2 deletions Signum/React/Lines/AutoLine.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react'
import { IsByAll, MemberInfo, PropertyRoute, PseudoType, Type, TypeInfo, TypeReference, isTypeEnum, isTypeModel, tryGetTypeInfos } from '../Reflection'
import { LineBaseController, LineBaseProps, tasks } from '../Lines/LineBase'
import { CheckboxLine, DateTimeLine, DateTimeLineController, EntityCheckboxList, EntityCombo, EntityDetail, EntityLine, EntityRepeater, EntityStrip, EntityTable, EnumCheckboxList, EnumLine, GuidLine, MultiValueLine, NumberLine, NumberLineController, PasswordLine, TextBoxLine, TimeLine, TypeContext } from '../Lines'
import { CheckboxLine, ColorLine, DateTimeLine, DateTimeLineController, EntityCheckboxList, EntityCombo, EntityDetail, EntityLine, EntityRepeater, EntityStrip, EntityTable, EnumCheckboxList, EnumLine, GuidLine, MultiValueLine, NumberLine, NumberLineController, PasswordLine, TextBoxLine, TimeLine, TypeContext } from '../Lines'
import { Entity, Lite, ModifiableEntity } from '../Signum.Entities'

export interface AutoLineProps extends LineBaseProps {
Expand Down Expand Up @@ -106,7 +106,7 @@ export namespace AutoLine {
return p => <PasswordLine {...p} />;

if (pr?.member!.format == "Color")
return p => <PasswordLine {...p} />;
return p => <ColorLine {...p} />;

return p => <TextBoxLine {...p} />;
}
Expand Down
87 changes: 18 additions & 69 deletions Signum/React/Lines/TextBoxLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,16 @@ export const TextBoxLine = React.memo(React.forwardRef(function TextBoxLine(prop
return LineBaseController.propEquals(prev, next);
});

export const PasswordLine = React.memo(React.forwardRef(function PasswordLine(props: TextBoxLineProps, ref: React.Ref<TextBoxLineController>) {
export class PasswordLineController extends ValueBaseController<TextBoxLineProps>{
init(p: TextBoxLineProps) {
super.init(p);
this.assertType("PasswordLine", ["string"]);
}
}

const c = useController(TextBoxLineController, props, ref);
export const PasswordLine = React.memo(React.forwardRef(function PasswordLine(props: TextBoxLineProps, ref: React.Ref<PasswordLineController>) {

const c = useController(PasswordLineController, props, ref);

if (c.isHidden)
return null;
Expand All @@ -51,9 +58,16 @@ export const PasswordLine = React.memo(React.forwardRef(function PasswordLine(pr
return LineBaseController.propEquals(prev, next);
});

export const GuidLine = React.memo(React.forwardRef(function GuidLine(props: TextBoxLineProps, ref: React.Ref<TextBoxLineController>) {
export class GuidLineController extends ValueBaseController<TextBoxLineProps>{
init(p: TextBoxLineProps) {
super.init(p);
this.assertType("TextBoxLine", ["Guid"]);
}
}

const c = useController(TextBoxLineController, props, ref);
export const GuidLine = React.memo(React.forwardRef(function GuidLine(props: TextBoxLineProps, ref: React.Ref<GuidLineController>) {

const c = useController(GuidLineController, props, ref);

if (c.isHidden)
return null;
Expand Down Expand Up @@ -148,68 +162,3 @@ function internalTextBox(vl: TextBoxLineController, type: "password" | "color" |
</FormGroup>
);
}

export interface ColorTextBoxProps {
value: string | null;
onChange: (newValue: string | null) => void;
formControlClass?: string;
groupClass?: string;
textValueHtmlAttributes?: React.HTMLAttributes<HTMLInputElement>;
groupHtmlAttributes?: React.HTMLAttributes<HTMLInputElement>;
innerRef?: React.Ref<HTMLInputElement>;
}

export function ColorTextBox(p: ColorTextBoxProps) {

const [text, setText] = React.useState<string | undefined>(undefined);

const value = text != undefined ? text : p.value != undefined ? p.value : "";

return (
<span {...p.groupHtmlAttributes} className={addClass(p.groupHtmlAttributes, classes(p.groupClass))}>
<input type="text"
autoComplete="asdfasf" /*Not in https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill*/
{...p.textValueHtmlAttributes}
className={addClass(p.textValueHtmlAttributes, classes(p.formControlClass))}
value={value}
onBlur={handleOnBlur}
onChange={handleOnChange}
onFocus={handleOnFocus}
ref={p.innerRef} />
<input type="color"
className={classes(p.formControlClass, "sf-color")}
value={value}
onBlur={handleOnBlur}
onChange={handleOnChange}
/>
</span>);

function handleOnFocus(e: React.FocusEvent<any>) {
const input = e.currentTarget as HTMLInputElement;

input.setSelectionRange(0, input.value != null ? input.value.length : 0);

if (p.textValueHtmlAttributes?.onFocus)
p.textValueHtmlAttributes.onFocus(e);
};

function handleOnBlur(e: React.FocusEvent<any>) {

const input = e.currentTarget as HTMLInputElement;

var result = input.value == undefined || input.value.length == 0 ? null : input.value;

setText(undefined);
if (p.value != result)
p.onChange(result);
if (p.textValueHtmlAttributes?.onBlur)
p.textValueHtmlAttributes.onBlur(e);
}

function handleOnChange(e: React.SyntheticEvent<any>) {
const input = e.currentTarget as HTMLInputElement;
setText(input.value);
if (p.onChange)
p.onChange(input.value);
}
}

2 comments on commit 44ca21e

@olmobrutall
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From ValueLine to AutoLine

Splitting ValueLine

Signum Framework has a set of components that inherit from LineBase and are meant to control a property, typically by receiving a TypeContext<T>.

Before this change, this components where following this hierarchy.

  • LineBase (abstract)
    • ValueLine (string, numbers, Enum, DateTime, Color, TimeSpan, Guid, ...)
    • MultiValueLine (MList of values)
    • EntityBase (abstract for Entity or Lite)
      • EntityLine
      • EntityCombo
      • EntityDetail
      • EntityListBase (abstract for MList or MList<Lite>)
        • EntityStrip
        • EntityTable
        • EntityRepeater
          ....

Grouping all the different values into one component (ValueLine) made it a very big components with many props, but only some of the props will take any effect for any particular ValueLineType.

  • LineBase (abstract)
    • ValueBase (abstract)
      • TextBoxLine / TextAreaLine / PasswordLine / ColorLine (for string)
      • NumberLine (for numbers)
      • EnumLine (for enums or selecting a string from a list)
      • DateTimeLine / DateTimeSplittedLine (for DateTime / DateOnly)
      • GuidLine (for Guid)
      • TimeLine (for TimeSpan / TimeOnly)
      • CheckboxLine (for non-nullable boolean).
    • MultiValueLine (MList of values)
    • EntityBase (abstract for Entity or Lite)
      • EntityLine
      • EntityCombo
      • EntityDetail
      • EntityListBase (abstract for MList or MList<Lite>)
        • EntityStrip
        • EntityTable
        • EntityRepeater
          ....

This change simplifies the implementation and understanding of ValueLine, but requires the developer to known and choose the appropiate component for every property.

AutoLine

To aliviate this, there is a new AutoLine component that tries to infer the right component depending on the metadata delivered by the server via reflection.

The implementation of AutoLine has an extension point to register new components (like FileLine or FileImageLine) but the default imlpementation is a catallog of all the monsters inheriting from LineBase and for what properties they make sense:

export function getComponentFactory(tr: TypeReference, pr?: PropertyRoute): (props: AutoLineProps) => React.ReactElement<any> {

This means that you can use AutoLine for every property: Entities, Lite, values, MList, ... you can also customize some things like label, onChange etc..:

export interface LineBaseProps extends StyleOptions {
https://github.com/signumsoftware/framework/blob/07273d779a3a62a39e042ffcb378dc45d90558af/Signum/React/Lines/AutoLine.tsx#L7C45-L7C45

But if you want to use component specific properties, you will need to use the actual component like EntityLine or TextBoxLine.

AutoViewDispatcher and AutoComponent (internal stuff)

The ViewDispatcher is the class that resolves the right component that will be used inside a FrameModal/ FramePage.

By default it uses the component register in the EntitySettings, or if not found, a component that automatically generates a basic UI for each property of the entity. This automatic component has been renamed from DynamicComponent to AutoComponent and has been grately simplified. Now is basically a foreach of AutoLine.

https://github.com/signumsoftware/framework/blob/07273d779a3a62a39e042ffcb378dc45d90558af/Signum/React/AutoComponent.tsx

How to Upgrade

There is a Upgrade_20231013_AutoLine that will replace all your ValueLine for AutoLine except when inlineCheckBox is used (then CheckBoxLine) or optionITems (then EnumLine).

https://github.com/signumsoftware/framework/blob/07273d779a3a62a39e042ffcb378dc45d90558af/Signum.Upgrade/Upgrades/Upgrade_20231013_AutoLine.cs

Everithing else will require some manual fixes, hopefully is not too much work.

@mehdy-karimpour
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As always, Great 💯

Please sign in to comment.