From 3b17516bda6e855e2c6ebfc8806b87d815c15668 Mon Sep 17 00:00:00 2001 From: eldh Date: Fri, 4 Oct 2019 09:49:49 +0200 Subject: [PATCH] Fixes --- TODO.md | 1 + revy/src/Box.re | 16 ++-- revy/src/Button.re | 59 ++++++++++++- revy/src/Card.re | 31 ++++--- revy/src/Checkbox.re | 9 +- revy/src/Core.re | 157 +++++++++++++++++++---------------- revy/src/Link.re | 36 ++++---- revy/src/Radiobutton.re | 7 +- revy/src/Text.re | 12 +-- revy/src/TextInput.re | 153 ++++++++++++++++++++++++++++------ revy/src/Toggle.re | 9 +- revy/src/TouchableOpacity.re | 12 +-- revy/src/View.re | 6 +- 13 files changed, 344 insertions(+), 164 deletions(-) diff --git a/TODO.md b/TODO.md index b67b8ec..eb76959 100644 --- a/TODO.md +++ b/TODO.md @@ -6,4 +6,5 @@ - Use border radii - Easier access to border styles - More font weights? +- Grid component - Same kindo of api for borders as for margin/padding diff --git a/revy/src/Box.re b/revy/src/Box.re index d1f0619..60ccb5d 100644 --- a/revy/src/Box.re +++ b/revy/src/Box.re @@ -1,7 +1,6 @@ -[@bs.config {jsx: 3}]; - let useBoxStyle = ( + ~position as position_, ~align as align_, ~alignSelf as alignSelf_, ~alignContent as alignContent_, @@ -24,6 +23,7 @@ let useBoxStyle = [ Css.[ + position(position_), alignSelf(alignSelf_), alignItems(align_), backgroundColor(Core.Styles.useColor(backgroundColor_)), @@ -51,22 +51,25 @@ let make = ~tag="div", ~a11yTitle as _a11yTitle=?, ~style as style_=[], + ~position=`relative, ~align=`flexStart, ~alignSelf=`auto, ~alignContent=`flexStart, ~backgroundColor=`transparent, ~grow=1., ~wrap=`wrap, - ~shrink=1., + ~shrink=0., ~basis=`auto, ~justify=`flexStart, ~direction=`column, - ~padding=`padding(`noSpace), - ~margin=`margin(`noSpace), + ~padding=?, + ~margin=?, ~height=`auto, ~width=`auto, ~overflow=`initial, ~borderRadius=Css.px(0), + ~onMouseOver=?, + ~onMouseOut=?, ~domProps=?, ~children=?, (), @@ -74,6 +77,7 @@ let make = let style = [ useBoxStyle( + ~position, ~align, ~alignSelf, ~alignContent, @@ -97,6 +101,6 @@ let make = |> List.concat; - children + children ; }; \ No newline at end of file diff --git a/revy/src/Button.re b/revy/src/Button.re index 0d357aa..da17356 100644 --- a/revy/src/Button.re +++ b/revy/src/Button.re @@ -16,7 +16,7 @@ let useButtonStyles = ( ~variant, ~outline as outline_, - ~margin as margin_, + ~margin as margin_=?, ~size, ~disabled as _disabled_, (), @@ -34,6 +34,7 @@ let useButtonStyles = textDecoration(`none), textAlign(`center), alignContent(`center), + position(`relative), flexGrow(0.), overflow(`visible), cursor(`pointer), @@ -52,7 +53,7 @@ let useButtonStyles = | Error => `error | Success => `success | Primary => `primary - | Secondary => `highlight((50, `neutral)) + | Secondary => `highlight((1, `body)) }; let styleStyles = [ outline_ @@ -96,12 +97,13 @@ let useButtonStyles = opacity(0.7), hover([backgroundColor(Styles.useColor(bgVariant))]), ]), - focus([outlineStyle(`none), ...Animations.focus]), + focus([outlineStyle(`none)]), + selector(":focus:not(:active)", Animations.focus), active([ backgroundColor( outline_ ? outlineHighlightBg(0.15) - : Styles.useColor(~highlight=15, bgVariant), + : Styles.useColor(~highlight=5, bgVariant), ), ]), ...styleStyles, @@ -172,4 +174,53 @@ module Link = { children ; }; +}; +module Round = { + [@react.component] + let make = + ( + ~onClick, + ~variant=Secondary, + ~size=Medium, + ~disabled=false, + ~outline=false, + ~style=[], + ~onlyFocusOnTab=true, + ~margin=?, + ~children, + (), + ) => { + let w = + switch (size) { + | Small => `triple + | Medium => `quad + | Large => `number(6) + }; + let btnStyle = + useButtonStyles(~variant, ~outline, ~margin?, ~size, ~disabled, ()); + List.concat + } + basis=`auto + onPress=onClick + domProps={"disabled": disabled}> + children + ; + }; }; \ No newline at end of file diff --git a/revy/src/Card.re b/revy/src/Card.re index c0c12a8..6cd99e9 100644 --- a/revy/src/Card.re +++ b/revy/src/Card.re @@ -1,20 +1,27 @@ open Core; -let useCardStyle = (~padding as p, ~margin as m, ()) => { +let useCardStyle = (~padding as p=?, ~margin as m=?, ()) => { + let alpha = Styles.useIsLight() ? 0.05 : 0.2; [ Css.[ - backgroundColor(Styles.useColor(`highlight((3, `body)))), + backgroundColor( + Styles.( + useColor(useIsLight() ? `transparent : `highlight((4, `body))) + ), + ), flexWrap(`wrap), + flexDirection(`column), + alignItems(`stretch), borderRadius(Css.px(6)), - borderWidth(px(1)), - borderColor(Styles.useColor(`highlight((8, `body)))), - borderStyle(`solid), + // borderWidth(px(1)), + // borderColor(Styles.useColor(`highlight((8, `body)))), + // borderStyle(`solid), unsafe("willChange", "transition"), - boxShadow( - ~y=px(4), - ~blur=px(10), - rgba(0, 0, 0, Styles.useIsLight() ? 0.15 : 0.45), - ), + boxShadows([ + `shadow("0 0px 4px " ++ string_of_rgba(0, 0, 0, alpha)), + `shadow("0 5px 12px " ++ string_of_rgba(0, 0, 0, alpha)), + `shadow("0 10px 16px " ++ string_of_rgba(0, 0, 0, alpha)), + ]), ], Styles.usePadding(p), Styles.useMargin(m), @@ -30,12 +37,12 @@ let make = ~style as style_=[], ~grow=1., ~padding=`padding(`single), - ~margin=`margin(`noSpace), + ~margin=?, ~domProps=?, ~children=?, (), ) => { - let style = [useCardStyle(~padding, ~margin, ()), style_] |> List.concat; + let style = [useCardStyle(~padding, ~margin?, ()), style_] |> List.concat; children ; }; \ No newline at end of file diff --git a/revy/src/Checkbox.re b/revy/src/Checkbox.re index 7a3dea4..a8d73e7 100644 --- a/revy/src/Checkbox.re +++ b/revy/src/Checkbox.re @@ -57,9 +57,8 @@ let make = ~id="", ~disabled=false, ~styles=?, - ~onFocus=ignore, - ~onBlur=ignore, - ~margin=`margin(`noSpace), + ~onFocus=?, + ~onBlur=?, ~checked, ~value, ~name="", @@ -79,8 +78,8 @@ let make = id disabled onChange - onFocus - onBlur + ?onFocus + ?onBlur label className={ ( diff --git a/revy/src/Core.re b/revy/src/Core.re index 76dab1b..bd91752 100644 --- a/revy/src/Core.re +++ b/revy/src/Core.re @@ -136,6 +136,7 @@ module Color = { | `bodyText | `transparent | `highlight(int, backgroundColor) + | `alpha(float, backgroundColor) | `unsafeCustomColor(Lab.t) ]; @@ -229,13 +230,15 @@ module BackgroundColorContext = { module Provider = { [@react.component] let make = (~value: Color.backgroundColor, ~children) => { - switch (value) { - | `transparent => children - | _ => + let updateVal = value => UnsafeCreateReactElement.use( Obj.magic(provider), {"value": value, "children": children}, - ) + ); + switch (value) { + | `transparent => children + | `alpha(a, _) => a > 0.49 ? updateVal(value) : children + | _ => updateVal(value) }; }; }; @@ -272,6 +275,7 @@ module Private = { | `body => theme.colors.bodyBackground | `bodyText => theme.colors.bodyText | `highlight(i, c) => backgroundColor(~theme, ~highlight=i, c) + | `alpha(f, c) => backgroundColor(~theme, ~alpha=f, c) | `transparent => `lab((100., 100., 100., 0.)) | `unsafeCustomColor(c) => c } @@ -338,24 +342,28 @@ module Private = { test(i) ? i : findMinStep(test, i + 1); }; - let space = (~theme, ~borderAdjust=0, v) => { + let space = (~negative=false, ~theme, ~borderAdjust=0, v) => { let length = v => Css.px(theme.baseGridUnit * v - borderAdjust); + let multiplier = negative ? (-1) : 1; switch (v) { | `auto => Obj.magic(Css.auto) | `noSpace => Css.px(0) - | `half => 1 |> length - | `single => 2 |> length - | `double => 4 |> length - | `triple => 6 |> length - | `quad => 8 |> length - | `quint => 10 |> length - | `number(i) => i |> length + | `half => 1 * multiplier |> length + | `single => 2 * multiplier |> length + | `double => 4 * multiplier |> length + | `triple => 6 * multiplier |> length + | `quad => 8 * multiplier |> length + | `quint => 10 * multiplier |> length + | `number(i) => i * multiplier |> length | `unsafeCustomValue(v) => v | `closest(pixels) => let rem = pixels mod theme.baseGridUnit; let extra = rem == 0 ? 0 : 1; - (pixels / theme.baseGridUnit + extra) * theme.baseGridUnit |> Css.px; - | `responsive(_, _, _) => 6 |> length // TODO Fix + (pixels / theme.baseGridUnit + extra) + * theme.baseGridUnit + * multiplier + |> Css.px; + | `responsive(_, _, _) => 6 * multiplier |> length // TODO Fix }; }; @@ -458,68 +466,76 @@ module Animations = { ]; }; module Styles = { - let marginSpace = (theme, v) => Obj.magic(Private.space(~theme, v)); + let marginSpace = (theme, v) => Obj.magic(Private.space(~theme, v)); // TODO fix let rec marginStyles_ = (theme, p) => { let marginSpace = v => Private.space(~theme, v); switch (p) { - | `auto => [Css.margin(`auto)] - | `margin(i) => [Css.margin(marginSpace(i))] - | `marginTop(i) => [Css.marginTop(marginSpace(i))] - | `marginBottom(i) => [Css.marginBottom(marginSpace(i))] - | `marginLeft(i) => [Css.marginLeft(marginSpace(i))] - | `marginRight(i) => [Css.marginRight(marginSpace(i))] - | `margin2(x, y) => [ - Css.margin2(~v=marginSpace(y), ~h=marginSpace(x)), - ] - | `margin4(l, t, r, b) => [ - Css.margin4( - ~top=marginSpace(t), - ~bottom=marginSpace(b), - ~right=marginSpace(r), - ~left=marginSpace(l), - ), - ] - | `responsive(s, m, l) => - responsive( - theme, - ( - marginStyles_(theme, s), - marginStyles_(theme, m), - marginStyles_(theme, l), - ), - ) + | None => [] + | Some(value) => + switch (value) { + | `auto => [Css.margin(`auto)] + | `margin(i) => [Css.margin(marginSpace(i))] + | `marginTop(i) => [Css.marginTop(marginSpace(i))] + | `marginBottom(i) => [Css.marginBottom(marginSpace(i))] + | `marginLeft(i) => [Css.marginLeft(marginSpace(i))] + | `marginRight(i) => [Css.marginRight(marginSpace(i))] + | `margin2(x, y) => [ + Css.margin2(~v=marginSpace(y), ~h=marginSpace(x)), + ] + | `margin4(l, t, r, b) => [ + Css.margin4( + ~top=marginSpace(t), + ~bottom=marginSpace(b), + ~right=marginSpace(r), + ~left=marginSpace(l), + ), + ] + | `responsive(s, m, l) => + responsive( + theme, + ( + marginStyles_(theme, s), + marginStyles_(theme, m), + marginStyles_(theme, l), + ), + ) + } }; }; let rec paddingStyles_ = (theme, p) => { switch (p) { - | `padding(i) => [Css.padding(Private.space(~theme, i))] - | `paddingTop(i) => [Css.paddingTop(Private.space(~theme, i))] - | `paddingBottom(i) => [Css.paddingBottom(Private.space(~theme, i))] - | `paddingLeft(i) => [Css.paddingLeft(Private.space(~theme, i))] - | `paddingRight(i) => [Css.paddingRight(Private.space(~theme, i))] - | `padding2(x, y) => [ - Css.padding2( - ~v=Private.space(~theme, y), - ~h=Private.space(~theme, x), - ), - ] - | `padding4(l, t, r, b) => [ - Css.padding4( - ~top=Private.space(~theme, t), - ~bottom=Private.space(~theme, b), - ~right=Private.space(~theme, r), - ~left=Private.space(~theme, l), - ), - ] - | `responsive(s, m, l) => - responsive( - theme, - ( - paddingStyles_(theme, s), - paddingStyles_(theme, m), - paddingStyles_(theme, l), - ), - ) + | None => [] + | Some(value) => + switch (value) { + | `padding(i) => [Css.padding(Private.space(~theme, i))] + | `paddingTop(i) => [Css.paddingTop(Private.space(~theme, i))] + | `paddingBottom(i) => [Css.paddingBottom(Private.space(~theme, i))] + | `paddingLeft(i) => [Css.paddingLeft(Private.space(~theme, i))] + | `paddingRight(i) => [Css.paddingRight(Private.space(~theme, i))] + | `padding2(x, y) => [ + Css.padding2( + ~v=Private.space(~theme, y), + ~h=Private.space(~theme, x), + ), + ] + | `padding4(l, t, r, b) => [ + Css.padding4( + ~top=Private.space(~theme, t), + ~bottom=Private.space(~theme, b), + ~right=Private.space(~theme, r), + ~left=Private.space(~theme, l), + ), + ] + | `responsive(s, m, l) => + responsive( + theme, + ( + paddingStyles_(theme, s), + paddingStyles_(theme, m), + paddingStyles_(theme, l), + ), + ) + } }; }; @@ -604,8 +620,9 @@ module Styles = { |> Css.px; }; - let useSpace = (~borderAdjust=0, s) => { + let useSpace = (~negative=?, ~borderAdjust=0, s) => { Private.space( + ~negative?, ~theme=React.useContext(Context.context), ~borderAdjust, s, diff --git a/revy/src/Link.re b/revy/src/Link.re index 3abbe20..8747941 100644 --- a/revy/src/Link.re +++ b/revy/src/Link.re @@ -8,21 +8,15 @@ let useLinkStyle = () => { color(Styles.useTextColor()), transition(~duration=200, "color"), hover([color(Styles.useTextColor(~highlight=-40, ()))]), - focus([ - outlineStyle(`none), - textShadow(~blur=px(3), Styles.useColor(~alpha=0.4, `primary)), - ...Animations.focus, - ]), - active([ - outlineStyle(`none), - boxShadow( - ~y=px(0), - ~blur=px(0), - ~spread=px(1), - ~inset=true, - Styles.useColor(`transparent), - ), - ]), + focus([outlineStyle(`none)]), + selector( + ":focus:not(:active)", + [ + textShadow(~blur=px(3), Styles.useColor(~alpha=0.4, `primary)), + ...Animations.focus, + ], + ), + active([opacity(0.5)]), ]; }; [@react.component] @@ -32,7 +26,7 @@ let make = ~onClick=ignore, ~size=0, ~lineHeight=0, - ~margin=`margin(`auto), + ~margin=?, ~weight=`normal, ~tintColor=?, ~children, @@ -45,7 +39,9 @@ let make = href onClick className={ - [textStyle, linkStyle, Styles.useMargin(margin)] |> List.concat |> Css.style + [textStyle, linkStyle, Styles.useMargin(margin)] + |> List.concat + |> Css.style }> children->React.string ; @@ -55,10 +51,10 @@ module Button = { [@react.component] let make = ( - ~onClick=ignore, + ~onClick, ~size=0, ~lineHeight=0, - ~margin=`margin(`auto), + ~margin=?, ~weight=`normal, ~tintColor=?, ~children, @@ -66,7 +62,7 @@ module Button = { ) => { let textStyle = Text.useTextStyles(~tintColor?, ~size, ~lineHeight, ~weight, ()); - let linkStyle = useLinkStyle(); + let linkStyle = useLinkStyle(()); { +let useRadiobuttonStyles = () => { Css.[ position(`absolute), cursor(`pointer), @@ -64,7 +64,6 @@ let make = ~styles=?, ~onFocus=ignore, ~onBlur=ignore, - ~margin=`margin(`noSpace), ~checked, ~value, ~name="", @@ -90,8 +89,8 @@ let make = className={ ( switch (styles) { - | None => useInputStyles() - | Some(v) => [useInputStyles(), v] |> List.concat + | None => useRadiobuttonStyles() + | Some(v) => [useRadiobuttonStyles(), v] |> List.concat } ) |> Css.style diff --git a/revy/src/Text.re b/revy/src/Text.re index 4b61b10..bb02b0c 100644 --- a/revy/src/Text.re +++ b/revy/src/Text.re @@ -48,7 +48,7 @@ let make = ~quiet=false, ~tintColor=?, ~style=?, - ~children:React.element, + ~children: React.element, (), ) => { let styles = @@ -110,8 +110,8 @@ module Block = { ( ~weight=`normal, ~tag="div", - ~margin as m=`margin(`noSpace), - ~padding as p=`padding(`noSpace), + ~margin as m=?, + ~padding as p=?, ~quiet=false, ~size=0, ~lineHeight=0, @@ -169,7 +169,7 @@ module Paragraph = { ) => { let styles = useTextStyles(~size, ~lineHeight, ~weight, ~quiet, ~tintColor?, ()); - let margin = Styles.useMargin(margin); + let margin = Styles.useMargin(Some(margin)); UnsafeCreateReactElement.use( tag, { @@ -214,8 +214,8 @@ module Code = { ~fontFamily=`mono, (), ); - let margin = Styles.useMargin(`margin(`noSpace)); - let padding = Styles.usePadding(`padding(`double)); + let margin = Styles.useMargin(Some(`margin(`noSpace))); + let padding = Styles.usePadding(Some(`padding(`double))); { +let useInputStyles = (~margin as m=?, ()) => { Core.( [ Css.[ @@ -13,19 +13,19 @@ let useInputStyles = (~margin as m, ()) => { fontSize(Styles.useFontSize(0)), fontFamily(Styles.useFontFamily(`body)), boxSizing(`borderBox), + borderRadius(Css.px(6)), borderWidth(px(0)), borderColor(Styles.useColor(`transparent)), - borderRadius(Css.px(6)), borderStyle(`solid), backgroundColor(Styles.useColor(~alpha=0.07, `bodyText)), color(Styles.useTextColor()), - boxShadow( - ~y=px(0), - ~blur=px(0), - ~spread=px(1), - ~inset=true, - Styles.useColor(~alpha=0.07, `bodyText), - ), + // boxShadow( + // ~y=px(0), + // ~blur=px(0), + // ~spread=px(1), + // ~inset=true, + // Styles.useColor(~alpha=0.07, `bodyText), + // ), focus([ outlineStyle(`none), boxShadow( @@ -47,43 +47,144 @@ module Input = { [@react.component] let make = ( - ~onClick as _=?, ~onChange, - ~label, ~value, - ~id="", + ~id=?, + ~label=?, ~type_="text", - ~disabled=false, + ~disabled=?, ~style=?, - ~onFocus=ignore, - ~onBlur=ignore, - ~placeholder="", - ~margin as m=`margin(`noSpace), + ~onFocus=?, + ~onBlur=?, + ~onKeyDown=?, + ~onKeyPress=?, + ~onKeyUp=?, + ~onClick=?, + ~placeholder=?, + ~margin=?, (), ) => { useInputStyles(~margin=m, ()) - | Some(l) => [useInputStyles(~margin=m, ()), l] |> List.concat + | None => useInputStyles(~margin?, ()) + | Some(l) => [useInputStyles(~margin?, ()), l] |> List.concat } ) |> Css.style } - type_ />; }; }; +[@bs.get] external getForm: Dom.element => Dom.element = "form"; +[@bs.send] external requestSubmitForm: Dom.element => unit = "requestSubmit"; +[@bs.get] external getScrollHeight: Dom.element => int = "scrollHeight"; +[@bs.send] +external setAttribute: (Dom.element, string, string) => unit = "setAttribute"; +[@bs.send] +external dispatchEvent: (Dom.element, Dom.event) => unit = "dispatchEvent"; +[@bs.new] external newEvent: string => Dom.event = "Event"; + +let submitForm = form => { + form->dispatchEvent(newEvent("submit")); +}; + +module Textarea = { + [@react.component] + let make = + ( + ~onChange as onChangeProp, + ~value, + ~id=?, + ~label=?, + ~disabled=?, + ~style=?, + ~onFocus=?, + ~onBlur=?, + ~onClick=?, + ~onKeyDown=?, + ~onKeyPress=?, + ~onKeyUp=?, + ~placeholder=?, + ~margin=?, + (), + ) => { + let domRef = React.useRef(Js.Nullable.null); + let onChange = e => { + // There's probably a more react-y way of doing this... + let current = domRef |> React.Ref.current |> Js.Nullable.toOption; + switch (current) { + | Some(el) => + el->setAttribute("style", "height:auto"); + let h = getScrollHeight(el); + el->setAttribute("style", "height:" ++ (h |> string_of_int) ++ "px"); + | None => () + }; + + onChangeProp(e); + }; + + let onKeyDown = e => { + let current = domRef |> React.Ref.current |> Js.Nullable.toOption; + let key = ReactEvent.Keyboard.key(e); + let cmd = ReactEvent.Keyboard.metaKey(e); + if (key === "Enter" && cmd) { + ReactEvent.Keyboard.preventDefault(e); + ReactEvent.Keyboard.stopPropagation(e); + switch (current) { + | Some(el) => el |> getForm |> submitForm + | None => () + }; + }; + switch (onKeyDown) { + | Some(fn) => fn(e) + | None => () + }; + }; +