diff --git a/Customizations/JSON/TagRenderingConfigJson.ts b/Customizations/JSON/TagRenderingConfigJson.ts index cf36f668b..e4628aec5 100644 --- a/Customizations/JSON/TagRenderingConfigJson.ts +++ b/Customizations/JSON/TagRenderingConfigJson.ts @@ -41,7 +41,7 @@ export interface TagRenderingConfigJson { type?: string, /** * If a value is added with the textfield, these extra tag is addded. - * Usefull to add a 'fixme=freeform textfield used - to be checked' + * Useful to add a 'fixme=freeform textfield used - to be checked' **/ addExtraTags?: string[]; }, diff --git a/Docs/CalculatedTags.md b/Docs/CalculatedTags.md index f7af04ca4..766db78c0 100644 --- a/Docs/CalculatedTags.md +++ b/Docs/CalculatedTags.md @@ -88,4 +88,4 @@ Given either a list of geojson features or a single layer name, gives the single ### memberships -Gives a list of {role: string, relation: Relation}-objects, containing all the relations that this feature is part of. For example: `_part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')` \ No newline at end of file +Gives a list of `{role: string, relation: Relation}`\-objects, containing all the relations that this feature is part of. For example: `_part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')` \ No newline at end of file diff --git a/Docs/SpecialInputElements b/Docs/SpecialInputElements new file mode 100644 index 000000000..5f807ab47 --- /dev/null +++ b/Docs/SpecialInputElements @@ -0,0 +1,63 @@ +# Available types for text fields + +The listed types here trigger a special input element. Use them in `tagrendering.freeform.type` of your tagrendering to activate them + +## string + +A basic string + +## text + +A string, but allows input of longer strings more comfortably (a text area) + +## date + +A date + +## wikidata + +A wikidata identifier, e.g. Q42 + +## int + +A number + +## nat + +A positive number or zero + +## pnat + +A strict positive number + +## direction + +A geographical direction, in degrees. 0° is north, 90° is east, ... Will return a value between 0 (incl) and 360 (excl) + +## float + +A decimal + +## pfloat + +A positive decimal (incl zero) + +## email + +An email adress + +## url + +A url + +## phone + +A phone number + +## opening_hours + +Has extra elements to easily input when a POI is opened + +## color + +Shows a color picker \ No newline at end of file diff --git a/Logic/ExtraFunction.ts b/Logic/ExtraFunction.ts index 842f4a65a..4e91393fc 100644 --- a/Logic/ExtraFunction.ts +++ b/Logic/ExtraFunction.ts @@ -1,7 +1,6 @@ import {GeoOperations} from "./GeoOperations"; import {UIElement} from "../UI/UIElement"; import Combine from "../UI/Base/Combine"; -import State from "../State"; import {Relation} from "./Osm/ExtractRelations"; export class ExtraFunction { @@ -65,9 +64,8 @@ Some advanced functions are available on feat as well: (featuresPerLayer, feature) => { return (arg0, lat) => { if (typeof arg0 === "number") { - const lon = arg0 // Feature._lon and ._lat is conveniently place by one of the other metatags - return GeoOperations.distanceBetween([lon, lat], [feature._lon, feature._lat]); + return GeoOperations.distanceBetween([arg0, lat], [feature._lon, feature._lat]); } else { // arg0 is probably a feature return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0), [feature._lon, feature._lat]) @@ -117,9 +115,11 @@ Some advanced functions are available on feat as well: private static readonly Memberships = new ExtraFunction( "memberships", - "Gives a list of {role: string, relation: Relation}-objects, containing all the relations that this feature is part of. \n\nFor example: _part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')", + "Gives a list of {role: string, relation: Relation}-objects, containing all the relations that this feature is part of. " + + "\n\n" + + "For example: _part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')", [], - (params, feature) => { + (params, _) => { return () => params.relations ?? []; } ) diff --git a/Models/Constants.ts b/Models/Constants.ts index 9a5a5fc9e..0c91a7e7c 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -2,7 +2,7 @@ import { Utils } from "../Utils"; export default class Constants { - public static vNumber = "0.7.1-rc1"; + public static vNumber = "0.7.2-dev"; // The user journey states thresholds when a new feature gets unlocked public static userJourney = { diff --git a/UI/Input/ColorPicker.ts b/UI/Input/ColorPicker.ts new file mode 100644 index 000000000..8a0b5e88d --- /dev/null +++ b/UI/Input/ColorPicker.ts @@ -0,0 +1,60 @@ +import {InputElement} from "./InputElement"; +import {UIEventSource} from "../../Logic/UIEventSource"; +import {Utils} from "../../Utils"; + +export default class ColorPicker extends InputElement { + + private readonly value: UIEventSource + + constructor( + value?: UIEventSource + ) { + super(); + this.value = value ?? new UIEventSource(undefined); + const self = this; + this.value.addCallbackAndRun(v => { + if(v === undefined){ + return; + } + self.SetValue(v); + }); + } + + + InnerRender(): string { + return ``; + } + + private SetValue(color: string){ + const field = document.getElementById("color-" + this.id); + if (field === undefined || field === null) { + return; + } + // @ts-ignore + field.value = color; + } + + protected InnerUpdate() { + const field = document.getElementById("color-" + this.id); + if (field === undefined || field === null) { + return; + } + const self = this; + field.oninput = () => { + const hex = field["value"]; + self.value.setData(hex); + } + + } + + GetValue(): UIEventSource { + return this.value; + } + + IsSelected: UIEventSource = new UIEventSource(false); + + IsValid(t: string): boolean { + return false; + } + +} \ No newline at end of file diff --git a/UI/Input/TextField.ts b/UI/Input/TextField.ts index b612f6b69..ccb4da1e3 100644 --- a/UI/Input/TextField.ts +++ b/UI/Input/TextField.ts @@ -10,6 +10,7 @@ export class TextField extends InputElement { private readonly _placeholder: UIElement; public readonly IsSelected: UIEventSource = new UIEventSource(false); private readonly _htmlType: string; + private readonly _inputMode : string; private readonly _textAreaRows: number; private readonly _isValid: (string,country) => boolean; @@ -20,6 +21,7 @@ export class TextField extends InputElement { value?: UIEventSource, textArea?: boolean, htmlType?: string, + inputMode?: string, label?: UIElement, textAreaRows?: number, isValid?: ((s: string, country?: () => string) => boolean) @@ -36,6 +38,7 @@ export class TextField extends InputElement { this._isValid = options.isValid ?? ((str, country) => true); this._placeholder = Translations.W(options.placeholder ?? ""); + this._inputMode = options.inputMode; this.ListenTo(this._placeholder._source); this.onClick(() => { @@ -72,11 +75,15 @@ export class TextField extends InputElement { if (this._label != undefined) { label = this._label.Render(); } + let inputMode = "" + if(this._inputMode !== undefined){ + inputMode = `inputmode="${this._inputMode}" ` + } return new Combine([ ``, `
`, label, - ``, + ``, `
`, `
` ]).Render(); @@ -134,9 +141,6 @@ export class TextField extends InputElement { } public SetCursorPosition(i: number) { - if(this._htmlType !== "text" && this._htmlType !== "area"){ - return; - } const field = document.getElementById('txt-' + this.id); if(field === undefined || field === null){ return; diff --git a/UI/Input/ValidatedTextField.ts b/UI/Input/ValidatedTextField.ts index 188179241..27f1f9051 100644 --- a/UI/Input/ValidatedTextField.ts +++ b/UI/Input/ValidatedTextField.ts @@ -10,53 +10,36 @@ import CombinedInputElement from "./CombinedInputElement"; import SimpleDatePicker from "./SimpleDatePicker"; import OpeningHoursInput from "../OpeningHours/OpeningHoursInput"; import DirectionInput from "./DirectionInput"; +import ColorPicker from "./ColorPicker"; +import {Utils} from "../../Utils"; interface TextFieldDef { name: string, explanation: string, - isValid: ((s: string, country?:() => string) => boolean), + isValid: ((s: string, country?: () => string) => boolean), reformat?: ((s: string, country?: () => string) => string), inputHelper?: (value: UIEventSource, options?: { location: [number, number] }) => InputElement, + + inputmode?: string } export default class ValidatedTextField { - private static tp(name: string, - explanation: string, - isValid?: ((s: string, country?: () => string) => boolean), - reformat?: ((s: string, country?: () => string) => string), - inputHelper?: (value: UIEventSource, options?:{ - location: [number, number] - }) => InputElement): TextFieldDef { - - if (isValid === undefined) { - isValid = () => true; - } - - if (reformat === undefined) { - reformat = (str, _) => str; - } - - - return { - name: name, - explanation: explanation, - isValid: isValid, - reformat: reformat, - inputHelper: inputHelper - } - } - public static tpList: TextFieldDef[] = [ ValidatedTextField.tp( "string", "A basic string"), ValidatedTextField.tp( "text", - "A string, but allows input of longer strings more comfortably (a text area)"), + "A string, but allows input of longer strings more comfortably (a text area)", + undefined, + undefined, + undefined, + "text"), + ValidatedTextField.tp( "date", "A date", @@ -87,44 +70,63 @@ export default class ValidatedTextField { (str) => { str = "" + str; return str !== undefined && str.indexOf(".") < 0 && !isNaN(Number(str)) - }), + }, + undefined, + undefined, + "numeric"), ValidatedTextField.tp( "nat", "A positive number or zero", (str) => { str = "" + str; return str !== undefined && str.indexOf(".") < 0 && !isNaN(Number(str)) && Number(str) >= 0 - }), + }, + undefined, + undefined, + "numeric"), ValidatedTextField.tp( "pnat", "A strict positive number", (str) => { str = "" + str; return str !== undefined && str.indexOf(".") < 0 && !isNaN(Number(str)) && Number(str) > 0 - }), + }, + undefined, + undefined, + "numeric"), ValidatedTextField.tp( "direction", "A geographical direction, in degrees. 0° is north, 90° is east, ... Will return a value between 0 (incl) and 360 (excl)", (str) => { str = "" + str; return str !== undefined && str.indexOf(".") < 0 && !isNaN(Number(str)) && Number(str) >= 0 && Number(str) <= 360 - },str => str, + }, str => str, (value) => { - return new DirectionInput(value); - } + return new DirectionInput(value); + }, + "numeric" ), ValidatedTextField.tp( "float", "A decimal", - (str) => !isNaN(Number(str))), + (str) => !isNaN(Number(str)), + undefined, + undefined, + "decimal"), ValidatedTextField.tp( "pfloat", "A positive decimal (incl zero)", - (str) => !isNaN(Number(str)) && Number(str) >= 0), + (str) => !isNaN(Number(str)) && Number(str) >= 0, + undefined, + undefined, + "decimal"), ValidatedTextField.tp( "email", "An email adress", - (str) => EmailValidator.validate(str)), + (str) => EmailValidator.validate(str), + undefined, + undefined, + "email"), ValidatedTextField.tp( "url", "A url", @@ -135,18 +137,19 @@ export default class ValidatedTextField { } catch (e) { return false; } - }, (str) => { + }, + (str) => { try { const url = new URL(str); const blacklistedTrackingParams = [ "fbclid",// Oh god, how I hate the fbclid. Let it burn, burn in hell! "gclid", - "cmpid", "agid", "utm", "utm_source","utm_medium"] + "cmpid", "agid", "utm", "utm_source", "utm_medium"] for (const dontLike of blacklistedTrackingParams) { url.searchParams.delete(dontLike) } let cleaned = url.toString(); - if(cleaned.endsWith("/") && !str.endsWith("/")){ + if (cleaned.endsWith("/") && !str.endsWith("/")) { // Do not add a trailing '/' if it wasn't typed originally cleaned = cleaned.substr(0, cleaned.length - 1) } @@ -155,7 +158,9 @@ export default class ValidatedTextField { console.error(e) return undefined; } - }), + }, + undefined, + "url"), ValidatedTextField.tp( "phone", "A phone number", @@ -165,26 +170,35 @@ export default class ValidatedTextField { } return parsePhoneNumberFromString(str, (country())?.toUpperCase() as any)?.isValid() ?? false }, - (str, country: () => string) => parsePhoneNumberFromString(str, (country())?.toUpperCase() as any).formatInternational() + (str, country: () => string) => parsePhoneNumberFromString(str, (country())?.toUpperCase() as any).formatInternational(), + undefined, + "tel" ), ValidatedTextField.tp( "opening_hours", "Has extra elements to easily input when a POI is opened", - (s, country) => true, - str => str, + () => true, + str => str, (value) => { return new OpeningHoursInput(value); } + ), + ValidatedTextField.tp( + "color", + "Shows a color picker", + () => true, + str => str, + (value) => { + return new ColorPicker(value.map(color => { + return Utils.ColourNameToHex(color ?? ""); + }, [], str => Utils.HexToColourName(str))) + } ) ] - - private static allTypesDict(){ - const types = {}; - for (const tp of ValidatedTextField.tpList) { - types[tp.name] = tp; - } - return types; - } + /** + * {string (typename) --> TextFieldDef} + */ + public static AllTypes = ValidatedTextField.allTypesDict(); public static TypeDropdown(): DropDown { const values: { value: string, shown: string }[] = []; @@ -195,15 +209,12 @@ export default class ValidatedTextField { return new DropDown("", values) } - /** - * {string (typename) --> TextFieldDef} - */ - public static AllTypes = ValidatedTextField.allTypesDict(); - public static InputForType(type: string, options?: { placeholder?: string | UIElement, value?: UIEventSource, - textArea?: boolean, + htmlType?: string, + textArea?:boolean, + inputMode?:string, textAreaRows?: number, isValid?: ((s: string, country: () => string) => boolean), country?: () => string, @@ -218,16 +229,16 @@ export default class ValidatedTextField { if (options.isValid) { const optValid = options.isValid; isValid = (str, country) => { - if(str === undefined){ + if (str === undefined) { return false; } return isValidTp(str, country ?? options.country) && optValid(str, country ?? options.country); } - }else{ + } else { isValid = isValidTp; } options.isValid = isValid; - + options.inputMode = tp.inputmode; let input: InputElement = new TextField(options); if (tp.reformat) { input.GetValue().addCallbackAndRun(str => { @@ -240,7 +251,7 @@ export default class ValidatedTextField { } if (tp.inputHelper) { - input = new CombinedInputElement(input, tp.inputHelper(input.GetValue(),{ + input = new CombinedInputElement(input, tp.inputHelper(input.GetValue(), { location: options.location })); } @@ -270,7 +281,7 @@ export default class ValidatedTextField { const textField = ValidatedTextField.InputForType(type); return new InputElementMap(textField, (n0, n1) => n0 === n1, fromString, toString) } - + public static KeyInput(allowEmpty: boolean = false): InputElement { function fromString(str) { @@ -299,8 +310,6 @@ export default class ValidatedTextField { return new InputElementMap(textfield, isSame, fromString, toString); } - - static Mapped(fromString: (str) => T, toString: (T) => string, options?: { placeholder?: string | UIElement, type?: string, @@ -323,4 +332,46 @@ export default class ValidatedTextField { ); } + + public static HelpText(): string { + const explanations = ValidatedTextField.tpList.map(type => ["## " + type.name, "", type.explanation].join("\n")).join("\n\n") + return "# Available types for text fields\n\nThe listed types here trigger a special input element. Use them in `tagrendering.freeform.type` of your tagrendering to activate them\n\n" + explanations + } + + private static tp(name: string, + explanation: string, + isValid?: ((s: string, country?: () => string) => boolean), + reformat?: ((s: string, country?: () => string) => string), + inputHelper?: (value: UIEventSource, options?: { + location: [number, number] + }) => InputElement, + inputmode?: string): TextFieldDef { + + if (isValid === undefined) { + isValid = () => true; + } + + if (reformat === undefined) { + reformat = (str, _) => str; + } + + + return { + name: name, + explanation: explanation, + isValid: isValid, + reformat: reformat, + inputHelper: inputHelper, + inputmode: inputmode + } + } + + + private static allTypesDict() { + const types = {}; + for (const tp of ValidatedTextField.tpList) { + types[tp.name] = tp; + } + return types; + } } \ No newline at end of file diff --git a/Utils.ts b/Utils.ts index 9754abc26..96d659af5 100644 --- a/Utils.ts +++ b/Utils.ts @@ -1,6 +1,6 @@ import * as $ from "jquery" import {type} from "os"; - +import * as colors from "./assets/colors.json" export class Utils { /** @@ -305,6 +305,69 @@ export class Utils { element.click(); } + + public static ColourNameToHex(color: string): string{ + return colors[color.toLowerCase()] ?? color; + } + + public static HexToColourName(hex : string): string{ + hex = hex.toLowerCase() + if(!hex.startsWith("#")){ + return hex; + } + const c = Utils.color(hex); + + let smallestDiff = Number.MAX_VALUE; + let bestColor = undefined; + for (const color in colors) { + if(!colors.hasOwnProperty(color)){ + continue; + } + const foundhex = colors[color]; + if(typeof foundhex !== "string"){ + continue + } + if(foundhex === hex){ + return color + } + const diff = this.colorDiff(Utils.color(foundhex), c) + if(diff > 50){ + continue; + } + if(diff < smallestDiff){ + smallestDiff = diff; + bestColor = color; + } + } + return bestColor ?? hex; + } + + private static colorDiff(c0 : {r: number, g: number, b: number}, c1: {r: number, g: number, b: number}){ + return Math.abs(c0.r - c1.r) + Math.abs(c0.g - c1.g) +Math.abs(c0.b - c1.b) ; + } + + private static color(hex: string) : {r: number, g: number, b: number}{ + if(hex.startsWith == undefined){ + console.trace("WUT?", hex) + throw "wut?" + } + if(!hex.startsWith("#")){ + return undefined; + } + if(hex.length === 4){ + return { + r : parseInt(hex.substr(1, 1), 16), + g : parseInt(hex.substr(2, 1), 16), + b : parseInt(hex.substr(3, 1), 16), + } + } + + return { + r : parseInt(hex.substr(1, 2), 16), + g : parseInt(hex.substr(3, 2), 16), + b : parseInt(hex.substr(5, 2), 16), + } + } } export interface TileRange{ diff --git a/assets/colors.json b/assets/colors.json new file mode 100644 index 000000000..c45482273 --- /dev/null +++ b/assets/colors.json @@ -0,0 +1,150 @@ +{ + "aliceblue": "#f0f8ff", + "antiquewhite": "#faebd7", + "aqua": "#00ffff", + "aquamarine": "#7fffd4", + "azure": "#f0ffff", + "beige": "#f5f5dc", + "bisque": "#ffe4c4", + "black": "#000000", + "blanchedalmond": "#ffebcd", + "blue": "#0000ff", + "blueviolet": "#8a2be2", + "brown": "#a52a2a", + "burlywood": "#deb887", + "cadetblue": "#5f9ea0", + "chartreuse": "#7fff00", + "chocolate": "#d2691e", + "coral": "#ff7f50", + "cornflowerblue": "#6495ed", + "cornsilk": "#fff8dc", + "crimson": "#dc143c", + "cyan": "#00ffff", + "darkblue": "#00008b", + "darkcyan": "#008b8b", + "darkgoldenrod": "#b8860b", + "darkgray": "#a9a9a9", + "darkgrey": "#a9a9a9", + "darkgreen": "#006400", + "darkkhaki": "#bdb76b", + "darkmagenta": "#8b008b", + "darkolivegreen": "#556b2f", + "darkorange": "#ff8c00", + "darkorchid": "#9932cc", + "darkred": "#8b0000", + "darksalmon": "#e9967a", + "darkseagreen": "#8fbc8f", + "darkslateblue": "#483d8b", + "darkslategray": "#2f4f4f", + "darkslategrey": "#2f4f4f", + "darkturquoise": "#00ced1", + "darkviolet": "#9400d3", + "deeppink": "#ff1493", + "deepskyblue": "#00bfff", + "dimgray": "#696969", + "dimgrey": "#696969", + "dodgerblue": "#1e90ff", + "firebrick": "#b22222", + "floralwhite": "#fffaf0", + "forestgreen": "#228b22", + "fuchsia": "#ff00ff", + "gainsboro": "#dcdcdc", + "ghostwhite": "#f8f8ff", + "gold": "#ffd700", + "goldenrod": "#daa520", + "gray": "#808080", + "grey": "#808080", + "green": "#008000", + "greenyellow": "#adff2f", + "honeydew": "#f0fff0", + "hotpink": "#ff69b4", + "indianred": "#cd5c5c", + "indigo": "#4b0082", + "ivory": "#fffff0", + "khaki": "#f0e68c", + "lavender": "#e6e6fa", + "lavenderblush": "#fff0f5", + "lawngreen": "#7cfc00", + "lemonchiffon": "#fffacd", + "lightblue": "#add8e6", + "lightcoral": "#f08080", + "lightcyan": "#e0ffff", + "lightgoldenrodyellow": "#fafad2", + "lightgray": "#d3d3d3", + "lightgrey": "#d3d3d3", + "lightgreen": "#90ee90", + "lightpink": "#ffb6c1", + "lightsalmon": "#ffa07a", + "lightseagreen": "#20b2aa", + "lightskyblue": "#87cefa", + "lightslategray": "#778899", + "lightslategrey": "#778899", + "lightsteelblue": "#b0c4de", + "lightyellow": "#ffffe0", + "lime": "#00ff00", + "limegreen": "#32cd32", + "linen": "#faf0e6", + "magenta": "#ff00ff", + "maroon": "#800000", + "mediumaquamarine": "#66cdaa", + "mediumblue": "#0000cd", + "mediumorchid": "#ba55d3", + "mediumpurple": "#9370db", + "mediumseagreen": "#3cb371", + "mediumslateblue": "#7b68ee", + "mediumspringgreen": "#00fa9a", + "mediumturquoise": "#48d1cc", + "mediumvioletred": "#c71585", + "midnightblue": "#191970", + "mintcream": "#f5fffa", + "mistyrose": "#ffe4e1", + "moccasin": "#ffe4b5", + "navajowhite": "#ffdead", + "navy": "#000080", + "oldlace": "#fdf5e6", + "olive": "#808000", + "olivedrab": "#6b8e23", + "orange": "#ffa500", + "orangered": "#ff4500", + "orchid": "#da70d6", + "palegoldenrod": "#eee8aa", + "palegreen": "#98fb98", + "paleturquoise": "#afeeee", + "palevioletred": "#db7093", + "papayawhip": "#ffefd5", + "peachpuff": "#ffdab9", + "peru": "#cd853f", + "pink": "#ffc0cb", + "plum": "#dda0dd", + "powderblue": "#b0e0e6", + "purple": "#800080", + "rebeccapurple": "#663399", + "red": "#ff0000", + "rosybrown": "#bc8f8f", + "royalblue": "#4169e1", + "saddlebrown": "#8b4513", + "salmon": "#fa8072", + "sandybrown": "#f4a460", + "seagreen": "#2e8b57", + "seashell": "#fff5ee", + "sienna": "#a0522d", + "silver": "#c0c0c0", + "skyblue": "#87ceeb", + "slateblue": "#6a5acd", + "slategray": "#708090", + "slategrey": "#708090", + "snow": "#fffafa", + "springgreen": "#00ff7f", + "steelblue": "#4682b4", + "tan": "#d2b48c", + "teal": "#008080", + "thistle": "#d8bfd8", + "tomato": "#ff6347", + "turquoise": "#40e0d0", + "violet": "#ee82ee", + "wheat": "#f5deb3", + "white": "#ffffff", + "whitesmoke": "#f5f5f5", + "yellow": "#ffff00", + "yellowgreen": "#9acd32" +} \ No newline at end of file diff --git a/scripts/generateDocs.ts b/scripts/generateDocs.ts index e371eaa39..9057a3e6a 100644 --- a/scripts/generateDocs.ts +++ b/scripts/generateDocs.ts @@ -6,6 +6,7 @@ import {UIElement} from "../UI/UIElement"; import SimpleMetaTagger from "../Logic/SimpleMetaTagger"; import Combine from "../UI/Base/Combine"; import {ExtraFunction} from "../Logic/ExtraFunction"; +import ValidatedTextField from "../UI/Input/ValidatedTextField"; @@ -19,6 +20,6 @@ function WriteFile(filename, html: UIElement) : void { WriteFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage) WriteFile("./Docs/CalculatedTags.md", new Combine([SimpleMetaTagger.HelpText(), ExtraFunction.HelpText()])) - +writeFileSync("./Docs/SpecialInputElements", ValidatedTextField.HelpText()); console.log("Generated docs") diff --git a/test.html b/test.html index ec8f0b03d..437e113aa 100644 --- a/test.html +++ b/test.html @@ -18,85 +18,8 @@
'maindiv' not attached
'extradiv' not attached
- - - - - + + diff --git a/test.ts b/test.ts index 45ad617f2..ddf4def81 100644 --- a/test.ts +++ b/test.ts @@ -1,4 +1,3 @@ +import ValidatedTextField from "./UI/Input/ValidatedTextField"; - - -alert("Hello world!") \ No newline at end of file +ValidatedTextField.InputForType("phone").AttachTo("maindiv") \ No newline at end of file