From 213668cbbe4de791eb3fe689082e031e07794a10 Mon Sep 17 00:00:00 2001 From: Patrick Stapfer Date: Wed, 30 Dec 2020 18:59:21 +0100 Subject: [PATCH] Use common SearchBox --- src/Packages.js | 99 +------------- src/Packages.res | 99 -------------- {bindings => src/bindings}/GithubSlugger.js | 0 {bindings => src/bindings}/GithubSlugger.res | 0 src/components/SearchBox.js | 112 +++++++++++++++ src/components/SearchBox.res | 101 ++++++++++++++ .../components}/SyntaxLookupWidget.js | 127 +++--------------- .../components}/SyntaxLookupWidget.res | 102 +------------- .../components}/SyntaxLookupWidget.resi | 0 9 files changed, 233 insertions(+), 407 deletions(-) rename {bindings => src/bindings}/GithubSlugger.js (100%) rename {bindings => src/bindings}/GithubSlugger.res (100%) create mode 100644 src/components/SearchBox.js create mode 100644 src/components/SearchBox.res rename {components => src/components}/SyntaxLookupWidget.js (74%) rename {components => src/components}/SyntaxLookupWidget.res (74%) rename {components => src/components}/SyntaxLookupWidget.resi (100%) diff --git a/src/Packages.js b/src/Packages.js index 38709ae7d..736c3cc99 100644 --- a/src/Packages.js +++ b/src/Packages.js @@ -14,6 +14,7 @@ import * as Js_null from "bs-platform/lib/es6/js_null.js"; import FuseJs from "fuse.js"; import * as Process from "process"; import * as Markdown from "./components/Markdown.js"; +import * as SearchBox from "./components/SearchBox.js"; import * as Belt_Array from "bs-platform/lib/es6/belt_Array.js"; import * as Navigation from "./components/Navigation.js"; import * as Belt_Option from "bs-platform/lib/es6/belt_Option.js"; @@ -124,102 +125,6 @@ function applySearch(resources, pattern) { return Belt_Array.concat(filteredNpm, filteredUrls); } -function Packages$SearchBox(Props) { - var completionValuesOpt = Props.completionValues; - var value = Props.value; - var onClear = Props.onClear; - var placeholderOpt = Props.placeholder; - var onValueChange = Props.onValueChange; - var completionValues = completionValuesOpt !== undefined ? completionValuesOpt : []; - var placeholder = placeholderOpt !== undefined ? placeholderOpt : ""; - var match = React.useState(function () { - return /* Inactive */1; - }); - var setState = match[1]; - var state = match[0]; - var textInput = React.useRef(null); - var onMouseDownClear = function (evt) { - evt.preventDefault(); - return Curry._1(onClear, undefined); - }; - var onAreaFocus = function (evt) { - var el = evt.target; - var isDiv = (el.type == null); - if (isDiv && state === /* Inactive */1) { - return Belt_Option.forEach(Caml_option.nullable_to_opt(textInput.current), (function (el) { - el.focus(); - - })); - } - - }; - var onFocus = function (param) { - return Curry._1(setState, (function (param) { - return /* Active */0; - })); - }; - var onBlur = function (param) { - return Curry._1(setState, (function (param) { - return /* Inactive */1; - })); - }; - var onKeyDown = function (evt) { - var key = evt.key; - var ctrlKey = evt.ctrlKey; - var full = ( - ctrlKey ? "CTRL+" : "" - ) + key; - switch (full) { - case "Escape" : - return Curry._1(onClear, undefined); - case "Tab" : - if (completionValues.length !== 1) { - return ; - } - var targetValue = Belt_Array.getExn(completionValues, 0); - if (targetValue !== value) { - evt.preventDefault(); - return Curry._1(onValueChange, targetValue); - } else { - return ; - } - default: - return ; - } - }; - var onChange = function (evt) { - evt.preventDefault(); - return Curry._1(onValueChange, evt.target.value); - }; - return React.createElement("div", { - className: ( - state === /* Active */0 ? "border-fire" : "border-fire-40" - ) + " flex items-center border rounded-lg py-4 px-5", - tabIndex: -1, - onFocus: onAreaFocus, - onBlur: onBlur - }, React.createElement(Icon.MagnifierGlass.make, { - className: ( - state === /* Active */0 ? "text-fire" : "text-fire-80" - ) + " w-4 h-4" - }), React.createElement("input", { - ref: textInput, - className: "text-16 outline-none ml-4 w-full", - placeholder: placeholder, - type: "text", - value: value, - onKeyDown: onKeyDown, - onFocus: onFocus, - onChange: onChange - }), React.createElement("button", { - className: value === "" ? "hidden" : "block", - onFocus: onFocus, - onMouseDown: onMouseDownClear - }, React.createElement(Icon.Close.make, { - className: "w-4 h-4 text-fire" - }))); -} - function Packages$Card(Props) { var value = Props.value; var onKeywordSelect = Props.onKeywordSelect; @@ -580,7 +485,7 @@ function $$default(props) { } }, React.createElement(Markdown.H1.make, { children: "Libraries & Bindings" - }), React.createElement(Packages$SearchBox, { + }), React.createElement(SearchBox.make, { value: searchValue, onClear: onClear, placeholder: "Enter a search term, name, keyword, etc", diff --git a/src/Packages.res b/src/Packages.res index 84a1288df..22102751f 100644 --- a/src/Packages.res +++ b/src/Packages.res @@ -123,105 +123,6 @@ module Resource = { } } -module SearchBox = { - @bs.send external focus: Dom.element => unit = "focus" - - type state = - | Active - | Inactive - - @react.component - let make = ( - ~completionValues: array=[], // set of possible values - ~value: string, - ~onClear: unit => unit, - ~placeholder: string="", - ~onValueChange: string => unit, - ) => { - let (state, setState) = React.useState(_ => Inactive) - let textInput = React.useRef(Js.Nullable.null) - - let onMouseDownClear = evt => { - ReactEvent.Mouse.preventDefault(evt) - onClear() - } - - let focusInput = () => - textInput.current->Js.Nullable.toOption->Belt.Option.forEach(el => el->focus) - - let onAreaFocus = evt => { - let el = ReactEvent.Focus.target(evt) - let isDiv = Js.Null_undefined.isNullable(el["type"]) - - if isDiv && state === Inactive { - focusInput() - } - } - - let onFocus = _ => { - setState(_ => Active) - } - - let onBlur = _ => { - setState(_ => Inactive) - } - - let onKeyDown = evt => { - let key = ReactEvent.Keyboard.key(evt) - let ctrlKey = ReactEvent.Keyboard.ctrlKey(evt) - - let full = (ctrlKey ? "CTRL+" : "") ++ key - - switch full { - | "Escape" => onClear() - | "Tab" => - if Js.Array.length(completionValues) === 1 { - let targetValue = Belt.Array.getExn(completionValues, 0) - - if targetValue !== value { - ReactEvent.Keyboard.preventDefault(evt) - onValueChange(targetValue) - } else { - () - } - } - | _ => () - } - } - - let onChange = evt => { - ReactEvent.Form.preventDefault(evt) - let value = ReactEvent.Form.target(evt)["value"] - onValueChange(value) - } - -
- - - -
- } -} - module Card = { @react.component let make = (~value: Resource.t, ~onKeywordSelect: option unit>=?) => { diff --git a/bindings/GithubSlugger.js b/src/bindings/GithubSlugger.js similarity index 100% rename from bindings/GithubSlugger.js rename to src/bindings/GithubSlugger.js diff --git a/bindings/GithubSlugger.res b/src/bindings/GithubSlugger.res similarity index 100% rename from bindings/GithubSlugger.res rename to src/bindings/GithubSlugger.res diff --git a/src/components/SearchBox.js b/src/components/SearchBox.js new file mode 100644 index 000000000..1a82b11fd --- /dev/null +++ b/src/components/SearchBox.js @@ -0,0 +1,112 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Icon from "./Icon.js"; +import * as Curry from "bs-platform/lib/es6/curry.js"; +import * as React from "react"; +import * as Belt_Array from "bs-platform/lib/es6/belt_Array.js"; +import * as Belt_Option from "bs-platform/lib/es6/belt_Option.js"; +import * as Caml_option from "bs-platform/lib/es6/caml_option.js"; + +function SearchBox(Props) { + var completionValuesOpt = Props.completionValues; + var value = Props.value; + var onClear = Props.onClear; + var placeholderOpt = Props.placeholder; + var onValueChange = Props.onValueChange; + var completionValues = completionValuesOpt !== undefined ? completionValuesOpt : []; + var placeholder = placeholderOpt !== undefined ? placeholderOpt : ""; + var match = React.useState(function () { + return /* Inactive */1; + }); + var setState = match[1]; + var state = match[0]; + var textInput = React.useRef(null); + var onMouseDownClear = function (evt) { + evt.preventDefault(); + return Curry._1(onClear, undefined); + }; + var onAreaFocus = function (evt) { + var el = evt.target; + var isDiv = (el.type == null); + if (isDiv && state === /* Inactive */1) { + return Belt_Option.forEach(Caml_option.nullable_to_opt(textInput.current), (function (el) { + el.focus(); + + })); + } + + }; + var onFocus = function (param) { + return Curry._1(setState, (function (param) { + return /* Active */0; + })); + }; + var onBlur = function (param) { + return Curry._1(setState, (function (param) { + return /* Inactive */1; + })); + }; + var onKeyDown = function (evt) { + var key = evt.key; + var ctrlKey = evt.ctrlKey; + var full = ( + ctrlKey ? "CTRL+" : "" + ) + key; + switch (full) { + case "Escape" : + return Curry._1(onClear, undefined); + case "Tab" : + if (completionValues.length !== 1) { + return ; + } + var targetValue = Belt_Array.getExn(completionValues, 0); + if (targetValue !== value) { + evt.preventDefault(); + return Curry._1(onValueChange, targetValue); + } else { + return ; + } + default: + return ; + } + }; + var onChange = function (evt) { + evt.preventDefault(); + return Curry._1(onValueChange, evt.target.value); + }; + return React.createElement("div", { + className: ( + state === /* Active */0 ? "border-fire" : "border-fire-40" + ) + " flex items-center border rounded-lg py-4 px-5", + tabIndex: -1, + onFocus: onAreaFocus, + onBlur: onBlur + }, React.createElement(Icon.MagnifierGlass.make, { + className: ( + state === /* Active */0 ? "text-fire" : "text-fire-80" + ) + " w-4 h-4" + }), React.createElement("input", { + ref: textInput, + className: "text-16 outline-none ml-4 w-full", + placeholder: placeholder, + type: "text", + value: value, + onKeyDown: onKeyDown, + onFocus: onFocus, + onChange: onChange + }), React.createElement("button", { + className: value === "" ? "hidden" : "block", + onFocus: onFocus, + onMouseDown: onMouseDownClear + }, React.createElement(Icon.Close.make, { + className: "w-4 h-4 text-fire" + }))); +} + +var make = SearchBox; + +export { + make , + +} +/* Icon Not a pure module */ diff --git a/src/components/SearchBox.res b/src/components/SearchBox.res new file mode 100644 index 000000000..8cd14de7e --- /dev/null +++ b/src/components/SearchBox.res @@ -0,0 +1,101 @@ +/* +* This SearchBox is used for fuzzy-find search scenarios, such as the syntax widget tool or +* the package index +*/ + +@bs.send external focus: Dom.element => unit = "focus" + +type state = + | Active + | Inactive + +@react.component +let make = ( + ~completionValues: array=[], // set of possible values + ~value: string, + ~onClear: unit => unit, + ~placeholder: string="", + ~onValueChange: string => unit, +) => { + let (state, setState) = React.useState(_ => Inactive) + let textInput = React.useRef(Js.Nullable.null) + + let onMouseDownClear = evt => { + ReactEvent.Mouse.preventDefault(evt) + onClear() + } + + let focusInput = () => + textInput.current->Js.Nullable.toOption->Belt.Option.forEach(el => el->focus) + + let onAreaFocus = evt => { + let el = ReactEvent.Focus.target(evt) + let isDiv = Js.Null_undefined.isNullable(el["type"]) + + if isDiv && state === Inactive { + focusInput() + } + } + + let onFocus = _ => { + setState(_ => Active) + } + + let onBlur = _ => { + setState(_ => Inactive) + } + + let onKeyDown = evt => { + let key = ReactEvent.Keyboard.key(evt) + let ctrlKey = ReactEvent.Keyboard.ctrlKey(evt) + + let full = (ctrlKey ? "CTRL+" : "") ++ key + + switch full { + | "Escape" => onClear() + | "Tab" => + if Js.Array.length(completionValues) === 1 { + let targetValue = Belt.Array.getExn(completionValues, 0) + + if targetValue !== value { + ReactEvent.Keyboard.preventDefault(evt) + onValueChange(targetValue) + } else { + () + } + } + | _ => () + } + } + + let onChange = evt => { + ReactEvent.Form.preventDefault(evt) + let value = ReactEvent.Form.target(evt)["value"] + onValueChange(value) + } + +
+ + + +
+} diff --git a/components/SyntaxLookupWidget.js b/src/components/SyntaxLookupWidget.js similarity index 74% rename from components/SyntaxLookupWidget.js rename to src/components/SyntaxLookupWidget.js index cf0a5a2a2..fa133291b 100644 --- a/components/SyntaxLookupWidget.js +++ b/src/components/SyntaxLookupWidget.js @@ -1,15 +1,15 @@ // Generated by ReScript, PLEASE EDIT WITH CARE -import * as Icon from "./Icon.js"; +import * as Next from "../bindings/Next.js"; import * as Curry from "bs-platform/lib/es6/curry.js"; import * as React from "react"; import * as Js_dict from "bs-platform/lib/es6/js_dict.js"; import FuseJs from "fuse.js"; import * as Markdown from "./Markdown.js"; +import * as SearchBox from "./SearchBox.js"; import * as Belt_Array from "bs-platform/lib/es6/belt_Array.js"; import * as Belt_Option from "bs-platform/lib/es6/belt_Option.js"; import * as Caml_option from "bs-platform/lib/es6/caml_option.js"; -import * as Router from "next/router"; import * as GithubSlugger from "github-slugger"; import Decorator_asMdx from "misc_docs/syntax/decorator_as.mdx"; import Decorator_moduleMdx from "misc_docs/syntax/decorator_module.mdx"; @@ -100,100 +100,6 @@ function getAnchor(path) { } } -function SyntaxLookupWidget$SearchBox(Props) { - var completionValuesOpt = Props.completionValues; - var value = Props.value; - var onClear = Props.onClear; - var onValueChange = Props.onValueChange; - var completionValues = completionValuesOpt !== undefined ? completionValuesOpt : []; - var match = React.useState(function () { - return /* Inactive */1; - }); - var setState = match[1]; - var state = match[0]; - var textInput = React.useRef(null); - var onMouseDownClear = function (evt) { - evt.preventDefault(); - return Curry._1(onClear, undefined); - }; - var onAreaFocus = function (evt) { - var el = evt.target; - var isDiv = (el.type == null); - if (isDiv && state === /* Inactive */1) { - return Belt_Option.forEach(Caml_option.nullable_to_opt(textInput.current), (function (el) { - el.focus(); - - })); - } - - }; - var onFocus = function (param) { - return Curry._1(setState, (function (param) { - return /* Active */0; - })); - }; - var onBlur = function (param) { - return Curry._1(setState, (function (param) { - return /* Inactive */1; - })); - }; - var onKeyDown = function (evt) { - var key = evt.key; - var ctrlKey = evt.ctrlKey; - var full = ( - ctrlKey ? "CTRL+" : "" - ) + key; - switch (full) { - case "Escape" : - return Curry._1(onClear, undefined); - case "Tab" : - if (completionValues.length !== 1) { - return ; - } - var targetValue = Belt_Array.getExn(completionValues, 0); - if (targetValue !== value) { - evt.preventDefault(); - return Curry._1(onValueChange, targetValue); - } else { - return ; - } - default: - return ; - } - }; - var onChange = function (evt) { - evt.preventDefault(); - return Curry._1(onValueChange, evt.target.value); - }; - return React.createElement("div", { - className: ( - state === /* Active */0 ? "border-fire" : "border-fire-40" - ) + " flex items-center border rounded-lg py-4 px-5", - tabIndex: -1, - onFocus: onAreaFocus, - onBlur: onBlur - }, React.createElement(Icon.MagnifierGlass.make, { - className: ( - state === /* Active */0 ? "text-fire" : "text-fire-80" - ) + " w-4 h-4" - }), React.createElement("input", { - ref: textInput, - className: "text-16 outline-none ml-4 w-full", - placeholder: "Enter keywords or syntax...", - type: "text", - value: value, - onKeyDown: onKeyDown, - onFocus: onFocus, - onChange: onChange - }), React.createElement("button", { - className: value === "" ? "hidden" : "block", - onFocus: onFocus, - onMouseDown: onMouseDownClear - }, React.createElement(Icon.Close.make, { - className: "w-4 h-4 text-fire" - }))); -} - function SyntaxLookupWidget$Tag(Props) { var text = Props.text; return React.createElement("span", { @@ -235,7 +141,7 @@ function SyntaxLookupWidget$DetailBox(Props) { } function SyntaxLookupWidget(Props) { - var router = Router.useRouter(); + var router = Next.Router.useRouter(undefined); var match = React.useState(function () { return /* ShowAll */0; }); @@ -261,23 +167,23 @@ function SyntaxLookupWidget(Props) { React.useEffect((function () { var match = getAnchor(router.asPath); var exit = 0; - if (typeof state === "number" || !state.TAG) { + if (typeof state === "number" || state.TAG === /* ShowFiltered */0) { exit = 1; } else { var item = state._0; if (match !== undefined) { var slug = GithubSlugger.slug(item.name); if (slug !== match) { - router.replace("syntax-lookup#" + match); + Next.Router.replace(router, "syntax-lookup#" + match); } } else { - router.replace("syntax-lookup#" + GithubSlugger.slug(item.name)); + Next.Router.replace(router, "syntax-lookup#" + GithubSlugger.slug(item.name)); } } if (exit === 1) { if (match !== undefined) { - router.replace("syntax-lookup"); + Next.Router.replace(router, "syntax-lookup"); } } @@ -317,7 +223,7 @@ function SyntaxLookupWidget(Props) { })); }; var details; - if (typeof state === "number" || !state.TAG) { + if (typeof state === "number" || state.TAG === /* ShowFiltered */0) { details = null; } else { var item = state._0; @@ -341,7 +247,7 @@ function SyntaxLookupWidget(Props) { })); var items; items = typeof state === "number" ? allItems : ( - state.TAG ? [] : state._1 + state.TAG === /* ShowFiltered */0 ? state._1 : [] ); var categories = Belt_Array.reduce(Js_dict.entries(Belt_Array.reduce(items, Js_dict.fromArray(initial), (function (acc, item) { var key = toString(item.category); @@ -391,16 +297,16 @@ function SyntaxLookupWidget(Props) { "", allItems ]; - } else if (state.TAG) { - var item$1 = state._0; + } else if (state.TAG === /* ShowFiltered */0) { match$1 = [ - item$1.name, - [item$1] + state._0, + state._1 ]; } else { + var item$1 = state._0; match$1 = [ - state._0, - state._1 + item$1.name, + [item$1] ]; } var onSearchClear = function (param) { @@ -424,12 +330,13 @@ function SyntaxLookupWidget(Props) { style: { maxWidth: "34rem" } - }, React.createElement(SyntaxLookupWidget$SearchBox, { + }, React.createElement(SearchBox.make, { completionValues: Belt_Array.map(match$1[1], (function (item) { return item.name; })), value: match$1[0], onClear: onSearchClear, + placeholder: "Enter keywords or syntax...", onValueChange: onSearchValueChange }))), React.createElement("div", { className: "mt-10" diff --git a/components/SyntaxLookupWidget.res b/src/components/SyntaxLookupWidget.res similarity index 74% rename from components/SyntaxLookupWidget.res rename to src/components/SyntaxLookupWidget.res index d84a32665..1fc094f95 100644 --- a/components/SyntaxLookupWidget.res +++ b/src/components/SyntaxLookupWidget.res @@ -104,107 +104,6 @@ let getAnchor = path => { } } -module SearchBox = { - @bs.send external focus: Dom.element => unit = "focus" - @bs.send external blur: Dom.element => unit = "blur" - - external toDomElement: Js.t<'a> => Dom.element = "%identity" - - type state = - | Active - | Inactive - - @react.component - let make = ( - ~completionValues: array=[], // set of possible values - ~value: string, - ~onClear: unit => unit, - ~onValueChange: string => unit, - ) => { - let (state, setState) = React.useState(_ => Inactive) - let textInput = React.useRef(Js.Nullable.null) - - let onMouseDownClear = evt => { - ReactEvent.Mouse.preventDefault(evt) - onClear() - } - - let focusInput = () => - textInput.current->Js.Nullable.toOption->Belt.Option.forEach(el => el->focus) - - let onAreaFocus = evt => { - let el = ReactEvent.Focus.target(evt) - let isDiv = Js.Null_undefined.isNullable(el["type"]) - - if isDiv && state === Inactive { - focusInput() - } - } - - let onFocus = _ => { - setState(_ => Active) - } - - let onBlur = _ => { - setState(_ => Inactive) - } - - let onKeyDown = evt => { - let key = ReactEvent.Keyboard.key(evt) - let ctrlKey = ReactEvent.Keyboard.ctrlKey(evt) - - let full = (ctrlKey ? "CTRL+" : "") ++ key - - switch full { - | "Escape" => onClear() - | "Tab" => - if Js.Array.length(completionValues) === 1 { - let targetValue = Belt.Array.getExn(completionValues, 0) - - if targetValue !== value { - ReactEvent.Keyboard.preventDefault(evt) - onValueChange(targetValue) - } else { - () - } - } - | _ => () - } - } - - let onChange = evt => { - ReactEvent.Form.preventDefault(evt) - let value = ReactEvent.Form.target(evt)["value"] - onValueChange(value) - } - -
- - - -
- } -} - module Tag = { @react.component let make = (~text: string) => { @@ -386,6 +285,7 @@ let make = () => {
item.name)} value=searchValue onClear=onSearchClear diff --git a/components/SyntaxLookupWidget.resi b/src/components/SyntaxLookupWidget.resi similarity index 100% rename from components/SyntaxLookupWidget.resi rename to src/components/SyntaxLookupWidget.resi