Skip to content

Commit

Permalink
Merge pull request #22 from farooqkz/input
Browse files Browse the repository at this point in the history
TextInput won't let Arrow Left and Right keys propagate outside when focused
  • Loading branch information
farooqkz authored Jun 28, 2024
2 parents f510c6c + 5ca2a5e commit 42e54b0
Show file tree
Hide file tree
Showing 8 changed files with 1,190 additions and 930 deletions.
4 changes: 2 additions & 2 deletions KaiUIngInferno/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
},
"devDependencies": {
"@babel/core": "^7.21.0",
"@parcel/packager-ts": "2.8.3",
"@parcel/packager-ts": "2.9.3",
"@parcel/transformer-babel": "^2.8.3",
"@parcel/transformer-sass": "^2.8.3",
"@parcel/transformer-typescript-tsc": "^2.8.3",
"@parcel/transformer-typescript-types": "2.8.3",
"@parcel/transformer-typescript-types": "2.9.3",
"babel-plugin-inferno": "^6.6.0",
"classnames": "^2.3.2",
"inferno": "^8.2.2",
Expand Down
4 changes: 3 additions & 1 deletion KaiUIngInferno/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ export { default as TextInput } from "./ui/TextInput";
export { default as Separator } from "./ui/Separator";
export { default as Button } from "./ui/Button";


export { default as Avatar } from "./ui/Avatar";
export { default as DropDownMenu } from "./DropDownMenu";


export { default as ListView } from "./views/ListView";
export { default as ListViewKeyed } from "./views/ListViewKeyed";
export { default as ListViewNonKeyed } from "./views/ListViewNonKeyed";
export { default as TabView } from "./views/TabView";

export { asArray } from "./utils";
export { default as toast } from "./toast";
export { default as toast } from "./toast";
20 changes: 20 additions & 0 deletions KaiUIngInferno/src/ui/OptionItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
interface OptionItemProps {
text: string;
isFocused?: boolean;
}

export default function OptionItem({ text, isFocused }: OptionItemProps) {
return (
<div
tabIndex={0}
ref={(ref: HTMLElement | null) => {
if (ref) {
isFocused ? ref.focus() : ref.blur();
}
}}
className="kai-om-item"
$HasTextChildren
>
{text}
</div>);
}
105 changes: 105 additions & 0 deletions KaiUIngInferno/src/ui/OptionMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Component } from "inferno";
import TextInput from "./TextInput";
import "KaiUI/src/components/OptionMenu/OptionMenu.scss";
import { asArray } from "../utils";

interface OptionMenuProps {
header: string;
children: any;
onChangeIndex?: (index: number) => void;
isActive: boolean;
onExit: () => void;
enableSearch?: boolean;
}

interface OptionMenuState {
selectedItem: number;
searchTerm: string;
}

