diff --git a/src/common/DV.tsx b/src/common/DV.tsx index 797796788..be3432d88 100644 --- a/src/common/DV.tsx +++ b/src/common/DV.tsx @@ -2,7 +2,7 @@ import {DocString, EdgeHead, ShortAttribETypes as SAType, U} from '../joiner'; import {GObject, RuntimeAccessible} from '../joiner'; import React, {ReactElement} from "react"; // const beautify = require('js-beautify').html; // BEWARE: this adds some newline that might be breaking and introduce syntax errors in our JSX parser -const beautify = (s: any)=>s; +const beautify = (s: string) => s; let ShortAttribETypes: typeof SAType = (window as any).ShortAttribETypes; @RuntimeAccessible @@ -17,7 +17,6 @@ export class DV { public static literalView(): string { return beautify(DefaultView.literal()); } public static voidView(): string { return beautify(DefaultView.void()); } public static operationView(): string { return beautify(DefaultView.operation()); } - public static operationViewm1(): string { return beautify(DefaultView.operationm1()); } public static objectView(): string { return beautify(DefaultView.object()); } public static valueView(): string { return beautify(DefaultView.value()); } public static defaultPackage(): string { return beautify(DefaultView.defaultPackage()); } @@ -155,81 +154,74 @@ class DefaultView { public static model(): string { return `
- {!data && "Model data missing."} -
{[ - true && data.suggestedEdges.reference && - data.suggestedEdges.reference.map( - se => (!se.vertexOverlaps) - && ) - , - true && data.suggestedEdges.extend && - data.suggestedEdges.extend.map( - se => (!se.vertexOverlaps) - && )] - } -
- {data && data.packages.map((pkg, index) => { - return - })} - {data && data.allSubObjects.map((child, index) => { - return - })} -
`; + {!data && "Model data missing."} +
{[ + true && data.suggestedEdges.reference && + data.suggestedEdges.reference.map( + se => (!se.vertexOverlaps) + && ) + , + true && data.suggestedEdges.extend && + data.suggestedEdges.extend.map( + se => (!se.vertexOverlaps) + && )] + } +
+ {data && data.packages.map((pkg, index) => { + return + })} + {data && data.allSubObjects.map((child, index) => { + return + })} +`; } public static void(): string { return `
-
voidvertex element test
-
data: {props.data ? props.data.name : "empty"}
-
`; +
voidvertex element test
+
data: {props.data ? props.data.name : "empty"}
+`; } public static package(): string { return `
- { /*EPackage:} field={'name'} hidden={true} />*/ } - { /*console.log("evalcontex:", {thiss: this, pname: pname, c: _context}) && null*/ } - {/*{pname}:} field={'name'} hidden={true} />*/} -
-
- - {data.children.map((child, index) => { - return - })} -
-
`; +
+
+ + {data.children.map((child, index) => { + return + })} +
+`; } public static class(): string { return `
- EClass:} - data={data.id} field={'name'} hidden={true} autosize={true} /> - EClass:} - data={data.id} field={'name'} hidden={true} autosize={true} /> -
- {/* i kept them separated because i want them in this order. i could have used data.children once, or put all in same container to mix them. */} -
{ data.attributes.map(c => ) }
-
{ data.references.map(c => ) }
-
{ data.operations.map(c => ) }
-
`; + EClass:} + data={data.id} field={'name'} hidden={true} autosize={true} /> +
+
{ data.attributes.map(c => ) }
+
{ data.references.map(c => ) }
+
{ data.operations.map(c => ) }
+`; } public static enum(): string { return `
- EEnum:} - data={data.id} field={'name'} hidden={true} autosize={true} /> -
-
- {data.children.map((child, index) => { - return - })} -
-
`; + EEnum:} + data={data.id} field={'name'} hidden={true} autosize={true} /> +
+
+ {data.children.map((child, index) => { + return + })} +
+`; } public static feature(): string { return `
-
`; + '} /> - `; - return ` '} /> +`; } public static object(): string { return `
- -
-
- {data.features.map((child, index) => { - return - })} -
-
`; + +
+
+ {data.features.map((child, index) => { + return + })} +
+`; } public static value() { return `
- {props.data.instanceof && } - {!props.data.instanceof && } - -
` + {props.data.instanceof && } + {!props.data.instanceof && } + +` } public static defaultPackage() { return `
- {data.children.map((child, index) => { - return - })} -
`; + {data.children.map((child, index) => { + return + })} +`; } public static error(msg: undefined | string | JSX.Element) { diff --git a/src/components/forEndUser/GenericInput.tsx b/src/components/forEndUser/GenericInput.tsx index 1f8769b97..0abcda1fa 100644 --- a/src/components/forEndUser/GenericInput.tsx +++ b/src/components/forEndUser/GenericInput.tsx @@ -1,5 +1,5 @@ -import React, {Dispatch, InputHTMLAttributes, PureComponent, ReactNode} from "react"; -import { connect } from "react-redux"; +import React, {Dispatch, InputHTMLAttributes, PureComponent, ReactNode} from 'react'; +import { connect } from 'react-redux'; import './GenericInput.scss'; import { Pointer, @@ -12,9 +12,9 @@ import { Select, ShortAttribETypes, Input, LViewElement, DViewElement, U -} from "../../joiner"; -import {DState, DPointerTargetable, LPointerTargetable, RuntimeAccessibleClass} from "../../joiner"; -import {SizeInput} from "./SizeInput"; +} from '../../joiner'; +import {DState, DPointerTargetable, LPointerTargetable, RuntimeAccessibleClass} from '../../joiner'; +import {SizeInput} from './SizeInput'; // private interface ThisState { @@ -30,27 +30,27 @@ class GenericInputComponent extends PureComponent; - if (!this.props.infoof){ + let info: GObject; + if (!this.props.info){ let DConstructor: typeof DPointerTargetable = RuntimeAccessibleClass.get(d.className); let singleton: GObject = DConstructor.singleton; - infoof = singleton["__info_of__" + this.props.field] ; - } else infoof = this.props.infoof; + info = singleton['__info_of__' + this.props.field] ; + } else info = this.props.info; let type: string; - let enumOptions: Dic, Dic, String<"values">>> = {}; // "Options" entry is a fallback for items without an optgroup + let enumOptions: Dic, Dic, String<'values'>>> = {}; // 'Options' entry is a fallback for items without an optgroup let enumOptionsJSX: JSX.Element | undefined; - if (infoof.enum) { - type = "EEnum"; - let prevoptgroup: string = "Options"; + if (info.enum) { + type = 'EEnum'; + let prevoptgroup: string = 'Options'; let group: string; let option: string; - for (let key in infoof.enum) { - let val: string = infoof.enum[key]; - if (key.indexOf("(") === 0) { - let endi = key.indexOf(")"); - group = key.substring(1, endi).trim(); - option = key.substring(endi+1).trim(); + for (let key in info.enum) { + let val: string = info.enum[key]; + if (key.indexOf('(') === 0) { + let end = key.indexOf(')'); + group = key.substring(1, end).trim(); + option = key.substring(end + 1).trim(); prevoptgroup = group; } else { option = key; @@ -64,28 +64,28 @@ class GenericInputComponent extends PureComponent { //data-selected={l[field] === unsorted[optkey]} - unsorted && Object.keys(unsorted).map( (optkey: string) => ) + unsorted && Object.keys(unsorted).map((optKey: string) => ) } - {Object.keys(enumOptions).map((grpkey: string) => { - Object.keys(enumOptions[grpkey]).map( (optkey: string) => ) + {Object.keys(enumOptions).map((grpKey: string) => { + Object.keys(enumOptions[grpKey]).map( (optKey: string) => ) })}; } else { - if (typeof infoof.type === "string") { - if (infoof.type.indexOf("Function") === 0) type = "Function"; - else type = infoof.type; + if (typeof info.type === 'string') { + if (info.type.indexOf('Function') === 0) type = 'Function'; + else type = info.type; } else { - if (!infoof.type) { Log.exDevv("missing __info_of__ type for " + d.className + "." + this.props.field, {d, infoof, props:this.props}); return <>} - let infotype: GObject = infoof.type; - type = infotype.cname || infotype.className || infotype.name; - Log.exDev(!type, "missing type:", {type, infoof}); + if (!info.type) { Log.exDevv('missing __info_of__ type for ' + d.className + '.' + this.props.field, {d, info, props: this.props}); return <>} + let infoType: GObject = info.type; + type = infoType.cname || infoType.className || infoType.name; + Log.exDev(!type, 'missing type:', {type, info}); } } - /*if (type.indexOf("|") !== -1) { - type = "EEnum"; - let options = type.split("|"); + /*if (type.indexOf('|') !== -1) { + type = 'EEnum'; + let options = type.split('|'); if (!enumOptions.Option) enumOptions.Option = {}; for (let o in options){ o = o.trim(); @@ -96,90 +96,91 @@ class GenericInputComponent extends PureComponent = {...this.props} as any; function setMinMax(max: number): void { - if (infoof.min !== undefined) otherProps.min = infoof.min; - else otherProps.min = infoof.positive === true ? 0 : -max / 2; // assume false if non specified + if (info.min !== undefined) otherProps.min = info.min; + else otherProps.min = info.positive === true ? 0 : -max / 2; // assume false if non specified - if (infoof.max !== undefined) otherProps.max = infoof.max; - else otherProps.max = infoof.positive === false ? max/2 - 1 : max-1; // assume true if non specified + if (info.max !== undefined) otherProps.max = info.max; + else otherProps.max = info.positive === false ? max/2 - 1 : max-1; // assume true if non specified } - let label = U.uppercaseFirstLetter(infoof.label || this.props.field); + let label = U.uppercaseFirstLetter(info.label || this.props.field); switch (type) { default: - Log.e("invalid type in GenericInput", {type, props:this.props, infoof, d}); - return
Invalid GInput type: "{type}"
; - case "Point": case "GraphPoint": case "Size": case "GraphSize": + Log.e('invalid type in GenericInput', {type, props:this.props, info, d}); + return
Invalid GInput type: '{type}'
; + case 'Point': case 'GraphPoint': case 'Size': case 'GraphSize': return ; - case "text": case "Function": - return ; - case "EEnum": - return ; + jsxLabel={label} tooltip={this.props.tooltip} />; // natives - case "radio": + case 'radio': // problem: this would need to return a
and multiple inputs generated by a single element. // it should be easy but unlikely it will be needed so i won't do it for now. - Log.eDevv("radio input type is unsuppoted"); break; - case "datetime": type = "datetime-local"; break; - case "color": break; - case "email": break; - case "image": break; // ? - case "password": break; - case "range": break; - case "month": break; - case "week": break; - case "datetime-local": break; - case "time": break; - case "url": break; + Log.eDevv('radio input type is unsupported'); break; + case 'datetime': type = 'datetime-local'; break; + case 'color': break; + case 'email': break; + case 'image': break; // ? + case 'password': break; + case 'range': break; + case 'month': break; + case 'week': break; + case 'datetime-local': break; + case 'time': break; + case 'url': break; // ecore case ShortAttribETypes.EChar: - type = "text"; + type = 'text'; if (undefined === otherProps.minLength) otherProps.minLength = 1; otherProps.maxLength = 1; - // otherProps.pattern = "^.{1}$"; + // otherProps.pattern = '^.{1}$'; break; - case ShortAttribETypes.EString: type = "text"; break; - case ShortAttribETypes.EBoolean: type = "checkbox"; break; + case ShortAttribETypes.EString: type = 'text'; break; + case ShortAttribETypes.EBoolean: type = 'checkbox'; break; case ShortAttribETypes.EByte: - type = "number"; + type = 'number'; setMinMax(2**8); break; case ShortAttribETypes.EShort: - type = "number"; + type = 'number'; setMinMax(2**16); break; case ShortAttribETypes.EInt: - type = "number"; + type = 'number'; setMinMax(2**32); break; case ShortAttribETypes.ELong: - type = "number"; + type = 'number'; setMinMax(2**64); break; case ShortAttribETypes.EFloat: case ShortAttribETypes.EDouble: - type = "number"; - if (!otherProps.step) otherProps.step = infoof.step || 0.1; - if (!otherProps.pattern) otherProps.pattern = infoof.pattern || "^[0-9]+\.[0-9]{" + infoof.digits + "}$"; + type = 'number'; + if (!otherProps.step) otherProps.step = info.step || 0.1; + if (!otherProps.pattern) otherProps.pattern = info.pattern || '^[0-9]+\.[0-9]{' + info.digits + '}$'; break; - case ShortAttribETypes.EDate: type = "datetime-local"; break; + case ShortAttribETypes.EDate: type = 'datetime-local'; break; } // delete otherProps.field; delete otherProps.data; delete otherProps.infoof; - return ; + jsxLabel={label} tooltip={this.props.tooltip} type={type as any}/>; } } // private -interface OwnProps0 { +interface _OwnProps { // propsRequestedFromJSX_AsAttributes: string; data: DPointerTargetable | LPointerTargetable; field: string; - infoof: Info | undefined; + info: Info | undefined; + tooltip?: boolean|string; className?: string; rootClassName?: string; @@ -192,18 +193,18 @@ interface OwnProps0 { they might be useful, but can just add them in without declaring all of them. i pass them like multiple?: boolean; // multi value for select! works on file, email (just changes default validation pattern), and maybe others size?: ?? - accept?: string // only for type = "file" - capture?: string // only for type = "file" + accept?: string // only for type = 'file' + capture?: string // only for type = 'file' autocomplete?: string; // only for types disabled?: boolean; - height?: string; // for "image" + height?: string; // for 'image' list?: string; // datalist maxLength?: string; // chars */ // many more skipped mostly for forms } -type OwnProps = OwnProps0 & InputHTMLAttributes; // {[inputattribute:HTMLInputAttribute]: any}; +type OwnProps = _OwnProps & InputHTMLAttributes; // {[inputattribute:HTMLInputAttribute]: any}; // private interface StateProps { // propsFromReduxStateOrOtherKindOfStateManagement: boolean; // flux or custom things too, unrelated to this.state of react. @@ -259,10 +260,10 @@ Supported __info_of__.type values: option2 // assumed still in optgroup1 option3 // assumed still in optgroup1 (optgroup2) option4 - if first option(s) are without optgroup, they are grouped in optgroup "Options" + if first option(s) are without optgroup, they are grouped in optgroup 'Options' NOT SUPPORT -- "EEnum" string, it is only used internally. pass it the whole enum. +- 'EEnum' string, it is only used internally. pass it the whole enum. native not supported - radio - tel diff --git a/src/components/forEndUser/Input.tsx b/src/components/forEndUser/Input.tsx index b17e623d6..75acb28ce 100644 --- a/src/components/forEndUser/Input.tsx +++ b/src/components/forEndUser/Input.tsx @@ -1,29 +1,18 @@ -import React, {Dispatch, ReactElement, ReactNode, useEffect} from "react"; -import {connect} from "react-redux"; -import {DState} from "../../redux/store"; -import { - Dictionary, - DPointerTargetable, DUser, - GObject, - LModelElement, - LPointerTargetable, - Overlap, - Pointer, - Selectors, - U -} from "../../joiner"; -import toast, {Toaster} from 'react-hot-toast'; -import {useStateIfMounted} from "use-state-if-mounted"; +import React, {Dispatch, ReactElement, ReactNode, useEffect} from 'react'; +import {connect} from 'react-redux'; +import {DState} from '../../redux/store'; +import {DPointerTargetable, GObject, LPointerTargetable, Overlap, Pointer, U} from '../../joiner'; +import {useStateIfMounted} from 'use-state-if-mounted'; +import './style.scss'; function InputComponent(props: AllProps) { // todo: data can be injected with UX, if field is present, can take type from a metainfo like __info_of__ const data = props.data; - // const selected = props.selected; - const fathers = U.fatherChain(data as LModelElement); let editable = true; /* Uncomment this when we have user authentication: if a user is on a ME, it cannot be edited. + const fathers = U.fatherChain(data as LModelElement); for(let father of fathers) { const user = Object.keys(selected).find(key => selected[key]?.id === father); if(user && user !== DUser.current) editable = false; @@ -37,6 +26,7 @@ function InputComponent(props: AllProps) { let __value = (!data) ? 'undefined' : ((getter) ? getter(data) : (data[field] !== undefined) ? data[field] : 'undefined'); const [value, setValue] = useStateIfMounted(__value); const [isTouched, setIsTouched] = useStateIfMounted(false); + const [showTooltip, setShowTooltip] = useStateIfMounted(false); useEffect(() => { // I check if the value that I have in my local state is being edited by other @@ -53,27 +43,14 @@ function InputComponent(props: AllProps) { const type = (props.type) ? props.type : 'text'; const label: string|undefined = props.label; const jsxLabel: ReactNode|undefined = props.jsxLabel; - /* - let tooltip: string | React.ReactElement | Info = props.tooltip === true ? data["__info_of__" + field] : (props.tooltip || undefined); - if (typeof tooltip === "object" && (tooltip as Info).txt) { - tooltip =
- {":"+tooltip.type+"\t"} - {(tooltip as Info).txt} -
; - } - */ - let tooltip: string = (props.tooltip === true) ? ((data["__info_of__" + field]) ? data["__info_of__" + field].txt: '') : props.tooltip; + let tooltip: string|undefined = (props.tooltip === true) ? ((data['__info_of__' + field]) ? data['__info_of__' + field].txt: '') : props.tooltip; + tooltip = (tooltip) ? tooltip : ''; let css = 'my-auto input '; css += (jsxLabel) ? 'ms-1' : (label) ? 'ms-auto' : ''; css += (props.hidden) ? ' hidden-input' : ''; - let autosize: boolean = props.autosize === undefined ? false : props.autosize; // props.type==="text" + let autosize: boolean = props.autosize === undefined ? false : props.autosize; // props.type==='text' css += autosize ? ' autosize-input' : ''; - const notify = () => toast((t: GObject) => ( -
toast.dismiss(t.id)}> - -
- )); const change = (evt: React.ChangeEvent) => { const isBoolean = (['checkbox', 'radio'].includes(evt.target.type)); @@ -122,20 +99,27 @@ function InputComponent(props: AllProps) { type={type} value={value} onChange={change} onBlur={blur} checked={(['checkbox', 'radio'].includes(type)) ? !!value : undefined} /> - return(