@devtools-ui/input 0.2.0--canary.25.1169 → 0.2.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,8 +41,8 @@ var import_react2 = __toESM(require("react"));
41
41
  var import_react3 = require("@chakra-ui/react");
42
42
  var import_react4 = require("@player-ui/react");
43
43
 
44
- // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/hooks.ts
45
- var import_react = __toESM(require("react"));
44
+ // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/hooks/index.ts
45
+ var import_react = require("react");
46
46
  var getConfig = (userConfig = {}) => {
47
47
  return {
48
48
  decimalSymbol: ".",
@@ -53,8 +53,8 @@ var getConfig = (userConfig = {}) => {
53
53
  };
54
54
  };
55
55
  var useInputAssetProps = (props, config) => {
56
- const [localValue, setLocalValue] = import_react.default.useState(props.value ?? "");
57
- const formatTimerRef = import_react.default.useRef(void 0);
56
+ const [localValue, setLocalValue] = (0, import_react.useState)(props.value ?? "");
57
+ const formatTimerRef = (0, import_react.useRef)(void 0);
58
58
  const { formatDelay, decimalSymbol, prefix, suffix } = getConfig(config);
59
59
  function clearPending() {
60
60
  if (formatTimerRef.current) {
@@ -144,10 +144,10 @@ var useInputAssetProps = (props, config) => {
144
144
  }
145
145
  };
146
146
  const propsValue = props.value;
147
- import_react.default.useEffect(() => {
147
+ (0, import_react.useEffect)(() => {
148
148
  setLocalValue(formatValueWithAffix(propsValue));
149
149
  }, [propsValue]);
150
- import_react.default.useEffect(() => clearPending, []);
150
+ (0, import_react.useEffect)(() => clearPending, []);
151
151
  return {
152
152
  onBlur,
153
153
  onChange,
@@ -156,12 +156,59 @@ var useInputAssetProps = (props, config) => {
156
156
  value: localValue
157
157
  };
158
158
  };
159
+ var useFileInputAssetProps = (props) => {
160
+ const { accept } = props;
161
+ const acceptedExtensions = accept ? accept.concat(".json").join(", ") : ".json";
162
+ const onFileUpload = (e) => {
163
+ const fileList = e.target.files;
164
+ const file = fileList ? fileList[0] : "";
165
+ const reader = new FileReader();
166
+ reader.addEventListener(
167
+ "load",
168
+ () => {
169
+ props.set(reader.result);
170
+ },
171
+ false
172
+ );
173
+ if (file) {
174
+ reader.readAsText(file);
175
+ props.handleFile && props.handleFile(file.name);
176
+ }
177
+ };
178
+ return {
179
+ type: "file",
180
+ onChange: onFileUpload,
181
+ accept: acceptedExtensions
182
+ };
183
+ };
159
184
 
160
185
  // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx
186
+ var FileInputComponent = (props) => {
187
+ const hiddenFileInput = (0, import_react2.useRef)(null);
188
+ const [fileName, setFileName] = (0, import_react2.useState)("");
189
+ const handleClick = () => {
190
+ hiddenFileInput.current?.click();
191
+ };
192
+ const handleFile = (fileName2) => {
193
+ setFileName(fileName2);
194
+ };
195
+ const { id, label } = props;
196
+ const inputProps = useFileInputAssetProps({ ...props, handleFile });
197
+ return /* @__PURE__ */ import_react2.default.createElement(import_react3.FormControl, null, /* @__PURE__ */ import_react2.default.createElement(import_react3.Button, { className: "button-file", onClick: handleClick }, /* @__PURE__ */ import_react2.default.createElement(import_react3.FormLabel, { style: { margin: 0 } }, label ? /* @__PURE__ */ import_react2.default.createElement(import_react4.ReactAsset, { ...label.asset }) : /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, "Select Content"))), /* @__PURE__ */ import_react2.default.createElement(
198
+ import_react3.Input,
199
+ {
200
+ id,
201
+ name: id,
202
+ ...inputProps,
203
+ style: { display: "none" },
204
+ ref: hiddenFileInput
205
+ }
206
+ ), fileName ? /* @__PURE__ */ import_react2.default.createElement("p", null, "Uploaded file: ", fileName) : null);
207
+ };
161
208
  var InputComponent = (props) => {
162
- const { validation, label, id, note, size, maxLength, placeholder } = props;
209
+ const { validation, label, id, note, size, maxLength, placeholder, file } = props;
163
210
  const inputProps = useInputAssetProps(props);
164
- return /* @__PURE__ */ import_react2.default.createElement(import_react3.FormControl, { isInvalid: Boolean(validation) }, label && /* @__PURE__ */ import_react2.default.createElement(import_react3.FormLabel, { htmlFor: id }, /* @__PURE__ */ import_react2.default.createElement(import_react4.ReactAsset, { ...label.asset })), /* @__PURE__ */ import_react2.default.createElement(
211
+ return file ? /* @__PURE__ */ import_react2.default.createElement(FileInputComponent, { ...props }) : /* @__PURE__ */ import_react2.default.createElement(import_react3.FormControl, { isInvalid: Boolean(validation) }, label && /* @__PURE__ */ import_react2.default.createElement(import_react3.FormLabel, { htmlFor: id }, /* @__PURE__ */ import_react2.default.createElement(import_react4.ReactAsset, { ...label.asset })), /* @__PURE__ */ import_react2.default.createElement(
165
212
  import_react3.Input,
166
213
  {
167
214
  id,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/index.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/hooks.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/dsl/Input.tsx","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/transform/index.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./components\";\nexport * from \"./dsl\";\nexport * from \"./transform\";\n","import React from \"react\";\nimport {\n Input,\n FormControl,\n FormLabel,\n FormHelperText,\n FormErrorMessage,\n} from \"@chakra-ui/react\";\nimport { TransformedInput } from \"../types\";\nimport { ReactAsset } from \"@player-ui/react\";\nimport { useInputAssetProps } from \"./hooks\";\n\nexport const InputComponent = (props: TransformedInput) => {\n const { validation, label, id, note, size, maxLength, placeholder } = props;\n const inputProps = useInputAssetProps(props);\n\n return (\n <FormControl isInvalid={Boolean(validation)}>\n {label && (\n <FormLabel htmlFor={id}>\n <ReactAsset {...label.asset} />\n </FormLabel>\n )}\n <Input\n id={id}\n {...inputProps}\n size={size}\n maxLength={maxLength}\n placeholder={placeholder}\n />\n {validation && <FormErrorMessage>{validation.message}</FormErrorMessage>}\n {note && (\n <FormHelperText>\n <ReactAsset {...note.asset} />\n </FormHelperText>\n )}\n </FormControl>\n );\n};\n","import React from \"react\";\nimport type { TransformedInput } from \"../types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KeyDownHandler = (currentValue: string, props?: TransformedInput) => any;\n\nexport interface InputHookConfig {\n /** Time in ms to wait before formatting the user input for normal keys */\n formatDelay?: number;\n\n /** Symbol to be used for decimal point */\n decimalSymbol?: string;\n\n /** Affix to append to value - does not save to model and is only for display on input */\n prefix?: string;\n\n /** Affix to prepend to value - does not save to model and is only for display on input */\n suffix?: string;\n}\n\n/** Create a valid config mixing in defaults and user overrides */\nexport const getConfig = (\n userConfig: InputHookConfig = {}\n): Required<InputHookConfig> => {\n return {\n decimalSymbol: \".\",\n formatDelay: 200,\n prefix: \"\",\n suffix: \"\",\n ...userConfig,\n };\n};\n\n/**\n * A hook to manage an input html element as an asset.\n * The hook returns an object containing props that are expected to reside on any html input.\n * It will handle formatting, setting values, beaconing, aria-labels, etc.\n *\n * @param props - The output of the input transform\n * @param config - Local config to manage user interaction overrides\n */\nexport const useInputAssetProps = (\n props: TransformedInput,\n config?: InputHookConfig\n) => {\n const [localValue, setLocalValue] = React.useState(props.value ?? \"\");\n const formatTimerRef = React.useRef<NodeJS.Timeout | undefined>(undefined);\n\n const { formatDelay, decimalSymbol, prefix, suffix } = getConfig(config);\n\n /** Reset and pending format timers */\n function clearPending() {\n if (formatTimerRef.current) {\n clearTimeout(formatTimerRef.current);\n formatTimerRef.current = undefined;\n }\n }\n\n /** Affix handling logic on focus */\n function handleAffixOnFocus(target: HTMLInputElement) {\n let val = target.value;\n\n if (suffix) val = val.substring(0, val.indexOf(suffix));\n\n if (prefix && !val.includes(prefix)) {\n val = `${prefix}${val}`;\n }\n\n return val;\n }\n\n /** Edge cases handling for prefix */\n function handlePrefixEdgeCases(e: React.KeyboardEvent<HTMLInputElement>) {\n const target = e.target as HTMLInputElement;\n const start = target.selectionStart;\n const end = target.selectionEnd;\n const pl = prefix.length;\n const atStart = start === pl;\n const atEnd = end === pl;\n\n if (start && end && start < pl) {\n e.preventDefault();\n target.setSelectionRange(pl, end - start + pl);\n } else if (\n (e.key === \"ArrowLeft\" && atStart) ||\n (e.key === \"Backspace\" && atStart && atEnd) ||\n e.key === \"Home\"\n ) {\n e.preventDefault();\n target.setSelectionRange(prefix.length, prefix.length);\n }\n }\n\n /** Helper to add affixes to value where appropriate */\n function formatValueWithAffix(value: string | undefined) {\n if (!value) return \"\";\n\n return `${prefix}${value}${suffix}`;\n }\n\n /** Value handling logic on key down */\n const onKeyDownHandler: KeyDownHandler = (currentValue: string) => {\n const symbolPosition = currentValue.indexOf(decimalSymbol);\n const newValue = props.format(currentValue) ?? \"\";\n const newSymbolPosition = newValue.indexOf(decimalSymbol);\n\n if (\n (symbolPosition === -1 || symbolPosition === 0) &&\n newSymbolPosition > 0\n ) {\n // formatting added dot, so set cursor before dot\n return {\n newValue: newValue.includes(prefix)\n ? `${newValue}`\n : `${prefix}${newValue}`,\n newCursorPosition: newValue.includes(prefix)\n ? newSymbolPosition\n : newSymbolPosition + prefix.length,\n };\n }\n\n return {\n newValue: newValue.includes(prefix)\n ? `${newValue}`\n : `${prefix}${newValue}`,\n };\n };\n\n /** On blur, commit the value to the model */\n const onBlur: React.FocusEventHandler<HTMLInputElement> = (e) => {\n clearPending();\n\n const formatted =\n (prefix\n ? e.target.value.replace(prefix, \"\")\n : props.format(e.target.value)) ?? \"\";\n\n if (formatted) {\n props.set(formatted);\n setLocalValue(formatValueWithAffix(formatted));\n } else {\n props.set(\"\");\n setLocalValue(\"\");\n }\n };\n\n /** Keep track of any user changes */\n const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n setLocalValue(e.target.value);\n };\n\n /** Schedule a format of the current input in the future */\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (e) => {\n clearPending();\n\n if (prefix) handlePrefixEdgeCases(e);\n\n const target = e.target as HTMLInputElement;\n\n formatTimerRef.current = setTimeout(() => {\n const cursorPosition = target.selectionStart;\n const currentValue = target.value;\n\n /** Skip formatting if we're in the middle of the input */\n if (cursorPosition !== currentValue.length) {\n return;\n }\n\n const obj = onKeyDownHandler(currentValue);\n\n setLocalValue(obj.newValue);\n target.selectionStart = obj.newCursorPosition ?? target.selectionStart;\n target.selectionEnd = obj.newCursorPosition ?? target.selectionEnd;\n }, formatDelay);\n };\n\n /** Format value onFocus if affixes exist */\n const onFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {\n const target = e.target as HTMLInputElement;\n const inputEmpty = target.value === \"\";\n\n if ((!inputEmpty && suffix) || (inputEmpty && prefix)) {\n setLocalValue(handleAffixOnFocus(target));\n }\n };\n\n // Update the stored value if data changes\n const propsValue = props.value;\n React.useEffect(() => {\n setLocalValue(formatValueWithAffix(propsValue));\n }, [propsValue]);\n\n /** clear anything pending on unmount of input */\n React.useEffect(() => clearPending, []);\n\n return {\n onBlur,\n onChange,\n onKeyDown,\n onFocus,\n value: localValue,\n };\n};\n","import React from \"react\";\nimport {\n AssetPropsWithChildren,\n Asset,\n createSlot,\n BindingTemplateInstance,\n} from \"@player-tools/dsl\";\nimport { InputAsset } from \"../types\";\nimport { Text } from \"@devtools-ui/text\";\n\nexport const Input = (\n props: Omit<AssetPropsWithChildren<InputAsset>, \"binding\"> & {\n /** The binding */\n binding: BindingTemplateInstance;\n }\n) => {\n const { children, binding, ...rest } = props;\n return (\n <Asset type=\"input\" {...rest}>\n <property name=\"binding\">{binding.toValue()}</property>\n {children}\n </Asset>\n );\n};\n\nInput.Label = createSlot({\n name: \"label\",\n TextComp: Text,\n isArray: false,\n wrapInAsset: true,\n});\n\nInput.Note = createSlot({\n name: \"note\",\n TextComp: Text,\n isArray: false,\n wrapInAsset: true,\n});\n","import type { TransformFunction } from \"@player-ui/player\";\nimport { InputAsset, TransformedInput } from \"../types\";\n\nexport const inputTransform: TransformFunction<InputAsset, TransformedInput> = (\n asset,\n options\n) => {\n return {\n ...asset,\n format(val) {\n if (asset.binding === undefined) {\n return val;\n }\n\n return options.data.format(asset.binding, val);\n },\n set(val) {\n if (asset.binding === undefined) {\n return;\n }\n\n return options.data.model.set([[asset.binding, val]], {\n formatted: true,\n });\n },\n value:\n asset.binding === undefined\n ? \"\"\n : options.data.model.get(asset.binding, {\n includeInvalid: true,\n formatted: true,\n }),\n validation:\n asset.binding === undefined\n ? undefined\n : options.validation?.get(asset.binding, { track: true }),\n dataType:\n asset.binding === undefined\n ? undefined\n : options.validation?.type(asset.binding),\n };\n};\n"],"mappings":"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","names":["Input","import_react","React","React","import_react","Input","React"]}
1
+ {"version":3,"sources":["../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/index.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/hooks/index.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/dsl/Input.tsx","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/transform/index.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./components\";\nexport * from \"./dsl\";\nexport * from \"./transform\";\n","import React, { useState, useRef } from \"react\";\nimport {\n Input,\n Button,\n FormControl,\n FormLabel,\n FormHelperText,\n FormErrorMessage,\n} from \"@chakra-ui/react\";\nimport { TransformedInput } from \"../types\";\nimport { ReactAsset } from \"@player-ui/react\";\nimport { useInputAssetProps, useFileInputAssetProps } from \"../hooks\";\n\nconst FileInputComponent = (props: TransformedInput) => {\n const hiddenFileInput: React.Ref<any> = useRef(null);\n\n const [fileName, setFileName] = useState(\"\");\n\n const handleClick = () => {\n hiddenFileInput.current?.click();\n };\n\n const handleFile = (fileName: string) => {\n setFileName(fileName);\n };\n\n const { id, label } = props;\n\n const inputProps = useFileInputAssetProps({ ...props, handleFile });\n\n return (\n <FormControl>\n <Button className=\"button-file\" onClick={handleClick}>\n <FormLabel style={{ margin: 0 }}>\n {label ? <ReactAsset {...label.asset} /> : <>Select Content</>}\n </FormLabel>\n </Button>\n <Input\n id={id}\n name={id}\n {...inputProps}\n style={{ display: \"none\" }}\n ref={hiddenFileInput}\n />\n {fileName ? <p>Uploaded file: {fileName}</p> : null}\n </FormControl>\n );\n};\n\nexport const InputComponent = (props: TransformedInput) => {\n const { validation, label, id, note, size, maxLength, placeholder, file } =\n props;\n\n const inputProps = useInputAssetProps(props);\n\n return file ? (\n <FileInputComponent {...props} />\n ) : (\n <FormControl isInvalid={Boolean(validation)}>\n {label && (\n <FormLabel htmlFor={id}>\n <ReactAsset {...label.asset} />\n </FormLabel>\n )}\n <Input\n id={id}\n {...inputProps}\n size={size}\n maxLength={maxLength}\n placeholder={placeholder}\n />\n {validation && <FormErrorMessage>{validation.message}</FormErrorMessage>}\n {note && (\n <FormHelperText>\n <ReactAsset {...note.asset} />\n </FormHelperText>\n )}\n </FormControl>\n );\n};\n","import React, { useState, useEffect, useRef } from \"react\";\nimport type { TransformedInput } from \"../types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KeyDownHandler = (currentValue: string, props?: TransformedInput) => any;\n\nexport interface InputHookConfig {\n /** Time in ms to wait before formatting the user input for normal keys */\n formatDelay?: number;\n\n /** Symbol to be used for decimal point */\n decimalSymbol?: string;\n\n /** Affix to append to value - does not save to model and is only for display on input */\n prefix?: string;\n\n /** Affix to prepend to value - does not save to model and is only for display on input */\n suffix?: string;\n}\n\n/** Create a valid config mixing in defaults and user overrides */\nexport const getConfig = (\n userConfig: InputHookConfig = {}\n): Required<InputHookConfig> => {\n return {\n decimalSymbol: \".\",\n formatDelay: 200,\n prefix: \"\",\n suffix: \"\",\n ...userConfig,\n };\n};\n\n/**\n * A hook to manage an input html element as an asset.\n * The hook returns an object containing props that are expected to reside on any html input.\n * It will handle formatting, setting values, beaconing, aria-labels, etc.\n *\n * @param props - The output of the input transform\n * @param config - Local config to manage user interaction overrides\n */\nexport const useInputAssetProps = (\n props: TransformedInput,\n config?: InputHookConfig\n) => {\n const [localValue, setLocalValue] = useState(props.value ?? \"\");\n const formatTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);\n\n const { formatDelay, decimalSymbol, prefix, suffix } = getConfig(config);\n\n /** Reset and pending format timers */\n function clearPending() {\n if (formatTimerRef.current) {\n clearTimeout(formatTimerRef.current);\n formatTimerRef.current = undefined;\n }\n }\n\n /** Affix handling logic on focus */\n function handleAffixOnFocus(target: HTMLInputElement) {\n let val = target.value;\n\n if (suffix) val = val.substring(0, val.indexOf(suffix));\n\n if (prefix && !val.includes(prefix)) {\n val = `${prefix}${val}`;\n }\n\n return val;\n }\n\n /** Edge cases handling for prefix */\n function handlePrefixEdgeCases(e: React.KeyboardEvent<HTMLInputElement>) {\n const target = e.target as HTMLInputElement;\n const start = target.selectionStart;\n const end = target.selectionEnd;\n const pl = prefix.length;\n const atStart = start === pl;\n const atEnd = end === pl;\n\n if (start && end && start < pl) {\n e.preventDefault();\n target.setSelectionRange(pl, end - start + pl);\n } else if (\n (e.key === \"ArrowLeft\" && atStart) ||\n (e.key === \"Backspace\" && atStart && atEnd) ||\n e.key === \"Home\"\n ) {\n e.preventDefault();\n target.setSelectionRange(prefix.length, prefix.length);\n }\n }\n\n /** Helper to add affixes to value where appropriate */\n function formatValueWithAffix(value: string | undefined) {\n if (!value) return \"\";\n\n return `${prefix}${value}${suffix}`;\n }\n\n /** Value handling logic on key down */\n const onKeyDownHandler: KeyDownHandler = (currentValue: string) => {\n const symbolPosition = currentValue.indexOf(decimalSymbol);\n const newValue = props.format(currentValue) ?? \"\";\n const newSymbolPosition = newValue.indexOf(decimalSymbol);\n\n if (\n (symbolPosition === -1 || symbolPosition === 0) &&\n newSymbolPosition > 0\n ) {\n // formatting added dot, so set cursor before dot\n return {\n newValue: newValue.includes(prefix)\n ? `${newValue}`\n : `${prefix}${newValue}`,\n newCursorPosition: newValue.includes(prefix)\n ? newSymbolPosition\n : newSymbolPosition + prefix.length,\n };\n }\n\n return {\n newValue: newValue.includes(prefix)\n ? `${newValue}`\n : `${prefix}${newValue}`,\n };\n };\n\n /** On blur, commit the value to the model */\n const onBlur: React.FocusEventHandler<HTMLInputElement> = (e) => {\n clearPending();\n\n const formatted =\n (prefix\n ? e.target.value.replace(prefix, \"\")\n : props.format(e.target.value)) ?? \"\";\n\n if (formatted) {\n props.set(formatted);\n setLocalValue(formatValueWithAffix(formatted));\n } else {\n props.set(\"\");\n setLocalValue(\"\");\n }\n };\n\n /** Keep track of any user changes */\n const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n setLocalValue(e.target.value);\n };\n\n /** Schedule a format of the current input in the future */\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (e) => {\n clearPending();\n\n if (prefix) handlePrefixEdgeCases(e);\n\n const target = e.target as HTMLInputElement;\n\n formatTimerRef.current = setTimeout(() => {\n const cursorPosition = target.selectionStart;\n const currentValue = target.value;\n\n /** Skip formatting if we're in the middle of the input */\n if (cursorPosition !== currentValue.length) {\n return;\n }\n\n const obj = onKeyDownHandler(currentValue);\n\n setLocalValue(obj.newValue);\n target.selectionStart = obj.newCursorPosition ?? target.selectionStart;\n target.selectionEnd = obj.newCursorPosition ?? target.selectionEnd;\n }, formatDelay);\n };\n\n /** Format value onFocus if affixes exist */\n const onFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {\n const target = e.target as HTMLInputElement;\n const inputEmpty = target.value === \"\";\n\n if ((!inputEmpty && suffix) || (inputEmpty && prefix)) {\n setLocalValue(handleAffixOnFocus(target));\n }\n };\n\n // Update the stored value if data changes\n const propsValue = props.value;\n useEffect(() => {\n setLocalValue(formatValueWithAffix(propsValue));\n }, [propsValue]);\n\n /** clear anything pending on unmount of input */\n useEffect(() => clearPending, []);\n\n return {\n onBlur,\n onChange,\n onKeyDown,\n onFocus,\n value: localValue,\n };\n};\n\n/** Props for file type Input */\nexport const useFileInputAssetProps = (props: TransformedInput) => {\n const { accept } = props;\n\n const acceptedExtensions = accept\n ? accept.concat(\".json\").join(\", \")\n : \".json\";\n\n /** Parses file content for upload into a string if file type Input */\n const onFileUpload: React.ChangeEventHandler = (e): void => {\n const fileList = (<HTMLInputElement>e.target).files;\n const file = fileList ? fileList[0] : \"\";\n const reader = new FileReader();\n\n reader.addEventListener(\n \"load\",\n () => {\n // this will set the file contents in the data model\n props.set(reader.result as string);\n },\n false\n );\n\n if (file) {\n reader.readAsText(file);\n props.handleFile && props.handleFile(file.name);\n }\n };\n\n return {\n type: \"file\",\n onChange: onFileUpload,\n accept: acceptedExtensions,\n };\n};\n","import React from \"react\";\nimport {\n AssetPropsWithChildren,\n Asset,\n createSlot,\n BindingTemplateInstance,\n} from \"@player-tools/dsl\";\nimport { InputAsset } from \"../types\";\nimport { Text } from \"@devtools-ui/text\";\n\nexport const Input = (\n props: Omit<AssetPropsWithChildren<InputAsset>, \"binding\"> & {\n /** The binding */\n binding: BindingTemplateInstance;\n }\n) => {\n const { children, binding, ...rest } = props;\n return (\n <Asset type=\"input\" {...rest}>\n <property name=\"binding\">{binding.toValue()}</property>\n {children}\n </Asset>\n );\n};\n\nInput.Label = createSlot({\n name: \"label\",\n TextComp: Text,\n isArray: false,\n wrapInAsset: true,\n});\n\nInput.Note = createSlot({\n name: \"note\",\n TextComp: Text,\n isArray: false,\n wrapInAsset: true,\n});\n","import type { TransformFunction } from \"@player-ui/player\";\nimport { InputAsset, TransformedInput } from \"../types\";\n\nexport const inputTransform: TransformFunction<InputAsset, TransformedInput> = (\n asset,\n options\n) => {\n return {\n ...asset,\n format(val) {\n if (asset.binding === undefined) {\n return val;\n }\n\n return options.data.format(asset.binding, val);\n },\n set(val) {\n if (asset.binding === undefined) {\n return;\n }\n\n return options.data.model.set([[asset.binding, val]], {\n formatted: true,\n });\n },\n value:\n asset.binding === undefined\n ? \"\"\n : options.data.model.get(asset.binding, {\n includeInvalid: true,\n formatted: true,\n }),\n validation:\n asset.binding === undefined\n ? undefined\n : options.validation?.get(asset.binding, { track: true }),\n dataType:\n asset.binding === undefined\n ? undefined\n : options.validation?.type(asset.binding),\n };\n};\n"],"mappings":"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","names":["Input","import_react","fileName","React","import_react","Input","React"]}
@@ -1,7 +1,8 @@
1
1
  // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx
2
- import React2 from "react";
2
+ import React2, { useState as useState2, useRef as useRef2 } from "react";
3
3
  import {
4
4
  Input,
5
+ Button,
5
6
  FormControl,
6
7
  FormLabel,
7
8
  FormHelperText,
@@ -9,8 +10,8 @@ import {
9
10
  } from "@chakra-ui/react";
10
11
  import { ReactAsset } from "@player-ui/react";
11
12
 
12
- // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/hooks.ts
13
- import React from "react";
13
+ // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/hooks/index.ts
14
+ import { useState, useEffect, useRef } from "react";
14
15
  var getConfig = (userConfig = {}) => {
15
16
  return {
16
17
  decimalSymbol: ".",
@@ -21,8 +22,8 @@ var getConfig = (userConfig = {}) => {
21
22
  };
22
23
  };
23
24
  var useInputAssetProps = (props, config) => {
24
- const [localValue, setLocalValue] = React.useState(props.value ?? "");
25
- const formatTimerRef = React.useRef(void 0);
25
+ const [localValue, setLocalValue] = useState(props.value ?? "");
26
+ const formatTimerRef = useRef(void 0);
26
27
  const { formatDelay, decimalSymbol, prefix, suffix } = getConfig(config);
27
28
  function clearPending() {
28
29
  if (formatTimerRef.current) {
@@ -112,10 +113,10 @@ var useInputAssetProps = (props, config) => {
112
113
  }
113
114
  };
114
115
  const propsValue = props.value;
115
- React.useEffect(() => {
116
+ useEffect(() => {
116
117
  setLocalValue(formatValueWithAffix(propsValue));
117
118
  }, [propsValue]);
118
- React.useEffect(() => clearPending, []);
119
+ useEffect(() => clearPending, []);
119
120
  return {
120
121
  onBlur,
121
122
  onChange,
@@ -124,12 +125,59 @@ var useInputAssetProps = (props, config) => {
124
125
  value: localValue
125
126
  };
126
127
  };
128
+ var useFileInputAssetProps = (props) => {
129
+ const { accept } = props;
130
+ const acceptedExtensions = accept ? accept.concat(".json").join(", ") : ".json";
131
+ const onFileUpload = (e) => {
132
+ const fileList = e.target.files;
133
+ const file = fileList ? fileList[0] : "";
134
+ const reader = new FileReader();
135
+ reader.addEventListener(
136
+ "load",
137
+ () => {
138
+ props.set(reader.result);
139
+ },
140
+ false
141
+ );
142
+ if (file) {
143
+ reader.readAsText(file);
144
+ props.handleFile && props.handleFile(file.name);
145
+ }
146
+ };
147
+ return {
148
+ type: "file",
149
+ onChange: onFileUpload,
150
+ accept: acceptedExtensions
151
+ };
152
+ };
127
153
 
128
154
  // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx
155
+ var FileInputComponent = (props) => {
156
+ const hiddenFileInput = useRef2(null);
157
+ const [fileName, setFileName] = useState2("");
158
+ const handleClick = () => {
159
+ hiddenFileInput.current?.click();
160
+ };
161
+ const handleFile = (fileName2) => {
162
+ setFileName(fileName2);
163
+ };
164
+ const { id, label } = props;
165
+ const inputProps = useFileInputAssetProps({ ...props, handleFile });
166
+ return /* @__PURE__ */ React2.createElement(FormControl, null, /* @__PURE__ */ React2.createElement(Button, { className: "button-file", onClick: handleClick }, /* @__PURE__ */ React2.createElement(FormLabel, { style: { margin: 0 } }, label ? /* @__PURE__ */ React2.createElement(ReactAsset, { ...label.asset }) : /* @__PURE__ */ React2.createElement(React2.Fragment, null, "Select Content"))), /* @__PURE__ */ React2.createElement(
167
+ Input,
168
+ {
169
+ id,
170
+ name: id,
171
+ ...inputProps,
172
+ style: { display: "none" },
173
+ ref: hiddenFileInput
174
+ }
175
+ ), fileName ? /* @__PURE__ */ React2.createElement("p", null, "Uploaded file: ", fileName) : null);
176
+ };
129
177
  var InputComponent = (props) => {
130
- const { validation, label, id, note, size, maxLength, placeholder } = props;
178
+ const { validation, label, id, note, size, maxLength, placeholder, file } = props;
131
179
  const inputProps = useInputAssetProps(props);
132
- return /* @__PURE__ */ React2.createElement(FormControl, { isInvalid: Boolean(validation) }, label && /* @__PURE__ */ React2.createElement(FormLabel, { htmlFor: id }, /* @__PURE__ */ React2.createElement(ReactAsset, { ...label.asset })), /* @__PURE__ */ React2.createElement(
180
+ return file ? /* @__PURE__ */ React2.createElement(FileInputComponent, { ...props }) : /* @__PURE__ */ React2.createElement(FormControl, { isInvalid: Boolean(validation) }, label && /* @__PURE__ */ React2.createElement(FormLabel, { htmlFor: id }, /* @__PURE__ */ React2.createElement(ReactAsset, { ...label.asset })), /* @__PURE__ */ React2.createElement(
133
181
  Input,
134
182
  {
135
183
  id,
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx
2
- import React2 from "react";
2
+ import React2, { useState as useState2, useRef as useRef2 } from "react";
3
3
  import {
4
4
  Input,
5
+ Button,
5
6
  FormControl,
6
7
  FormLabel,
7
8
  FormHelperText,
@@ -9,8 +10,8 @@ import {
9
10
  } from "@chakra-ui/react";
10
11
  import { ReactAsset } from "@player-ui/react";
11
12
 
12
- // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/hooks.ts
13
- import React from "react";
13
+ // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/hooks/index.ts
14
+ import { useState, useEffect, useRef } from "react";
14
15
  var getConfig = (userConfig = {}) => {
15
16
  return {
16
17
  decimalSymbol: ".",
@@ -21,8 +22,8 @@ var getConfig = (userConfig = {}) => {
21
22
  };
22
23
  };
23
24
  var useInputAssetProps = (props, config) => {
24
- const [localValue, setLocalValue] = React.useState(props.value ?? "");
25
- const formatTimerRef = React.useRef(void 0);
25
+ const [localValue, setLocalValue] = useState(props.value ?? "");
26
+ const formatTimerRef = useRef(void 0);
26
27
  const { formatDelay, decimalSymbol, prefix, suffix } = getConfig(config);
27
28
  function clearPending() {
28
29
  if (formatTimerRef.current) {
@@ -112,10 +113,10 @@ var useInputAssetProps = (props, config) => {
112
113
  }
113
114
  };
114
115
  const propsValue = props.value;
115
- React.useEffect(() => {
116
+ useEffect(() => {
116
117
  setLocalValue(formatValueWithAffix(propsValue));
117
118
  }, [propsValue]);
118
- React.useEffect(() => clearPending, []);
119
+ useEffect(() => clearPending, []);
119
120
  return {
120
121
  onBlur,
121
122
  onChange,
@@ -124,12 +125,59 @@ var useInputAssetProps = (props, config) => {
124
125
  value: localValue
125
126
  };
126
127
  };
128
+ var useFileInputAssetProps = (props) => {
129
+ const { accept } = props;
130
+ const acceptedExtensions = accept ? accept.concat(".json").join(", ") : ".json";
131
+ const onFileUpload = (e) => {
132
+ const fileList = e.target.files;
133
+ const file = fileList ? fileList[0] : "";
134
+ const reader = new FileReader();
135
+ reader.addEventListener(
136
+ "load",
137
+ () => {
138
+ props.set(reader.result);
139
+ },
140
+ false
141
+ );
142
+ if (file) {
143
+ reader.readAsText(file);
144
+ props.handleFile && props.handleFile(file.name);
145
+ }
146
+ };
147
+ return {
148
+ type: "file",
149
+ onChange: onFileUpload,
150
+ accept: acceptedExtensions
151
+ };
152
+ };
127
153
 
128
154
  // ../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx
155
+ var FileInputComponent = (props) => {
156
+ const hiddenFileInput = useRef2(null);
157
+ const [fileName, setFileName] = useState2("");
158
+ const handleClick = () => {
159
+ hiddenFileInput.current?.click();
160
+ };
161
+ const handleFile = (fileName2) => {
162
+ setFileName(fileName2);
163
+ };
164
+ const { id, label } = props;
165
+ const inputProps = useFileInputAssetProps({ ...props, handleFile });
166
+ return /* @__PURE__ */ React2.createElement(FormControl, null, /* @__PURE__ */ React2.createElement(Button, { className: "button-file", onClick: handleClick }, /* @__PURE__ */ React2.createElement(FormLabel, { style: { margin: 0 } }, label ? /* @__PURE__ */ React2.createElement(ReactAsset, { ...label.asset }) : /* @__PURE__ */ React2.createElement(React2.Fragment, null, "Select Content"))), /* @__PURE__ */ React2.createElement(
167
+ Input,
168
+ {
169
+ id,
170
+ name: id,
171
+ ...inputProps,
172
+ style: { display: "none" },
173
+ ref: hiddenFileInput
174
+ }
175
+ ), fileName ? /* @__PURE__ */ React2.createElement("p", null, "Uploaded file: ", fileName) : null);
176
+ };
129
177
  var InputComponent = (props) => {
130
- const { validation, label, id, note, size, maxLength, placeholder } = props;
178
+ const { validation, label, id, note, size, maxLength, placeholder, file } = props;
131
179
  const inputProps = useInputAssetProps(props);
132
- return /* @__PURE__ */ React2.createElement(FormControl, { isInvalid: Boolean(validation) }, label && /* @__PURE__ */ React2.createElement(FormLabel, { htmlFor: id }, /* @__PURE__ */ React2.createElement(ReactAsset, { ...label.asset })), /* @__PURE__ */ React2.createElement(
180
+ return file ? /* @__PURE__ */ React2.createElement(FileInputComponent, { ...props }) : /* @__PURE__ */ React2.createElement(FormControl, { isInvalid: Boolean(validation) }, label && /* @__PURE__ */ React2.createElement(FormLabel, { htmlFor: id }, /* @__PURE__ */ React2.createElement(ReactAsset, { ...label.asset })), /* @__PURE__ */ React2.createElement(
133
181
  Input,
134
182
  {
135
183
  id,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx","../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/hooks.ts","../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/dsl/Input.tsx","../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/transform/index.ts"],"sourcesContent":["import React from \"react\";\nimport {\n Input,\n FormControl,\n FormLabel,\n FormHelperText,\n FormErrorMessage,\n} from \"@chakra-ui/react\";\nimport { TransformedInput } from \"../types\";\nimport { ReactAsset } from \"@player-ui/react\";\nimport { useInputAssetProps } from \"./hooks\";\n\nexport const InputComponent = (props: TransformedInput) => {\n const { validation, label, id, note, size, maxLength, placeholder } = props;\n const inputProps = useInputAssetProps(props);\n\n return (\n <FormControl isInvalid={Boolean(validation)}>\n {label && (\n <FormLabel htmlFor={id}>\n <ReactAsset {...label.asset} />\n </FormLabel>\n )}\n <Input\n id={id}\n {...inputProps}\n size={size}\n maxLength={maxLength}\n placeholder={placeholder}\n />\n {validation && <FormErrorMessage>{validation.message}</FormErrorMessage>}\n {note && (\n <FormHelperText>\n <ReactAsset {...note.asset} />\n </FormHelperText>\n )}\n </FormControl>\n );\n};\n","import React from \"react\";\nimport type { TransformedInput } from \"../types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KeyDownHandler = (currentValue: string, props?: TransformedInput) => any;\n\nexport interface InputHookConfig {\n /** Time in ms to wait before formatting the user input for normal keys */\n formatDelay?: number;\n\n /** Symbol to be used for decimal point */\n decimalSymbol?: string;\n\n /** Affix to append to value - does not save to model and is only for display on input */\n prefix?: string;\n\n /** Affix to prepend to value - does not save to model and is only for display on input */\n suffix?: string;\n}\n\n/** Create a valid config mixing in defaults and user overrides */\nexport const getConfig = (\n userConfig: InputHookConfig = {}\n): Required<InputHookConfig> => {\n return {\n decimalSymbol: \".\",\n formatDelay: 200,\n prefix: \"\",\n suffix: \"\",\n ...userConfig,\n };\n};\n\n/**\n * A hook to manage an input html element as an asset.\n * The hook returns an object containing props that are expected to reside on any html input.\n * It will handle formatting, setting values, beaconing, aria-labels, etc.\n *\n * @param props - The output of the input transform\n * @param config - Local config to manage user interaction overrides\n */\nexport const useInputAssetProps = (\n props: TransformedInput,\n config?: InputHookConfig\n) => {\n const [localValue, setLocalValue] = React.useState(props.value ?? \"\");\n const formatTimerRef = React.useRef<NodeJS.Timeout | undefined>(undefined);\n\n const { formatDelay, decimalSymbol, prefix, suffix } = getConfig(config);\n\n /** Reset and pending format timers */\n function clearPending() {\n if (formatTimerRef.current) {\n clearTimeout(formatTimerRef.current);\n formatTimerRef.current = undefined;\n }\n }\n\n /** Affix handling logic on focus */\n function handleAffixOnFocus(target: HTMLInputElement) {\n let val = target.value;\n\n if (suffix) val = val.substring(0, val.indexOf(suffix));\n\n if (prefix && !val.includes(prefix)) {\n val = `${prefix}${val}`;\n }\n\n return val;\n }\n\n /** Edge cases handling for prefix */\n function handlePrefixEdgeCases(e: React.KeyboardEvent<HTMLInputElement>) {\n const target = e.target as HTMLInputElement;\n const start = target.selectionStart;\n const end = target.selectionEnd;\n const pl = prefix.length;\n const atStart = start === pl;\n const atEnd = end === pl;\n\n if (start && end && start < pl) {\n e.preventDefault();\n target.setSelectionRange(pl, end - start + pl);\n } else if (\n (e.key === \"ArrowLeft\" && atStart) ||\n (e.key === \"Backspace\" && atStart && atEnd) ||\n e.key === \"Home\"\n ) {\n e.preventDefault();\n target.setSelectionRange(prefix.length, prefix.length);\n }\n }\n\n /** Helper to add affixes to value where appropriate */\n function formatValueWithAffix(value: string | undefined) {\n if (!value) return \"\";\n\n return `${prefix}${value}${suffix}`;\n }\n\n /** Value handling logic on key down */\n const onKeyDownHandler: KeyDownHandler = (currentValue: string) => {\n const symbolPosition = currentValue.indexOf(decimalSymbol);\n const newValue = props.format(currentValue) ?? \"\";\n const newSymbolPosition = newValue.indexOf(decimalSymbol);\n\n if (\n (symbolPosition === -1 || symbolPosition === 0) &&\n newSymbolPosition > 0\n ) {\n // formatting added dot, so set cursor before dot\n return {\n newValue: newValue.includes(prefix)\n ? `${newValue}`\n : `${prefix}${newValue}`,\n newCursorPosition: newValue.includes(prefix)\n ? newSymbolPosition\n : newSymbolPosition + prefix.length,\n };\n }\n\n return {\n newValue: newValue.includes(prefix)\n ? `${newValue}`\n : `${prefix}${newValue}`,\n };\n };\n\n /** On blur, commit the value to the model */\n const onBlur: React.FocusEventHandler<HTMLInputElement> = (e) => {\n clearPending();\n\n const formatted =\n (prefix\n ? e.target.value.replace(prefix, \"\")\n : props.format(e.target.value)) ?? \"\";\n\n if (formatted) {\n props.set(formatted);\n setLocalValue(formatValueWithAffix(formatted));\n } else {\n props.set(\"\");\n setLocalValue(\"\");\n }\n };\n\n /** Keep track of any user changes */\n const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n setLocalValue(e.target.value);\n };\n\n /** Schedule a format of the current input in the future */\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (e) => {\n clearPending();\n\n if (prefix) handlePrefixEdgeCases(e);\n\n const target = e.target as HTMLInputElement;\n\n formatTimerRef.current = setTimeout(() => {\n const cursorPosition = target.selectionStart;\n const currentValue = target.value;\n\n /** Skip formatting if we're in the middle of the input */\n if (cursorPosition !== currentValue.length) {\n return;\n }\n\n const obj = onKeyDownHandler(currentValue);\n\n setLocalValue(obj.newValue);\n target.selectionStart = obj.newCursorPosition ?? target.selectionStart;\n target.selectionEnd = obj.newCursorPosition ?? target.selectionEnd;\n }, formatDelay);\n };\n\n /** Format value onFocus if affixes exist */\n const onFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {\n const target = e.target as HTMLInputElement;\n const inputEmpty = target.value === \"\";\n\n if ((!inputEmpty && suffix) || (inputEmpty && prefix)) {\n setLocalValue(handleAffixOnFocus(target));\n }\n };\n\n // Update the stored value if data changes\n const propsValue = props.value;\n React.useEffect(() => {\n setLocalValue(formatValueWithAffix(propsValue));\n }, [propsValue]);\n\n /** clear anything pending on unmount of input */\n React.useEffect(() => clearPending, []);\n\n return {\n onBlur,\n onChange,\n onKeyDown,\n onFocus,\n value: localValue,\n };\n};\n","import React from \"react\";\nimport {\n AssetPropsWithChildren,\n Asset,\n createSlot,\n BindingTemplateInstance,\n} from \"@player-tools/dsl\";\nimport { InputAsset } from \"../types\";\nimport { Text } from \"@devtools-ui/text\";\n\nexport const Input = (\n props: Omit<AssetPropsWithChildren<InputAsset>, \"binding\"> & {\n /** The binding */\n binding: BindingTemplateInstance;\n }\n) => {\n const { children, binding, ...rest } = props;\n return (\n <Asset type=\"input\" {...rest}>\n <property name=\"binding\">{binding.toValue()}</property>\n {children}\n </Asset>\n );\n};\n\nInput.Label = createSlot({\n name: \"label\",\n TextComp: Text,\n isArray: false,\n wrapInAsset: true,\n});\n\nInput.Note = createSlot({\n name: \"note\",\n TextComp: Text,\n isArray: false,\n wrapInAsset: true,\n});\n","import type { TransformFunction } from \"@player-ui/player\";\nimport { InputAsset, TransformedInput } from \"../types\";\n\nexport const inputTransform: TransformFunction<InputAsset, TransformedInput> = (\n asset,\n options\n) => {\n return {\n ...asset,\n format(val) {\n if (asset.binding === undefined) {\n return val;\n }\n\n return options.data.format(asset.binding, val);\n },\n set(val) {\n if (asset.binding === undefined) {\n return;\n }\n\n return options.data.model.set([[asset.binding, val]], {\n formatted: true,\n });\n },\n value:\n asset.binding === undefined\n ? \"\"\n : options.data.model.get(asset.binding, {\n includeInvalid: true,\n formatted: true,\n }),\n validation:\n asset.binding === undefined\n ? undefined\n : options.validation?.get(asset.binding, { track: true }),\n dataType:\n asset.binding === undefined\n ? undefined\n : options.validation?.type(asset.binding),\n };\n};\n"],"mappings":"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","names":["React","React","React","Input"]}
1
+ {"version":3,"sources":["../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/components/InputComponent.tsx","../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/hooks/index.ts","../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/dsl/Input.tsx","../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/input/src/transform/index.ts"],"sourcesContent":["import React, { useState, useRef } from \"react\";\nimport {\n Input,\n Button,\n FormControl,\n FormLabel,\n FormHelperText,\n FormErrorMessage,\n} from \"@chakra-ui/react\";\nimport { TransformedInput } from \"../types\";\nimport { ReactAsset } from \"@player-ui/react\";\nimport { useInputAssetProps, useFileInputAssetProps } from \"../hooks\";\n\nconst FileInputComponent = (props: TransformedInput) => {\n const hiddenFileInput: React.Ref<any> = useRef(null);\n\n const [fileName, setFileName] = useState(\"\");\n\n const handleClick = () => {\n hiddenFileInput.current?.click();\n };\n\n const handleFile = (fileName: string) => {\n setFileName(fileName);\n };\n\n const { id, label } = props;\n\n const inputProps = useFileInputAssetProps({ ...props, handleFile });\n\n return (\n <FormControl>\n <Button className=\"button-file\" onClick={handleClick}>\n <FormLabel style={{ margin: 0 }}>\n {label ? <ReactAsset {...label.asset} /> : <>Select Content</>}\n </FormLabel>\n </Button>\n <Input\n id={id}\n name={id}\n {...inputProps}\n style={{ display: \"none\" }}\n ref={hiddenFileInput}\n />\n {fileName ? <p>Uploaded file: {fileName}</p> : null}\n </FormControl>\n );\n};\n\nexport const InputComponent = (props: TransformedInput) => {\n const { validation, label, id, note, size, maxLength, placeholder, file } =\n props;\n\n const inputProps = useInputAssetProps(props);\n\n return file ? (\n <FileInputComponent {...props} />\n ) : (\n <FormControl isInvalid={Boolean(validation)}>\n {label && (\n <FormLabel htmlFor={id}>\n <ReactAsset {...label.asset} />\n </FormLabel>\n )}\n <Input\n id={id}\n {...inputProps}\n size={size}\n maxLength={maxLength}\n placeholder={placeholder}\n />\n {validation && <FormErrorMessage>{validation.message}</FormErrorMessage>}\n {note && (\n <FormHelperText>\n <ReactAsset {...note.asset} />\n </FormHelperText>\n )}\n </FormControl>\n );\n};\n","import React, { useState, useEffect, useRef } from \"react\";\nimport type { TransformedInput } from \"../types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KeyDownHandler = (currentValue: string, props?: TransformedInput) => any;\n\nexport interface InputHookConfig {\n /** Time in ms to wait before formatting the user input for normal keys */\n formatDelay?: number;\n\n /** Symbol to be used for decimal point */\n decimalSymbol?: string;\n\n /** Affix to append to value - does not save to model and is only for display on input */\n prefix?: string;\n\n /** Affix to prepend to value - does not save to model and is only for display on input */\n suffix?: string;\n}\n\n/** Create a valid config mixing in defaults and user overrides */\nexport const getConfig = (\n userConfig: InputHookConfig = {}\n): Required<InputHookConfig> => {\n return {\n decimalSymbol: \".\",\n formatDelay: 200,\n prefix: \"\",\n suffix: \"\",\n ...userConfig,\n };\n};\n\n/**\n * A hook to manage an input html element as an asset.\n * The hook returns an object containing props that are expected to reside on any html input.\n * It will handle formatting, setting values, beaconing, aria-labels, etc.\n *\n * @param props - The output of the input transform\n * @param config - Local config to manage user interaction overrides\n */\nexport const useInputAssetProps = (\n props: TransformedInput,\n config?: InputHookConfig\n) => {\n const [localValue, setLocalValue] = useState(props.value ?? \"\");\n const formatTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);\n\n const { formatDelay, decimalSymbol, prefix, suffix } = getConfig(config);\n\n /** Reset and pending format timers */\n function clearPending() {\n if (formatTimerRef.current) {\n clearTimeout(formatTimerRef.current);\n formatTimerRef.current = undefined;\n }\n }\n\n /** Affix handling logic on focus */\n function handleAffixOnFocus(target: HTMLInputElement) {\n let val = target.value;\n\n if (suffix) val = val.substring(0, val.indexOf(suffix));\n\n if (prefix && !val.includes(prefix)) {\n val = `${prefix}${val}`;\n }\n\n return val;\n }\n\n /** Edge cases handling for prefix */\n function handlePrefixEdgeCases(e: React.KeyboardEvent<HTMLInputElement>) {\n const target = e.target as HTMLInputElement;\n const start = target.selectionStart;\n const end = target.selectionEnd;\n const pl = prefix.length;\n const atStart = start === pl;\n const atEnd = end === pl;\n\n if (start && end && start < pl) {\n e.preventDefault();\n target.setSelectionRange(pl, end - start + pl);\n } else if (\n (e.key === \"ArrowLeft\" && atStart) ||\n (e.key === \"Backspace\" && atStart && atEnd) ||\n e.key === \"Home\"\n ) {\n e.preventDefault();\n target.setSelectionRange(prefix.length, prefix.length);\n }\n }\n\n /** Helper to add affixes to value where appropriate */\n function formatValueWithAffix(value: string | undefined) {\n if (!value) return \"\";\n\n return `${prefix}${value}${suffix}`;\n }\n\n /** Value handling logic on key down */\n const onKeyDownHandler: KeyDownHandler = (currentValue: string) => {\n const symbolPosition = currentValue.indexOf(decimalSymbol);\n const newValue = props.format(currentValue) ?? \"\";\n const newSymbolPosition = newValue.indexOf(decimalSymbol);\n\n if (\n (symbolPosition === -1 || symbolPosition === 0) &&\n newSymbolPosition > 0\n ) {\n // formatting added dot, so set cursor before dot\n return {\n newValue: newValue.includes(prefix)\n ? `${newValue}`\n : `${prefix}${newValue}`,\n newCursorPosition: newValue.includes(prefix)\n ? newSymbolPosition\n : newSymbolPosition + prefix.length,\n };\n }\n\n return {\n newValue: newValue.includes(prefix)\n ? `${newValue}`\n : `${prefix}${newValue}`,\n };\n };\n\n /** On blur, commit the value to the model */\n const onBlur: React.FocusEventHandler<HTMLInputElement> = (e) => {\n clearPending();\n\n const formatted =\n (prefix\n ? e.target.value.replace(prefix, \"\")\n : props.format(e.target.value)) ?? \"\";\n\n if (formatted) {\n props.set(formatted);\n setLocalValue(formatValueWithAffix(formatted));\n } else {\n props.set(\"\");\n setLocalValue(\"\");\n }\n };\n\n /** Keep track of any user changes */\n const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n setLocalValue(e.target.value);\n };\n\n /** Schedule a format of the current input in the future */\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (e) => {\n clearPending();\n\n if (prefix) handlePrefixEdgeCases(e);\n\n const target = e.target as HTMLInputElement;\n\n formatTimerRef.current = setTimeout(() => {\n const cursorPosition = target.selectionStart;\n const currentValue = target.value;\n\n /** Skip formatting if we're in the middle of the input */\n if (cursorPosition !== currentValue.length) {\n return;\n }\n\n const obj = onKeyDownHandler(currentValue);\n\n setLocalValue(obj.newValue);\n target.selectionStart = obj.newCursorPosition ?? target.selectionStart;\n target.selectionEnd = obj.newCursorPosition ?? target.selectionEnd;\n }, formatDelay);\n };\n\n /** Format value onFocus if affixes exist */\n const onFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {\n const target = e.target as HTMLInputElement;\n const inputEmpty = target.value === \"\";\n\n if ((!inputEmpty && suffix) || (inputEmpty && prefix)) {\n setLocalValue(handleAffixOnFocus(target));\n }\n };\n\n // Update the stored value if data changes\n const propsValue = props.value;\n useEffect(() => {\n setLocalValue(formatValueWithAffix(propsValue));\n }, [propsValue]);\n\n /** clear anything pending on unmount of input */\n useEffect(() => clearPending, []);\n\n return {\n onBlur,\n onChange,\n onKeyDown,\n onFocus,\n value: localValue,\n };\n};\n\n/** Props for file type Input */\nexport const useFileInputAssetProps = (props: TransformedInput) => {\n const { accept } = props;\n\n const acceptedExtensions = accept\n ? accept.concat(\".json\").join(\", \")\n : \".json\";\n\n /** Parses file content for upload into a string if file type Input */\n const onFileUpload: React.ChangeEventHandler = (e): void => {\n const fileList = (<HTMLInputElement>e.target).files;\n const file = fileList ? fileList[0] : \"\";\n const reader = new FileReader();\n\n reader.addEventListener(\n \"load\",\n () => {\n // this will set the file contents in the data model\n props.set(reader.result as string);\n },\n false\n );\n\n if (file) {\n reader.readAsText(file);\n props.handleFile && props.handleFile(file.name);\n }\n };\n\n return {\n type: \"file\",\n onChange: onFileUpload,\n accept: acceptedExtensions,\n };\n};\n","import React from \"react\";\nimport {\n AssetPropsWithChildren,\n Asset,\n createSlot,\n BindingTemplateInstance,\n} from \"@player-tools/dsl\";\nimport { InputAsset } from \"../types\";\nimport { Text } from \"@devtools-ui/text\";\n\nexport const Input = (\n props: Omit<AssetPropsWithChildren<InputAsset>, \"binding\"> & {\n /** The binding */\n binding: BindingTemplateInstance;\n }\n) => {\n const { children, binding, ...rest } = props;\n return (\n <Asset type=\"input\" {...rest}>\n <property name=\"binding\">{binding.toValue()}</property>\n {children}\n </Asset>\n );\n};\n\nInput.Label = createSlot({\n name: \"label\",\n TextComp: Text,\n isArray: false,\n wrapInAsset: true,\n});\n\nInput.Note = createSlot({\n name: \"note\",\n TextComp: Text,\n isArray: false,\n wrapInAsset: true,\n});\n","import type { TransformFunction } from \"@player-ui/player\";\nimport { InputAsset, TransformedInput } from \"../types\";\n\nexport const inputTransform: TransformFunction<InputAsset, TransformedInput> = (\n asset,\n options\n) => {\n return {\n ...asset,\n format(val) {\n if (asset.binding === undefined) {\n return val;\n }\n\n return options.data.format(asset.binding, val);\n },\n set(val) {\n if (asset.binding === undefined) {\n return;\n }\n\n return options.data.model.set([[asset.binding, val]], {\n formatted: true,\n });\n },\n value:\n asset.binding === undefined\n ? \"\"\n : options.data.model.get(asset.binding, {\n includeInvalid: true,\n formatted: true,\n }),\n validation:\n asset.binding === undefined\n ? undefined\n : options.validation?.get(asset.binding, { track: true }),\n dataType:\n asset.binding === undefined\n ? undefined\n : options.validation?.type(asset.binding),\n };\n};\n"],"mappings":"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","names":["React","useState","useRef","useRef","useState","fileName","React","React","Input"]}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@devtools-ui/input",
3
- "version": "0.2.0--canary.25.1169",
3
+ "version": "0.2.0-next.1",
4
4
  "main": "dist/cjs/index.cjs",
5
5
  "dependencies": {
6
- "@devtools-ui/text": "0.2.0--canary.25.1169",
6
+ "@devtools-ui/text": "0.2.0-next.1",
7
7
  "@chakra-ui/react": "^2.8.2",
8
8
  "@emotion/react": "^11.11.4",
9
9
  "@emotion/styled": "^11.11.0",
@@ -1,6 +1,7 @@
1
- import React from "react";
1
+ import React, { useState, useRef } from "react";
2
2
  import {
3
3
  Input,
4
+ Button,
4
5
  FormControl,
5
6
  FormLabel,
6
7
  FormHelperText,
@@ -8,13 +9,53 @@ import {
8
9
  } from "@chakra-ui/react";
9
10
  import { TransformedInput } from "../types";
10
11
  import { ReactAsset } from "@player-ui/react";
11
- import { useInputAssetProps } from "./hooks";
12
+ import { useInputAssetProps, useFileInputAssetProps } from "../hooks";
13
+
14
+ const FileInputComponent = (props: TransformedInput) => {
15
+ const hiddenFileInput: React.Ref<any> = useRef(null);
16
+
17
+ const [fileName, setFileName] = useState("");
18
+
19
+ const handleClick = () => {
20
+ hiddenFileInput.current?.click();
21
+ };
22
+
23
+ const handleFile = (fileName: string) => {
24
+ setFileName(fileName);
25
+ };
26
+
27
+ const { id, label } = props;
28
+
29
+ const inputProps = useFileInputAssetProps({ ...props, handleFile });
30
+
31
+ return (
32
+ <FormControl>
33
+ <Button className="button-file" onClick={handleClick}>
34
+ <FormLabel style={{ margin: 0 }}>
35
+ {label ? <ReactAsset {...label.asset} /> : <>Select Content</>}
36
+ </FormLabel>
37
+ </Button>
38
+ <Input
39
+ id={id}
40
+ name={id}
41
+ {...inputProps}
42
+ style={{ display: "none" }}
43
+ ref={hiddenFileInput}
44
+ />
45
+ {fileName ? <p>Uploaded file: {fileName}</p> : null}
46
+ </FormControl>
47
+ );
48
+ };
12
49
 
13
50
  export const InputComponent = (props: TransformedInput) => {
14
- const { validation, label, id, note, size, maxLength, placeholder } = props;
51
+ const { validation, label, id, note, size, maxLength, placeholder, file } =
52
+ props;
53
+
15
54
  const inputProps = useInputAssetProps(props);
16
55
 
17
- return (
56
+ return file ? (
57
+ <FileInputComponent {...props} />
58
+ ) : (
18
59
  <FormControl isInvalid={Boolean(validation)}>
19
60
  {label && (
20
61
  <FormLabel htmlFor={id}>
@@ -0,0 +1,57 @@
1
+ import React from "react";
2
+ import { render, fireEvent } from "@testing-library/react";
3
+ import { describe, expect, test } from "vitest";
4
+ import { InputComponent } from "../index";
5
+ import { TransformedInput } from "../../types";
6
+
7
+ describe("InputComponent test", () => {
8
+ const inputAssetPropsMock: TransformedInput = {
9
+ id: "default-input",
10
+ type: "input",
11
+ set: () => {},
12
+ format: (value) => value,
13
+ value: "test",
14
+ binding: "some.binding",
15
+ };
16
+
17
+ const inputFileAssetPropsMock: TransformedInput = {
18
+ ...inputAssetPropsMock,
19
+ id: "file-input",
20
+ file: true,
21
+ accept: [".txt"],
22
+ };
23
+
24
+ test("Renders default Input asset", () => {
25
+ const inputElement = render(<InputComponent {...inputAssetPropsMock} />);
26
+
27
+ const input = inputElement.container.querySelector(
28
+ "input"
29
+ ) as HTMLInputElement;
30
+
31
+ fireEvent.change(input, { target: { value: "Test 2" } });
32
+
33
+ fireEvent.blur(input);
34
+
35
+ expect(input.value).toBe("Test 2");
36
+ });
37
+
38
+ test("Renders file type Input asset", () => {
39
+ const inputElement = render(
40
+ <InputComponent {...inputFileAssetPropsMock} />
41
+ );
42
+
43
+ const fileUploader = inputElement.container.querySelector(
44
+ "input"
45
+ ) as HTMLInputElement;
46
+
47
+ const file = new File(['{"some":"content"}'], "content.json", {
48
+ type: "json",
49
+ });
50
+
51
+ fireEvent.change(fileUploader, { target: { files: [file] } });
52
+
53
+ expect(inputElement.container.querySelector("p")?.textContent).toBe(
54
+ "Uploaded file: content.json"
55
+ );
56
+ });
57
+ });
@@ -62,4 +62,40 @@ describe("DSL: Input", () => {
62
62
  binding: "binding",
63
63
  });
64
64
  });
65
+
66
+ test("It should render a file uploader version of Input asset", async () => {
67
+ const rendered = await render(
68
+ <Input binding={b`binding`} file={true}>
69
+ <Input.Label>Label</Input.Label>
70
+ </Input>
71
+ );
72
+
73
+ expect(rendered.jsonValue).toStrictEqual({
74
+ id: "root",
75
+ type: "input",
76
+ file: true,
77
+ label: {
78
+ asset: {
79
+ id: "label",
80
+ type: "text",
81
+ value: "Label",
82
+ },
83
+ },
84
+ binding: "binding",
85
+ });
86
+ });
87
+
88
+ test("It should render a file uploader Input asset with accepted file extensions", async () => {
89
+ const rendered = await render(
90
+ <Input binding={b`binding`} file={true} accept={[".tsx", ".jsx"]} />
91
+ );
92
+
93
+ expect(rendered.jsonValue).toStrictEqual({
94
+ id: "root",
95
+ type: "input",
96
+ file: true,
97
+ accept: [".tsx", ".jsx"],
98
+ binding: "binding",
99
+ });
100
+ });
65
101
  });
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useState, useEffect, useRef } from "react";
2
2
  import type { TransformedInput } from "../types";
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -43,8 +43,8 @@ export const useInputAssetProps = (
43
43
  props: TransformedInput,
44
44
  config?: InputHookConfig
45
45
  ) => {
46
- const [localValue, setLocalValue] = React.useState(props.value ?? "");
47
- const formatTimerRef = React.useRef<NodeJS.Timeout | undefined>(undefined);
46
+ const [localValue, setLocalValue] = useState(props.value ?? "");
47
+ const formatTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);
48
48
 
49
49
  const { formatDelay, decimalSymbol, prefix, suffix } = getConfig(config);
50
50
 
@@ -186,12 +186,12 @@ export const useInputAssetProps = (
186
186
 
187
187
  // Update the stored value if data changes
188
188
  const propsValue = props.value;
189
- React.useEffect(() => {
189
+ useEffect(() => {
190
190
  setLocalValue(formatValueWithAffix(propsValue));
191
191
  }, [propsValue]);
192
192
 
193
193
  /** clear anything pending on unmount of input */
194
- React.useEffect(() => clearPending, []);
194
+ useEffect(() => clearPending, []);
195
195
 
196
196
  return {
197
197
  onBlur,
@@ -201,3 +201,39 @@ export const useInputAssetProps = (
201
201
  value: localValue,
202
202
  };
203
203
  };
204
+
205
+ /** Props for file type Input */
206
+ export const useFileInputAssetProps = (props: TransformedInput) => {
207
+ const { accept } = props;
208
+
209
+ const acceptedExtensions = accept
210
+ ? accept.concat(".json").join(", ")
211
+ : ".json";
212
+
213
+ /** Parses file content for upload into a string if file type Input */
214
+ const onFileUpload: React.ChangeEventHandler = (e): void => {
215
+ const fileList = (<HTMLInputElement>e.target).files;
216
+ const file = fileList ? fileList[0] : "";
217
+ const reader = new FileReader();
218
+
219
+ reader.addEventListener(
220
+ "load",
221
+ () => {
222
+ // this will set the file contents in the data model
223
+ props.set(reader.result as string);
224
+ },
225
+ false
226
+ );
227
+
228
+ if (file) {
229
+ reader.readAsText(file);
230
+ props.handleFile && props.handleFile(file.name);
231
+ }
232
+ };
233
+
234
+ return {
235
+ type: "file",
236
+ onChange: onFileUpload,
237
+ accept: acceptedExtensions,
238
+ };
239
+ };
@@ -24,6 +24,12 @@ export interface InputAsset extends Asset<"input"> {
24
24
 
25
25
  /** Max character length in the Input */
26
26
  maxLength?: number;
27
+
28
+ /** For file uploader Input */
29
+ file?: boolean;
30
+
31
+ /** File extensions to be accepted by the file uploader Input, .json supported by default */
32
+ accept?: string[];
27
33
  }
28
34
 
29
35
  export interface TransformedInput extends InputAsset {
@@ -41,4 +47,7 @@ export interface TransformedInput extends InputAsset {
41
47
 
42
48
  /** The dataType defined from the schema */
43
49
  dataType?: Schema.DataType;
50
+
51
+ /** Handler for persisting file name for file type input */
52
+ handleFile?: (name: string) => void;
44
53
  }
@@ -27,4 +27,10 @@ export declare const useInputAssetProps: (props: TransformedInput, config?: Inpu
27
27
  onFocus: React.FocusEventHandler<HTMLInputElement>;
28
28
  value: string;
29
29
  };
30
- //# sourceMappingURL=hooks.d.ts.map
30
+ /** Props for file type Input */
31
+ export declare const useFileInputAssetProps: (props: TransformedInput) => {
32
+ type: string;
33
+ onChange: React.ChangeEventHandler<Element>;
34
+ accept: string;
35
+ };
36
+ //# sourceMappingURL=index.d.ts.map
@@ -16,6 +16,10 @@ export interface InputAsset extends Asset<"input"> {
16
16
  placeholder?: string;
17
17
  /** Max character length in the Input */
18
18
  maxLength?: number;
19
+ /** For file uploader Input */
20
+ file?: boolean;
21
+ /** File extensions to be accepted by the file uploader Input, .json supported by default */
22
+ accept?: string[];
19
23
  }
20
24
  export interface TransformedInput extends InputAsset {
21
25
  /** A function to commit the new value to the data-model */
@@ -28,6 +32,8 @@ export interface TransformedInput extends InputAsset {
28
32
  validation?: ValidationResponse;
29
33
  /** The dataType defined from the schema */
30
34
  dataType?: Schema.DataType;
35
+ /** Handler for persisting file name for file type input */
36
+ handleFile?: (name: string) => void;
31
37
  }
32
38
  export {};
33
39
  //# sourceMappingURL=index.d.ts.map