export default class OptionMenu extends Component<OptionMenuProps, OptionMenuState> {
public state: OptionMenuState;

handleKeyDown = (evt: KeyboardEvent) => {
if (!this.props.isActive) {
return;
}
const childrenArray: any[] = asArray(this.props.children);
const childrenLength = childrenArray.length;
evt.stopPropagation();
let index = this.state.selectedItem;
switch (evt.key) {
case "Backspace":
index !== 0 && this.props.onExit();
break;
case "ArrowDown":
index--;
break;
case "ArrowUp":
index++;
break;
default:
break;
}
index = (index + childrenLength) % childrenLength;
this.setState({ selectedItem: index });
}

constructor(props: any) {
super(props);
this.state = {
selectedItem: 0,
searchTerm: ""
}
}

componentDidMount() {
document.addEventListener("keydown", this.handleKeyDown);
}

componentWillUnmount() {
document.removeEventListener("keydown", this.handleKeyDown);
}

componentDidUpdate(lastProps: OptionMenuProps, lastState: OptionMenuState) {
lastProps.onChangeIndex && lastProps.onChangeIndex(lastState.selectedItem);
}

render() {
const { searchTerm, selectedItem } = this.state;
let childrenToRender = this.props.children;
if (this.props.enableSearch) {
childrenToRender.unshift(
<TextInput
id="optMenuSearch"
defaultValue={searchTerm}
placeholder="Search"
onChange={(text: string) => this.setState({ searchTerm: text })}
label=""
fieldType="text"
/>
);
}

childrenToRender = childrenToRender.filter((child: any) => {
if (child.props.fieldType === "text") {
return true;
}
if (child.props.text && child.props.text.indexOf(searchTerm) >= 0) {
return true;
}
return false;
});

childrenToRender[selectedItem].props.isFocused = true;

return (
<div className="kai-om">
<header $HasTextChildren>{this.props.header}</header>
<nav $HasKeyedChildren>
{childrenToRender}
</nav>
</div>
);
}
};
2 changes: 1 addition & 1 deletion KaiUIngInferno/src/ui/SoftKey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface ButtonProps {

const prefixCls = "kai-softkey";
function Button(props: ButtonProps) {
let renderedIcon: JSX.Element;
let renderedIcon: Component;
if (props.icon && props.icon.toString().indexOf("kai-") === -1) {
renderedIcon = <img src={props.icon} width={20} height={20} alt="" />;
} else {
Expand Down
48 changes: 34 additions & 14 deletions KaiUIngInferno/src/ui/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component } from "inferno";
import { Component, RefObject, createRef } from "inferno";
import classnames from "classnames";
import "KaiUI/src/components/TextInput/TextInput.scss";
import morecolor from "../morecolor";
Expand All @@ -7,7 +7,7 @@ const prefixCls = "kai-text-input";
const labelCls = `${prefixCls}-label p-thi`;
const inputCls = `${prefixCls}-label p-pri`;

interface TextInputProps {
interface Props {
onChange?: (text: string) => void;
isFocused?: boolean;
fieldType: string;
Expand All @@ -18,26 +18,49 @@ interface TextInputProps {
focusClass?: string;
}

class TextInput extends Component<TextInputProps> {
interface State {
value: string;
}

class TextInput extends Component<Props, State> {
private onChange: (_evt?: Event) => void;
private textInput: any;
private textInputRef: RefObject<HTMLInputElement>;
public state: { value: string };

constructor(props: TextInputProps) {
onKeyDown = (evt: KeyboardEvent) => {
if (!this.props.isFocused) return; // do we need this? --Farooq
if (evt.key === "ArrowLeft" || evt.key === "ArrowRight") {
evt.stopImmediatePropagation();
}
};

constructor(props: any) {
const { defaultValue } = props;
super(props);
this.textInputRef = createRef();
this.onChange = (_evt?: Event) => {
this.setState({ value: this.textInput.value });
if (this.props.onChange) this.props.onChange(this.textInput.value);
if (!this.textInputRef.current) return;
this.setState({ value: this.textInputRef.current.value });
if (this.props.onChange) this.props.onChange(this.textInputRef.current.value);
};

this.state = {
value: defaultValue || "",
};
}



componentDidMount() {
this.textInputRef.current?.addEventListener("keydown", this.onKeyDown, true)
}

componentWillUnmount() {
this.textInputRef.current?.removeEventListener("keydown", this.onKeyDown, true)
}

componentDidUpdate() {
if (this.props.isFocused) this.textInput.focus();
if (this.props.isFocused) this.textInputRef.current?.focus();
}

render() {
Expand All @@ -51,9 +74,8 @@ class TextInput extends Component<TextInputProps> {
id={this.props.id}
tabIndex={0}
className={itemCls}
style={`background-color: ${
this.props.isFocused ? morecolor.focusColor : ""
}`}
style={`background-color: ${this.props.isFocused ? morecolor.focusColor : ""
}`}
>
<label className={labelCls} $HasTextChildren>
{this.props.label}
Expand All @@ -70,9 +92,7 @@ class TextInput extends Component<TextInputProps> {
defaultValue={this.state.value || ""}
placeholder={this.props.placeholder || ""}
style={`color: ${this.props.isFocused ? "var(--text-color)" : ""}`}
ref={(input) => {
this.textInput = input;
}}
ref={this.textInputRef}
/>
</div>
);
Expand Down
4 changes: 1 addition & 3 deletions KaiUIngInferno/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { VNode } from "inferno";

function asArray(children: VNode | VNode[]) : VNode[] {
function asArray(children: any | any[]) : any[] {
if (children instanceof Array) {
return children;
} else {
Expand Down
Loading

0 comments on commit 42e54b0

Please sign in to comment.