mirror of
https://github.com/rowtype-yoga/ry-blocks.git
synced 2024-08-18 01:30:31 +03:00
Input work
This commit is contained in:
parent
774db186ef
commit
c32928933f
1
.psci_modules/index.js
Normal file
1
.psci_modules/index.js
Normal file
@ -0,0 +1 @@
|
||||
require('$PSCI')['$main']();
|
8
convert-more.fish
Normal file
8
convert-more.fish
Normal file
@ -0,0 +1,8 @@
|
||||
for f in (ls src/Yoga/Block/Icon/SVG/*.svg)
|
||||
npx svgo -i $f
|
||||
end
|
||||
node convert-svgs.js
|
||||
for f in (ls src/Yoga/Block/Icon/SVG/*.purs)
|
||||
sed -i "" 's/stroke: "#333"/stroke: "var(--stroke-colour)"/g' $f
|
||||
end
|
||||
|
@ -1,6 +1,6 @@
|
||||
const path = require('path');
|
||||
const svg2psreact = require("svg2psreact");
|
||||
|
||||
const assetsDir = path.join(__dirname, 'src', 'Assets');
|
||||
const assetsDir = path.join(__dirname, 'src', 'Yoga', 'Block', 'Icon', 'SVG');
|
||||
|
||||
svg2psreact.convertAllSVGsInDirectory("Assets", assetsDir)
|
||||
svg2psreact.convertAllSVGsInDirectory("Yoga.Block.Icon.SVG", assetsDir)
|
||||
|
@ -17,7 +17,7 @@
|
||||
"babel-loader": "^8.1.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"compression-webpack-plugin": "^6.0.3",
|
||||
"framer-motion": "^2.7.0",
|
||||
"framer-motion": "^3.0.0",
|
||||
"html-webpack-plugin": "^4.5.0",
|
||||
"jsdom": "^16.3.0",
|
||||
"jsdom-global": "^3.0.2",
|
||||
|
@ -119,7 +119,7 @@ let additions =
|
||||
|
||||
|
||||
let upstream =
|
||||
https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20201021/packages.dhall sha256:55ebdbda1bd6ede4d5307fbc1ef19988c80271b4225d833c8d6fb9b6fb1aa6d8
|
||||
https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20201217/packages.dhall sha256:f46d45e29977f3b57717b56d20a5ceac12532224516eea3012a4688f22ac1539
|
||||
|
||||
let overrides =
|
||||
{ spec-discovery = upstream.spec-discovery // { version = "master" }
|
||||
|
@ -18,6 +18,7 @@ You can edit this file as you like.
|
||||
, "routing-duplex"
|
||||
, "spec-discovery"
|
||||
, "untagged-union"
|
||||
, "web-uievents"
|
||||
]
|
||||
, packages = ./packages.dhall
|
||||
, sources = [ "src/**/*.purs", "test/**/*.purs" ]
|
||||
|
@ -6,6 +6,14 @@ module Framer.Motion
|
||||
, callback
|
||||
, class EffectFnMaker
|
||||
, toEffectFn
|
||||
, OnHoverStart
|
||||
, onHoverStart
|
||||
, customProp
|
||||
, OnHoverEnd
|
||||
, onHoverEnd
|
||||
, whileHover
|
||||
, WhileHover
|
||||
, EventInfo
|
||||
, OnTap
|
||||
, TapInfo
|
||||
, OnTapStart
|
||||
@ -80,6 +88,7 @@ import Data.Nullable (Nullable)
|
||||
import Data.Symbol (class IsSymbol, SProxy, reflectSymbol)
|
||||
import Effect (Effect)
|
||||
import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, mkEffectFn2)
|
||||
import Foreign (Foreign, unsafeToForeign)
|
||||
import Foreign.Object (Object)
|
||||
import Heterogeneous.Mapping (class HMapWithIndex, class MappingWithIndex, hmapWithIndex)
|
||||
import Literals.Undefined (Undefined)
|
||||
@ -97,6 +106,7 @@ import Untagged.Castable (class Castable, cast)
|
||||
import Untagged.Union (type (|+|))
|
||||
import Web.DOM (Node)
|
||||
import Web.Event.Internal.Types (Event)
|
||||
import Web.UIEvent.MouseEvent (MouseEvent)
|
||||
import Yoga.Block.Internal (Id)
|
||||
|
||||
foreign import divImpl ∷ ∀ a. ReactComponent { | a }
|
||||
@ -216,6 +226,28 @@ onTap fn2 = cast (mkEffectFn2 fn2)
|
||||
onTapCancel ∷ (Event -> TapInfo -> Effect Unit) -> OnTap
|
||||
onTapCancel fn2 = cast (mkEffectFn2 fn2)
|
||||
|
||||
type EventInfo =
|
||||
{ point ∷ { x ∷ Number, y ∷ Number }
|
||||
}
|
||||
|
||||
type WhileHover =
|
||||
(EffectFn2 MouseEvent EventInfo Unit |+| Undefined)
|
||||
|
||||
type OnHoverEnd =
|
||||
(EffectFn2 MouseEvent EventInfo Unit |+| Undefined)
|
||||
|
||||
type OnHoverStart =
|
||||
(EffectFn2 MouseEvent EventInfo Unit |+| Undefined)
|
||||
|
||||
onHoverStart ∷ (MouseEvent -> EventInfo -> Effect Unit) -> OnHoverStart
|
||||
onHoverStart = cast <<< toEffectFn
|
||||
|
||||
onHoverEnd ∷ (MouseEvent -> EventInfo -> Effect Unit) -> OnHoverEnd
|
||||
onHoverEnd = cast <<< toEffectFn
|
||||
|
||||
whileHover ∷ ∀ c. Castable c WhileHover => c -> WhileHover
|
||||
whileHover = cast
|
||||
|
||||
type TapInfo =
|
||||
{ x ∷ Number, y ∷ Number }
|
||||
|
||||
@ -250,9 +282,13 @@ onDragEnd = cast <<< toEffectFn
|
||||
onDrag ∷ (Event -> PanInfo -> Effect Unit) -> OnDrag
|
||||
onDrag fn2 = cast (mkEffectFn2 fn2)
|
||||
|
||||
customProp ∷ ∀ a. a -> Foreign
|
||||
customProp = unsafeToForeign
|
||||
|
||||
type MotionPropsF f r =
|
||||
( initial ∷ f Initial
|
||||
, animate ∷ f Animate
|
||||
, custom ∷ f Foreign
|
||||
, drag ∷ f Drag
|
||||
, dragMomentum ∷ f DragMomentum
|
||||
, dragElastic ∷ f DragElastic
|
||||
@ -270,6 +306,9 @@ type MotionPropsF f r =
|
||||
, onTapStart ∷ f OnTapStart
|
||||
, onTapEnd ∷ f OnTapEnd
|
||||
, onTapCancel ∷ f OnTapCancel
|
||||
, whileHover ∷ f WhileHover
|
||||
, onHoverStart ∷ f OnHoverStart
|
||||
, onHoverEnd ∷ f OnHoverEnd
|
||||
, exit ∷ f Exit
|
||||
| r
|
||||
)
|
||||
|
@ -7,43 +7,11 @@ import Effect.Uncurried (EffectFn3, runEffectFn3)
|
||||
import Foreign.Object (Object)
|
||||
import Foreign.Object as Object
|
||||
import Prim.Row (class Union)
|
||||
import React.Basic.DOM (CSS)
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Yoga.Prelude.View (Hook, NodeRef, unsafeHook)
|
||||
import Yoga.Prelude.View (Hook, unsafeHook)
|
||||
import React.Basic.Popper.Types (Options, PopperData, PopperElement, ReferenceElement)
|
||||
|
||||
foreign import data UsePopper ∷ Type -> Type -> Type
|
||||
|
||||
type ReferenceElement =
|
||||
NodeRef
|
||||
|
||||
type PopperElement =
|
||||
NodeRef
|
||||
|
||||
type ArrowElement =
|
||||
NodeRef
|
||||
|
||||
type DataAttributes =
|
||||
{ popper ∷ Object String, arrow ∷ Object String }
|
||||
|
||||
type Styles =
|
||||
{ popper ∷ CSS, arrow ∷ CSS }
|
||||
|
||||
type PopperData =
|
||||
{ styles ∷ Styles, attributes ∷ DataAttributes }
|
||||
|
||||
foreign import data Modifier ∷ Type
|
||||
|
||||
modifierArrow ∷ ArrowElement -> Modifier
|
||||
modifierArrow element = unsafeCoerce { name: "arrow", options: { element } }
|
||||
|
||||
modifierOffset ∷ { x ∷ Number, y ∷ Number } -> Modifier
|
||||
modifierOffset { x, y } = unsafeCoerce { name: "offset", options: { offset: [ x, y ] } }
|
||||
|
||||
type Options =
|
||||
( modifiers ∷ Array Modifier
|
||||
, strategy ∷ String
|
||||
)
|
||||
|
||||
foreign import usePopperImpl ∷ ∀ opts. EffectFn3 ReferenceElement PopperElement { | opts } PopperData
|
||||
|
||||
toDataAttributes ∷ Object String -> Object String
|
||||
|
@ -1,27 +1,24 @@
|
||||
module React.Basic.Popper.Story where
|
||||
|
||||
import Prelude
|
||||
import Color as Color
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.Interpolate (i)
|
||||
import Data.Nullable (null)
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Effect (Effect)
|
||||
import Effect.Uncurried (mkEffectFn1)
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import Framer.Motion (onTap)
|
||||
import Framer.Motion as Motion
|
||||
import React.Basic (JSX, element, fragment)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Emotion as E
|
||||
import React.Basic.Hooks as React
|
||||
import React.Basic.Popper.Hook (modifierArrow, modifierOffset, usePopper)
|
||||
import React.Basic.Popper.Hook (usePopper)
|
||||
import React.Basic.Popper.Types (modifierArrow, modifierOffset)
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Yoga.Block as Block
|
||||
import Yoga.Block.Atom.Toggle as Toggle
|
||||
import Yoga.Block.Container.Style (DarkOrLightMode(..))
|
||||
import Yoga.Block.Container.Style as Styles
|
||||
import Yoga.Block.Internal.CSS (nest)
|
||||
import Yoga.Prelude.View (NodeRef, el, styled, styledLeaf)
|
||||
import Yoga.Prelude.View (NodeRef, el, guard, handler, preventDefault, styled, styledLeaf)
|
||||
|
||||
default ∷
|
||||
{ decorators ∷ Array (Effect JSX -> JSX)
|
||||
@ -136,6 +133,7 @@ animatedPopper = do
|
||||
|
||||
mkBasicExample =
|
||||
React.reactComponent "Popper example" \p -> React.do
|
||||
-- Hooks
|
||||
referenceElement /\ setReferenceElement <- React.useState' nullRef
|
||||
popperElement /\ setPopperElement <- React.useState' nullRef
|
||||
arrowElement /\ setArrowElement <- React.useState' nullRef
|
||||
@ -143,63 +141,105 @@ animatedPopper = do
|
||||
usePopper referenceElement popperElement
|
||||
{ modifiers:
|
||||
[ modifierArrow arrowElement
|
||||
, modifierOffset { x: 0.0, y: 8.0 }
|
||||
, modifierOffset { x: 0.0, y: 12.0 }
|
||||
]
|
||||
}
|
||||
pure
|
||||
$ fragment
|
||||
$ [ element R.div'
|
||||
{ ref: unsafeCoerce (mkEffectFn1 setReferenceElement)
|
||||
, children: [ R.text "Reference element" ]
|
||||
}
|
||||
, el Motion.animatePresence {}
|
||||
[ styled Motion.div
|
||||
{ className: "popper-element"
|
||||
, key: "heinz"
|
||||
, css:
|
||||
E.css
|
||||
{ background: E.str "darkslateblue"
|
||||
, borderRadius: E.str "8px"
|
||||
, display: E.str "block"
|
||||
, padding: E.str "4px 8px"
|
||||
, "&[data-popper-placement^='top'] > .popper-arrow":
|
||||
nest { bottom: E.str "-4px" }
|
||||
, "&[data-popper-placement^='bottom'] > .popper-arrow":
|
||||
nest { top: E.str "-4px" }
|
||||
, "&[data-popper-placement^='left'] > .popper-arrow":
|
||||
nest { right: E.str "-4px" }
|
||||
, "&[data-popper-placement^='right'] > .popper-arrow":
|
||||
nest { left: E.str "-4px" }
|
||||
}
|
||||
, ref: unsafeCoerce (mkEffectFn1 setPopperElement)
|
||||
, style: styles.popper
|
||||
, _data: attributes.popper
|
||||
}
|
||||
[ R.text "Popper Element"
|
||||
, styledLeaf R.div'
|
||||
{ className: "popper-arrow"
|
||||
, id: "arrow"
|
||||
, css:
|
||||
E.css
|
||||
{ position: E.str "absolute"
|
||||
, width: E.str "8px"
|
||||
, height: E.str "8px"
|
||||
, zIndex: E.str "-1"
|
||||
, "&::before":
|
||||
nest
|
||||
{ position: E.str "absolute"
|
||||
, width: E.str "8px"
|
||||
, height: E.str "8px"
|
||||
, zIndex: E.str "-1"
|
||||
, content: E.str "''"
|
||||
, transform: E.str "rotate(45deg)"
|
||||
, background: E.str "darkslateblue"
|
||||
}
|
||||
}
|
||||
, ref: unsafeCoerce (mkEffectFn1 setArrowElement)
|
||||
, style: styles.arrow
|
||||
, _data: attributes.arrow
|
||||
}
|
||||
on /\ setOn <- React.useState' true
|
||||
-- Handlers
|
||||
let buttonClicked = setOn (not on)
|
||||
-- Elements
|
||||
let
|
||||
result =
|
||||
fragment
|
||||
$ [ refElem
|
||||
, popperEl
|
||||
[ animatePresence
|
||||
$ guard on
|
||||
[ content
|
||||
[ el Block.box {} [ R.text "Ich bin Stinky Bill" ]
|
||||
, arrow
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
animatePresence =
|
||||
el Motion.animatePresence
|
||||
{ initial: false
|
||||
}
|
||||
content =
|
||||
styled Motion.div
|
||||
{ className: "popper-element-content"
|
||||
, css: contentCss
|
||||
, initial: Motion.initial $ R.css { opacity: [ 1.0, 0.8, 0.0 ], scale: [ 1.0, 0.85 ] }
|
||||
, animate: Motion.animate $ R.css { opacity: [ 0.0, 0.3, 1.0 ], scale: [ 0.0, 1.05, 1.0, 0.98, 1.01, 1.0 ] }
|
||||
, exit: Motion.exit $ R.css { opacity: [ 1.0, 0.8, 0.0 ], scale: [ 1.0, 0.85 ] }
|
||||
, transition: Motion.transition { duration: 0.2 }
|
||||
, key: "container"
|
||||
}
|
||||
popperEl =
|
||||
styled R.div'
|
||||
{ className: "popper-element"
|
||||
, css: popperCss
|
||||
, ref: unsafeCoerce (mkEffectFn1 setPopperElement)
|
||||
, style: styles.popper
|
||||
, _data: attributes.popper
|
||||
}
|
||||
arrow =
|
||||
styledLeaf R.div'
|
||||
{ className: "popper-arrow"
|
||||
, id: "arrow"
|
||||
, css: arrowCss
|
||||
, ref: unsafeCoerce (mkEffectFn1 setArrowElement)
|
||||
, style: styles.arrow
|
||||
, _data: attributes.arrow
|
||||
}
|
||||
refElem =
|
||||
element R.button'
|
||||
{ ref: unsafeCoerce (mkEffectFn1 setReferenceElement)
|
||||
, children: [ R.text "Reference element" ]
|
||||
, onClick: handler preventDefault (const buttonClicked)
|
||||
}
|
||||
pure result
|
||||
|
||||
backgroundColour = "var(--highlight)"
|
||||
|
||||
backgroundColour2 = "rgb(100, 160, 240)"
|
||||
|
||||
arrowCss =
|
||||
E.css
|
||||
{ position: E.str "absolute"
|
||||
, width: E.str "8px"
|
||||
, height: E.str "8px"
|
||||
, zIndex: E.str "0"
|
||||
, "&::before":
|
||||
nest
|
||||
{ position: E.str "absolute"
|
||||
, width: E.str "8px"
|
||||
, height: E.str "8px"
|
||||
, content: E.str "''"
|
||||
, transform: E.str "rotate(45deg)"
|
||||
, background: E.str backgroundColour
|
||||
}
|
||||
}
|
||||
|
||||
contentCss =
|
||||
E.css
|
||||
{ background: E.str $ i "linear-gradient(0deg," backgroundColour "," backgroundColour2 "," backgroundColour ")"
|
||||
, fontSize: E.str "14px"
|
||||
, zIndex: E.str "-1"
|
||||
, color: E.str $ "white"
|
||||
, boxShadow: E.str "0 1px 8px rgba(0,0,0,0.5)"
|
||||
, borderRadius: E.str "12px"
|
||||
}
|
||||
|
||||
popperCss =
|
||||
E.css
|
||||
{ "&[data-popper-placement^='top'] > * > .popper-arrow":
|
||||
nest { bottom: E.str "-4px" }
|
||||
, "&[data-popper-placement^='bottom'] > * > .popper-arrow":
|
||||
nest { top: E.str "-4px" }
|
||||
, "&[data-popper-placement^='left'] > * > .popper-arrow":
|
||||
nest { right: E.str "-4px" }
|
||||
, "&[data-popper-placement^='right'] > * > .popper-arrow":
|
||||
nest { left: E.str "-4px" }
|
||||
}
|
||||
|
40
src/React/Basic/Popper/Types.purs
Normal file
40
src/React/Basic/Popper/Types.purs
Normal file
@ -0,0 +1,40 @@
|
||||
module React.Basic.Popper.Types where
|
||||
|
||||
import Foreign.Object (Object)
|
||||
import React.Basic.DOM (CSS)
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Yoga.Prelude.View (NodeRef, null)
|
||||
|
||||
nullRef ∷ NodeRef
|
||||
nullRef = unsafeCoerce null
|
||||
|
||||
type ReferenceElement =
|
||||
NodeRef
|
||||
|
||||
type PopperElement =
|
||||
NodeRef
|
||||
|
||||
type ArrowElement =
|
||||
NodeRef
|
||||
|
||||
type DataAttributes =
|
||||
{ popper ∷ Object String, arrow ∷ Object String }
|
||||
|
||||
type Styles =
|
||||
{ popper ∷ CSS, arrow ∷ CSS }
|
||||
|
||||
type PopperData =
|
||||
{ styles ∷ Styles, attributes ∷ DataAttributes }
|
||||
|
||||
foreign import data Modifier ∷ Type
|
||||
|
||||
modifierArrow ∷ ArrowElement -> Modifier
|
||||
modifierArrow element = unsafeCoerce { name: "arrow", options: { element } }
|
||||
|
||||
modifierOffset ∷ { x ∷ Number, y ∷ Number } -> Modifier
|
||||
modifierOffset { x, y } = unsafeCoerce { name: "offset", options: { offset: [ x, y ] } }
|
||||
|
||||
type Options =
|
||||
( modifiers ∷ Array Modifier
|
||||
, strategy ∷ String
|
||||
)
|
@ -21,7 +21,7 @@ codeInput props = styles <>? cast props.css
|
||||
, background: str colour.inputBackground
|
||||
, border: str $ i "solid 1px " colour.inputBorder
|
||||
, borderRadius: str "var(--s-2)"
|
||||
, fontFamily: str "var(--monoFont)"
|
||||
, fontFamily: str "var(--mono-font)"
|
||||
, fontSize: str "var(--s0)"
|
||||
, lineHeight: str "var(--s0)"
|
||||
, width: str $ i "calc(" (cast props.maxLength ?|| 10) "ch + 4.3 * var(--s-5))"
|
||||
|
5
src/Yoga/Block/Atom/Icon.purs
Normal file
5
src/Yoga/Block/Atom/Icon.purs
Normal file
@ -0,0 +1,5 @@
|
||||
module Yoga.Block.Atom.Icon
|
||||
( module Yoga.Block.Atom.Icon.View
|
||||
) where
|
||||
|
||||
import Yoga.Block.Atom.Icon.View (component, Props)
|
37
src/Yoga/Block/Atom/Icon/Story.purs
Normal file
37
src/Yoga/Block/Atom/Icon/Story.purs
Normal file
@ -0,0 +1,37 @@
|
||||
module Yoga.Block.Atom.Icon.Story where
|
||||
|
||||
import Prelude
|
||||
import Effect (Effect)
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import React.Basic (JSX, element, fragment)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Emotion as E
|
||||
import Yoga.Block.Atom.Icon as Icon
|
||||
import Yoga.Block.Container.Style as Styles
|
||||
import Yoga.Block.Icon.SVG as SVGIcon
|
||||
|
||||
default ∷
|
||||
{ decorators ∷ Array (Effect JSX -> JSX)
|
||||
, title ∷ String
|
||||
}
|
||||
default =
|
||||
{ title: "Atom/Icon"
|
||||
, decorators:
|
||||
[ \storyFn ->
|
||||
R.div_
|
||||
[ element E.global { styles: Styles.global }
|
||||
, unsafePerformEffect storyFn
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
icon ∷ Effect JSX
|
||||
icon = do
|
||||
pure
|
||||
$ fragment
|
||||
[ R.div_
|
||||
[ R.h2_ [ R.text "Icon" ]
|
||||
, element Icon.component { icon: SVGIcon.on }
|
||||
, element Icon.component { icon: SVGIcon.off }
|
||||
]
|
||||
]
|
27
src/Yoga/Block/Atom/Icon/Style.purs
Normal file
27
src/Yoga/Block/Atom/Icon/Style.purs
Normal file
@ -0,0 +1,27 @@
|
||||
module Yoga.Block.Atom.Icon.Style where
|
||||
|
||||
import Yoga.Prelude.Style
|
||||
import Yoga.Block.Container.Style (colour)
|
||||
|
||||
type Props f r =
|
||||
( css ∷ f Style
|
||||
, colour ∷ f StyleProperty
|
||||
, stroke ∷ f StyleProperty
|
||||
, fill ∷ f StyleProperty
|
||||
, size ∷ f StyleProperty
|
||||
, width ∷ f StyleProperty
|
||||
, height ∷ f StyleProperty
|
||||
| r
|
||||
)
|
||||
|
||||
span ∷ ∀ r. { | Props OptionalProp r } -> Style
|
||||
span props =
|
||||
css
|
||||
{ "--stroke-colour": (props.stroke <|> props.colour) ?|| (str colour.text)
|
||||
, "--fill-colour": (props.fill <|> props.colour) ?|| (str "transparent")
|
||||
, "& > svg":
|
||||
nest
|
||||
{ width: (props.width <|> props.size) ?|| (str "auto")
|
||||
, height: (props.height <|> props.size) ?|| (str "1.2ch")
|
||||
}
|
||||
}
|
32
src/Yoga/Block/Atom/Icon/View.purs
Normal file
32
src/Yoga/Block/Atom/Icon/View.purs
Normal file
@ -0,0 +1,32 @@
|
||||
module Yoga.Block.Atom.Icon.View where
|
||||
|
||||
import Yoga.Prelude.View
|
||||
import React.Basic.DOM as R
|
||||
import Yoga.Block.Atom.Icon.Style as Style
|
||||
|
||||
type Props =
|
||||
PropsF Id
|
||||
|
||||
type MandatoryProps r =
|
||||
( icon ∷ JSX
|
||||
| r
|
||||
)
|
||||
|
||||
type PropsF f =
|
||||
( className ∷ f String
|
||||
| Style.Props f (MandatoryProps ())
|
||||
)
|
||||
|
||||
component ∷ ∀ p p_. Union p p_ Props => ReactComponent { | MandatoryProps p }
|
||||
component = rawComponent
|
||||
|
||||
rawComponent ∷ ∀ p. ReactComponent { | p }
|
||||
rawComponent =
|
||||
mkForwardRefComponent "Yoga Icon" \(props ∷ { | PropsF OptionalProp }) ref -> React.do
|
||||
pure
|
||||
$ styled R.span'
|
||||
{ className: "ry-icon" <>? props.className
|
||||
, css: Style.span props
|
||||
, ref
|
||||
}
|
||||
[ props.icon ]
|
5
src/Yoga/Block/Atom/Input.purs
Normal file
5
src/Yoga/Block/Atom/Input.purs
Normal file
@ -0,0 +1,5 @@
|
||||
module Yoga.Block.Atom.Input
|
||||
( module Yoga.Block.Atom.Input.View
|
||||
) where
|
||||
|
||||
import Yoga.Block.Atom.Input.View (component, Props)
|
56
src/Yoga/Block/Atom/Input/Story.purs
Normal file
56
src/Yoga/Block/Atom/Input/Story.purs
Normal file
@ -0,0 +1,56 @@
|
||||
module Yoga.Block.Atom.Input.Story where
|
||||
|
||||
import Prelude
|
||||
import Effect (Effect)
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import React.Basic (JSX, element, fragment)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Emotion as E
|
||||
import React.Basic.Events (handler_)
|
||||
import Yoga.Block.Atom.Input as Input
|
||||
import Yoga.Block.Container.Style as Styles
|
||||
|
||||
default ∷
|
||||
{ decorators ∷ Array (Effect JSX -> JSX)
|
||||
, title ∷ String
|
||||
}
|
||||
default =
|
||||
{ title: "Atom/Input"
|
||||
, decorators:
|
||||
[ \storyFn ->
|
||||
R.div_
|
||||
[ element E.global { styles: Styles.global }
|
||||
, unsafePerformEffect storyFn
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
input ∷ Effect JSX
|
||||
input = do
|
||||
pure
|
||||
$ fragment
|
||||
[ R.div_
|
||||
[ R.h2_ [ R.text "Generic Input" ]
|
||||
, element Input.component { value: "A Generic Input", onChange: handler_ mempty }
|
||||
, R.h2_ [ R.text "Password" ]
|
||||
, element Input.component { type: "password" }
|
||||
, R.h2_ [ R.text "Text Input" ]
|
||||
, element Input.component { type: "text", value: "Some text", onChange: handler_ mempty }
|
||||
, R.h2_ [ R.text "Search Input" ]
|
||||
, element Input.component { type: "search", value: "Search...", onChange: handler_ mempty }
|
||||
, R.h2_ [ R.text "Button" ]
|
||||
, element Input.component { type: "button", value: "A button", onChange: handler_ mempty }
|
||||
, R.h2_ [ R.text "Submit" ]
|
||||
, element Input.component { type: "submit" }
|
||||
, R.h2_ [ R.text "Radio" ]
|
||||
, element Input.component { type: "radio" }
|
||||
, R.h2_ [ R.text "Checkbox" ]
|
||||
, element Input.component { type: "checkbox" }
|
||||
, R.h2_ [ R.text "File" ]
|
||||
, element Input.component { type: "file" }
|
||||
, R.h2_ [ R.text "Image" ]
|
||||
, element Input.component { type: "image" }
|
||||
, R.h2_ [ R.text "Number" ]
|
||||
, element Input.component { type: "number" }
|
||||
]
|
||||
]
|
91
src/Yoga/Block/Atom/Input/Style.purs
Normal file
91
src/Yoga/Block/Atom/Input/Style.purs
Normal file
@ -0,0 +1,91 @@
|
||||
module Yoga.Block.Atom.Input.Style where
|
||||
|
||||
import Yoga.Prelude.Style
|
||||
import Yoga.Block.Container.Style (colour)
|
||||
import Yoga.Prelude.Style as Color
|
||||
|
||||
type Props f r =
|
||||
( css ∷ f Style
|
||||
| r
|
||||
)
|
||||
|
||||
leftIconSize ∷ StyleProperty
|
||||
leftIconSize = var "--left-icon-size"
|
||||
|
||||
rightIconSize ∷ StyleProperty
|
||||
rightIconSize = var "--right-icon-size"
|
||||
|
||||
leftIconStyle ∷ Style
|
||||
leftIconStyle =
|
||||
css
|
||||
{ "--stroke-colour": str colour.interfaceTextDisabled
|
||||
, marginTop: str "4px"
|
||||
, marginLeft: str "-4px"
|
||||
}
|
||||
|
||||
rightIconStyle ∷ Style
|
||||
rightIconStyle =
|
||||
css
|
||||
{ "--stroke-colour": str colour.interfaceTextDisabled
|
||||
, paddingTop: str "6px"
|
||||
, marginRight: str "6px"
|
||||
}
|
||||
|
||||
textWrapper ∷ ∀ r. { | Props OptionalProp r } -> Style
|
||||
textWrapper props =
|
||||
css
|
||||
{ fontFamily: var "--main-font"
|
||||
, boxSizing: borderBox
|
||||
, backgroundColor: str $ colour.background07
|
||||
, display: inlineFlex
|
||||
, "--left-icon-size": var "--s0"
|
||||
, "--right-icon-size": str "calc(var(--s0) * 1.2)"
|
||||
, alignItems: center
|
||||
, justifyContent: flexStart
|
||||
, paddingLeft: var "--s-1"
|
||||
, gap: var "--s-3"
|
||||
, "--border-width": var "--s-5"
|
||||
, border: str $ "var(--border-width) solid " <> colour.inputBorder
|
||||
, borderRadius: var "--s-1"
|
||||
, "&:focus-within":
|
||||
nest
|
||||
{}
|
||||
}
|
||||
|
||||
input ∷ ∀ r. { | Props OptionalProp r } -> Style
|
||||
input props =
|
||||
css
|
||||
{ "&[type=text],&[type=search],&[type=password],&[type=number],&:not([type])":
|
||||
nest
|
||||
{ color: str colour.text
|
||||
, background: str "transparent"
|
||||
, alignSelf: stretch
|
||||
, "--padding-top": str "var(--s-1)"
|
||||
, "--padding-bottom": str "calc(var(--padding-top) * 0.85)"
|
||||
, paddingTop: var "--padding-top"
|
||||
, paddingBottom: var "--padding-bottom"
|
||||
, paddingLeft: _0
|
||||
, paddingRight: _0
|
||||
-- , background: str colour.inputBackground
|
||||
, border: none
|
||||
}
|
||||
, "&[type=search]":
|
||||
nest
|
||||
{ "&::-webkit-search-decoration, &::-webkit-search-cancel-button, &::-webkit-serch-results-button, &::-webkit-search-results-decoration":
|
||||
nest
|
||||
{ "WebkitAppearance": none
|
||||
}
|
||||
}
|
||||
, "&:focus":
|
||||
nest
|
||||
{ outline: none
|
||||
}
|
||||
, "&[type=button], &[type=submit]":
|
||||
nest
|
||||
{ background: str colour.highlight
|
||||
, color: str "white"
|
||||
, boxShadow: str "0 1px 4px rgba(0,0,0,0.5)"
|
||||
, borderColour: str colour.highlight
|
||||
, height: str "auto"
|
||||
}
|
||||
}
|
142
src/Yoga/Block/Atom/Input/View.purs
Normal file
142
src/Yoga/Block/Atom/Input/View.purs
Normal file
@ -0,0 +1,142 @@
|
||||
module Yoga.Block.Atom.Input.View where
|
||||
|
||||
import Yoga.Prelude.View
|
||||
import Framer.Motion as M
|
||||
import React.Basic.DOM (css)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
import React.Basic.Hooks as React
|
||||
import Record.Extra (pick)
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Yoga.Block.Atom.Icon as Icon
|
||||
import Yoga.Block.Atom.Input.Style as Style
|
||||
import Yoga.Block.Atom.Tooltip as Tooltip
|
||||
import Yoga.Block.Icon.SVG as SVGIcon
|
||||
|
||||
type PropsF f =
|
||||
( iconLeft ∷ f JSX
|
||||
, iconRight ∷ f JSX
|
||||
| Style.Props f InputProps
|
||||
)
|
||||
|
||||
type Props =
|
||||
PropsF Id
|
||||
|
||||
type PropsOptional =
|
||||
PropsF OptionalProp
|
||||
|
||||
component ∷ ∀ p p_. Union p p_ Props => ReactComponent { | p }
|
||||
component = rawComponent
|
||||
|
||||
mkLeftIcon ∷ JSX -> JSX
|
||||
mkLeftIcon icon =
|
||||
styledLeaf
|
||||
Icon.component
|
||||
{ size: Style.leftIconSize
|
||||
, className: "ry-input-right-icon"
|
||||
, css: Style.leftIconStyle
|
||||
, icon
|
||||
}
|
||||
|
||||
mkRightIcon ∷ JSX -> JSX
|
||||
mkRightIcon icon =
|
||||
styledLeaf Icon.component
|
||||
{ size: Style.rightIconSize
|
||||
, className: "ry-input-left-icon"
|
||||
, css: Style.rightIconStyle
|
||||
, icon
|
||||
}
|
||||
|
||||
rawComponent ∷ ∀ p. ReactComponent { | p }
|
||||
rawComponent =
|
||||
mkForwardRefComponent "Input" do
|
||||
\(props ∷ { | PropsOptional }) ref -> React.do
|
||||
let
|
||||
iconLeft =
|
||||
props.iconLeft
|
||||
?|| if (((cast props.type) ?|| "") == "search") then mkLeftIcon SVGIcon.magnifyingGlass else mempty
|
||||
iconRight =
|
||||
props.iconRight
|
||||
?|| if (((cast props.type) ?|| "") == "password") then mkRightIcon SVGIcon.eyeOpen else mempty
|
||||
pure
|
||||
$ case props.type # cast # opToMaybe of
|
||||
Just "password" -> el_ password props
|
||||
_ ->
|
||||
styled R.div'
|
||||
{ className: "ry-input-wrapper"
|
||||
, css: Style.textWrapper props
|
||||
}
|
||||
[ iconLeft
|
||||
, emotionInput
|
||||
ref
|
||||
props
|
||||
{ className: "ry-input"
|
||||
, css: Style.input props
|
||||
}
|
||||
, iconRight
|
||||
]
|
||||
|
||||
password ∷ ∀ p. ReactComponent { | p }
|
||||
password =
|
||||
mkForwardRefComponent "Password" do
|
||||
\(props ∷ { | PropsOptional }) ref -> React.do
|
||||
hidePassword /\ modifyHidePassword <- useState true
|
||||
let
|
||||
eyeCon =
|
||||
el_ Tooltip.component
|
||||
{ target:
|
||||
el R.div'
|
||||
{ onClick: handler preventDefault \_ -> modifyHidePassword not
|
||||
}
|
||||
[ el M.animatePresence
|
||||
{ exitBeforeEnter: true
|
||||
}
|
||||
[ if hidePassword then
|
||||
el M.div
|
||||
{ key: "eyeOpen"
|
||||
, initial: M.initial $ css { scaleY: 0 }
|
||||
, animate: M.animate $ css { scaleY: 1 }
|
||||
, exit: M.exit $ css { scaleY: 0.9 }
|
||||
, transition: M.transition { duration: 0.15 }
|
||||
}
|
||||
[ styledLeaf Icon.component
|
||||
{ size: Style.rightIconSize
|
||||
, className: "ry-input-left-icon"
|
||||
, css: Style.rightIconStyle
|
||||
, icon: SVGIcon.eyeOpen
|
||||
}
|
||||
]
|
||||
else
|
||||
el M.div
|
||||
{ key: "eyeClosed"
|
||||
, initial: M.initial $ css { scaleY: 0.0 }
|
||||
, animate: M.animate $ css { scaleY: 1 }
|
||||
, exit: M.exit $ css { scaleY: 0.9 }
|
||||
, transition: M.transition { duration: 0.15 }
|
||||
}
|
||||
[ styledLeaf Icon.component
|
||||
{ size: Style.rightIconSize
|
||||
, className: "ry-input-left-icon"
|
||||
, css: Style.rightIconStyle
|
||||
, icon: SVGIcon.eyeClosed
|
||||
}
|
||||
]
|
||||
]
|
||||
]
|
||||
, theTip: R.text if hidePassword then "Show password" else "Hide password"
|
||||
}
|
||||
let iconRight = props.iconRight ?|| eyeCon
|
||||
pure
|
||||
$ styled R.div'
|
||||
{ className: "ry-input-wrapper"
|
||||
, css: Style.textWrapper props
|
||||
}
|
||||
[ emotionInput
|
||||
ref
|
||||
props
|
||||
{ className: "ry-input"
|
||||
, css: Style.input props
|
||||
, type: if hidePassword then "password" else "text"
|
||||
}
|
||||
, iconRight
|
||||
]
|
@ -6,8 +6,6 @@ import Yoga.Block.Container.Style (colour)
|
||||
|
||||
type Props f r =
|
||||
( css ∷ f Style
|
||||
, space ∷ f StyleProperty
|
||||
, splitAfter ∷ f Int
|
||||
| r
|
||||
)
|
||||
|
||||
|
@ -1,13 +1,15 @@
|
||||
module Yoga.Block.Atom.Range.View (component, Props, PropsF) where
|
||||
|
||||
import Yoga.Prelude.View
|
||||
import Yoga.Block.Atom.Range.Style as Style
|
||||
import Data.Int as Int
|
||||
import Foreign.Object as Object
|
||||
import Framer.Motion as M
|
||||
import React.Basic.DOM (css)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.Events as Event
|
||||
import React.Basic.Hooks as React
|
||||
import Yoga.Block.Atom.Range.Style as Style
|
||||
import Yoga.Block.Atom.Tooltip as Tooltip
|
||||
|
||||
type PropsF f =
|
||||
( className ∷ f String
|
||||
@ -58,11 +60,11 @@ rawComponent =
|
||||
{ className: "ry-range-focus-circle"
|
||||
, css: Style.focusCircle
|
||||
}
|
||||
, emotionInput ref (props { max = show max, min = show min, value = show value })
|
||||
, emotionInput
|
||||
ref
|
||||
(props { max = show max, min = show min, value = show value })
|
||||
{ className: "ry-range-thumb " <>? props.className
|
||||
, css: Style.range props <> guard props.disabled Style.inputDisabled <>? props.css
|
||||
, style: props.style
|
||||
, value: show value
|
||||
, type: "range"
|
||||
, onChange: handler Event.targetValue ((_ >>= Int.fromString) >>> (foldMap setValue))
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ module Yoga.Block.Atom.Toggle.Spec where
|
||||
|
||||
import Yoga.Prelude.Spec
|
||||
import Yoga.Block.Atom.Toggle as Toggle
|
||||
import Yoga.Block.Atom.Toggle.Types (TogglePosition(..))
|
||||
|
||||
spec ∷ Spec Unit
|
||||
spec =
|
||||
@ -10,6 +11,6 @@ spec =
|
||||
it "renders without errors" do
|
||||
void
|
||||
$ renderComponent Toggle.component
|
||||
{ value: true
|
||||
, onToggle: mempty
|
||||
{ togglePosition: ToggleIsLeft
|
||||
, setTogglePosition: mempty
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import React.Basic.DOM as R
|
||||
import React.Basic.Hooks as React
|
||||
import Yoga.Block as Block
|
||||
import Yoga.Block.Atom.Toggle as Toggle
|
||||
import Yoga.Block.Atom.Toggle.Types (TogglePosition(..))
|
||||
import Yoga.Block.Container.Style (DarkOrLightMode(..))
|
||||
|
||||
default ∷
|
||||
@ -35,30 +36,32 @@ toggle = do
|
||||
where
|
||||
mkBasicExample =
|
||||
React.reactComponent "Toggle example" \p -> React.do
|
||||
isOn /\ turnOnOrOff <- React.useState' false
|
||||
togglePosition /\ setTogglePosition <- React.useState' ToggleIsRight
|
||||
pure
|
||||
$ element Toggle.component
|
||||
{ value: isOn
|
||||
, onToggle: turnOnOrOff
|
||||
{ togglePosition
|
||||
, setTogglePosition
|
||||
}
|
||||
|
||||
mkDarkLightToggle =
|
||||
React.reactComponent "Toggle dark night example" \p -> React.do
|
||||
isOn /\ turnOnOrOff <- React.useState' false
|
||||
togglePosition /\ setTogglePosition <- React.useState' ToggleIsLeft
|
||||
theme /\ setTheme <- React.useState' Nothing
|
||||
let
|
||||
content =
|
||||
element Toggle.component
|
||||
{ value: isOn
|
||||
, onToggle:
|
||||
\b -> do
|
||||
turnOnOrOff b
|
||||
setTheme (Just if b then DarkMode else LightMode)
|
||||
, on: R.text "🌒"
|
||||
, off: R.text "🌞"
|
||||
, backgroundOn:
|
||||
Color.hsl 205.0 1.0 0.93
|
||||
, backgroundOff:
|
||||
{ togglePosition: togglePosition
|
||||
, setTogglePosition:
|
||||
\newTogglePosition -> do
|
||||
setTogglePosition newTogglePosition
|
||||
setTheme case newTogglePosition of
|
||||
ToggleIsRight -> Just DarkMode
|
||||
ToggleIsLeft -> Just LightMode
|
||||
, left: R.text "🌒"
|
||||
, right: R.text "🌞"
|
||||
, backgroundLeft:
|
||||
Color.hsl 205.0 1.0 0.83
|
||||
, backgroundRight:
|
||||
Color.hsl 260.0 0.7 0.45
|
||||
}
|
||||
pure
|
||||
|
@ -5,8 +5,8 @@ import Yoga.Block.Container.Style (colour)
|
||||
|
||||
type Props f r =
|
||||
( css ∷ f Style
|
||||
, backgroundOn ∷ f Color
|
||||
, backgroundOff ∷ f Color
|
||||
, backgroundLeft ∷ f Color
|
||||
, backgroundRight ∷ f Color
|
||||
| r
|
||||
)
|
||||
|
||||
@ -23,17 +23,17 @@ button =
|
||||
, padding: _0
|
||||
}
|
||||
|
||||
theToggle ∷ ∀ p. { | Props OptionalProp p } -> Style
|
||||
theToggle props =
|
||||
theToggle ∷ Style
|
||||
theToggle =
|
||||
css
|
||||
{ width: var "--s2"
|
||||
, height: var "--s2"
|
||||
{ width: str "calc(var(--s2) * 0.8)"
|
||||
, height: str "calc(var(--s2) * 0.8)"
|
||||
, background: str $ colour.interfaceBackground
|
||||
, border: none
|
||||
, borderRadius: str $ "calc(var(--s2) / 2)"
|
||||
, position: absolute
|
||||
, top: str "-1px"
|
||||
, left: _0
|
||||
, top: str "3px"
|
||||
, left: str "3px"
|
||||
, margin: _0
|
||||
, boxShadow: str "0 0.5px 3px rgba(0,0,0,0.50)"
|
||||
}
|
||||
@ -46,25 +46,33 @@ toggleTextContainer =
|
||||
, fontWeight: str "bold"
|
||||
, position: absolute
|
||||
, top: _0
|
||||
, fontSize: str "calc(0.6 * var(--s1))"
|
||||
, lineHeight: var "--s2"
|
||||
, height: var "--s2"
|
||||
, display: flex
|
||||
}
|
||||
|
||||
successTextColour ∷ StyleProperty
|
||||
successTextColour = str colour.successText
|
||||
|
||||
disabledTextColour ∷ StyleProperty
|
||||
disabledTextColour = str colour.interfaceTextDisabled
|
||||
|
||||
toggleText ∷ Style
|
||||
toggleText =
|
||||
css
|
||||
{ textAlign: str "left"
|
||||
, margin: _0
|
||||
, padding: _0
|
||||
, width: str "50%"
|
||||
, height: str "100%"
|
||||
, display: flex
|
||||
, justifyContent: center
|
||||
, alignItems: center
|
||||
, color: str colour.interfaceTextDisabled
|
||||
, "&:first-child":
|
||||
, color: disabledTextColour
|
||||
, "& > *":
|
||||
nest
|
||||
{ color: str colour.successText
|
||||
{ color: successTextColour
|
||||
}
|
||||
}
|
||||
|
||||
|
19
src/Yoga/Block/Atom/Toggle/Types.purs
Normal file
19
src/Yoga/Block/Atom/Toggle/Types.purs
Normal file
@ -0,0 +1,19 @@
|
||||
module Yoga.Block.Atom.Toggle.Types where
|
||||
|
||||
import Prelude
|
||||
|
||||
data TogglePosition
|
||||
= ToggleIsLeft
|
||||
| ToggleIsRight
|
||||
|
||||
derive instance eqTogglePosition ∷ Eq TogglePosition
|
||||
|
||||
instance showTogglePosition ∷ Show TogglePosition where
|
||||
show = case _ of
|
||||
ToggleIsLeft -> "ToggleIsLeft"
|
||||
ToggleIsRight -> "ToggleIsRight"
|
||||
|
||||
flipToggle ∷ TogglePosition -> TogglePosition
|
||||
flipToggle = case _ of
|
||||
ToggleIsLeft -> ToggleIsRight
|
||||
ToggleIsRight -> ToggleIsLeft
|
@ -3,26 +3,33 @@ module Yoga.Block.Atom.Toggle.View (component, MandatoryProps, Props, PropsF) wh
|
||||
import Yoga.Prelude.View
|
||||
import Color as Color
|
||||
import Data.Interpolate (i)
|
||||
import Data.Maybe (isNothing)
|
||||
import Effect.Class.Console as Console
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import Foreign.Object as Object
|
||||
import Framer.Motion as Motion
|
||||
import Partial.Unsafe (unsafeCrashWith)
|
||||
import React.Basic.DOM (css)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Emotion as Emotion
|
||||
import React.Basic.Hooks (reactComponent)
|
||||
import React.Basic.Hooks as React
|
||||
import Yoga.Block.Atom.Icon as Icon
|
||||
import Yoga.Block.Atom.Toggle.Style as Style
|
||||
import Yoga.Block.Atom.Toggle.Types (TogglePosition(..), flipToggle)
|
||||
import Yoga.Block.Container.Style (colour)
|
||||
import Yoga.Block.Icon.SVG as SVGIcon
|
||||
|
||||
type PropsF f =
|
||||
( className ∷ f String
|
||||
, on ∷ f JSX
|
||||
, off ∷ f JSX
|
||||
, left ∷ f JSX
|
||||
, right ∷ f JSX
|
||||
| Style.Props f (MandatoryProps InputProps)
|
||||
)
|
||||
|
||||
type MandatoryProps r =
|
||||
( value ∷ Boolean
|
||||
, onToggle ∷ Boolean -> Effect Unit
|
||||
( togglePosition ∷ TogglePosition
|
||||
, setTogglePosition ∷ TogglePosition -> Effect Unit
|
||||
| r
|
||||
)
|
||||
|
||||
@ -32,7 +39,7 @@ data TappingState
|
||||
|
||||
data DragState
|
||||
= NotDragging
|
||||
| Dragging { startX ∷ Number }
|
||||
| Dragging { startX ∷ Number, currentX ∷ Number }
|
||||
| DragDone { startX ∷ Number, endX ∷ Number }
|
||||
|
||||
derive instance eqDragState ∷ Eq DragState
|
||||
@ -40,8 +47,8 @@ derive instance eqDragState ∷ Eq DragState
|
||||
instance showDragState ∷ Show DragState where
|
||||
show = case _ of
|
||||
NotDragging -> "NotDragging"
|
||||
Dragging x -> "Dragging " <> (show x)
|
||||
DragDone x -> "DragDone " <> (show x)
|
||||
Dragging x -> "Dragging " <> show x
|
||||
DragDone x -> "DragDone " <> show x
|
||||
|
||||
type Props =
|
||||
PropsF Id
|
||||
@ -57,147 +64,213 @@ rawComponent =
|
||||
mkForwardRefComponent "Toggle" do
|
||||
\(props ∷ { | PropsOptional }) ref -> React.do
|
||||
let disabled = props.disabled
|
||||
tapState <- useRef TapNotAllowed
|
||||
dragState /\ setDragState <- React.useState' NotDragging
|
||||
maxLeft /\ setMaxLeft <- useState' 0.0
|
||||
buttonRef <- useRef null
|
||||
toggleRef <- useRef null
|
||||
leftState /\ setLeftState <- React.useState' 0.0
|
||||
let
|
||||
getWidth aRef = do
|
||||
bbox <- getBoundingBoxFromRef aRef
|
||||
pure $ bbox <#> _.width # fromMaybe 0.0
|
||||
buttonWidth = getWidth buttonRef
|
||||
toggleWidth = getWidth toggleRef
|
||||
useLayoutEffectAlways do
|
||||
when (maxLeft == 0.0) do
|
||||
bw <- buttonWidth
|
||||
tw <- toggleWidth
|
||||
setMaxLeft (bw - tw)
|
||||
mempty
|
||||
let
|
||||
toggleVariants =
|
||||
{ off: { x: 0.0 }
|
||||
, on: { x: maxLeft }
|
||||
}
|
||||
toggleVariant = Motion.makeVariantLabels toggleVariants
|
||||
buttonVariants =
|
||||
{ off: { backgroundColor: (Emotion.str <<< Color.cssStringRGBA <$> props.backgroundOn) ?|| Emotion.str colour.inputBackground }
|
||||
, on: { backgroundColor: (Emotion.str <<< Color.cssStringRGBA <$> props.backgroundOff) ?|| Emotion.str colour.success }
|
||||
}
|
||||
buttonVariant = Motion.makeVariantLabels buttonVariants
|
||||
hasFocus /\ setHasFocus <- useState' false
|
||||
tapState <- useRef TapNotAllowed
|
||||
dragState /\ setDragState <- React.useState' NotDragging
|
||||
useEffect dragState do
|
||||
case dragState of
|
||||
NotDragging -> mempty
|
||||
Dragging { startX } -> writeRef tapState TapNotAllowed
|
||||
Dragging { startX, currentX } -> do
|
||||
writeRef tapState TapNotAllowed
|
||||
DragDone { startX, endX } -> do
|
||||
maybeBbox <- getBoundingBoxFromRef buttonRef
|
||||
for_ maybeBbox \bbox -> do
|
||||
if endX - startX <= (bbox.left - startX) + (bbox.width / 2.0) then do
|
||||
props.onToggle false
|
||||
props.setTogglePosition ToggleIsLeft
|
||||
else do
|
||||
props.onToggle true
|
||||
props.setTogglePosition ToggleIsRight
|
||||
mempty
|
||||
pure
|
||||
$ styled Motion.button
|
||||
let
|
||||
buttonVariants =
|
||||
{ left: { backgroundColor: (Emotion.str <<< Color.cssStringRGBA <$> props.backgroundLeft) ?|| Emotion.str colour.inputBackground }
|
||||
, right: { backgroundColor: (Emotion.str <<< Color.cssStringRGBA <$> props.backgroundRight) ?|| Emotion.str colour.success }
|
||||
}
|
||||
buttonVariant = Motion.makeVariantLabels buttonVariants
|
||||
-- components
|
||||
let
|
||||
result =
|
||||
container
|
||||
[ animateTextPresence
|
||||
[ textContainer
|
||||
[ textOnContainer
|
||||
[ guard (props.togglePosition == ToggleIsRight)
|
||||
$ textOn
|
||||
[ props.left
|
||||
?|| el_ Icon.component { icon: SVGIcon.on, stroke: Style.successTextColour }
|
||||
]
|
||||
]
|
||||
, textOffContainer
|
||||
[ guard (props.togglePosition == ToggleIsLeft)
|
||||
$ textOff
|
||||
[ props.right
|
||||
?|| el_ Icon.component { icon: SVGIcon.off, stroke: Style.disabledTextColour }
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
, toggle
|
||||
]
|
||||
container =
|
||||
styled Motion.button
|
||||
{ className: "ry-toggle"
|
||||
, css: Style.button <> guard props.disabled Style.inputDisabled
|
||||
, onFocus: handler_ $ setHasFocus true
|
||||
, onBlur: handler_ $ setHasFocus false
|
||||
, css: Style.button
|
||||
, transition: Motion.transition { type: "tween", duration: 0.33, ease: "easeOut" }
|
||||
, variants: Motion.variants buttonVariants
|
||||
, animate: Motion.animate if props.value then buttonVariant.on else buttonVariant.off
|
||||
, value: show props.value
|
||||
, onClick: handler preventDefault \_ -> props.onToggle (not props.value)
|
||||
, animate:
|
||||
Motion.animate case props.togglePosition of
|
||||
ToggleIsRight -> buttonVariant.right
|
||||
ToggleIsLeft -> buttonVariant.left
|
||||
, value: show props.togglePosition
|
||||
, onClick: handler preventDefault \_ -> props.setTogglePosition (flipToggle props.togglePosition)
|
||||
, style: props.style
|
||||
, _data: Object.singleton "testid" "toggle-testid"
|
||||
, role: "switch"
|
||||
, _aria: Object.singleton "checked" "switch"
|
||||
, ref: buttonRef
|
||||
}
|
||||
[ styled R.div'
|
||||
{ className: "ry-toggle-text"
|
||||
, css: Style.toggleTextContainer
|
||||
}
|
||||
[ styled R.div'
|
||||
{ className: "ry-toggle-text-on"
|
||||
, css: Style.toggleText
|
||||
}
|
||||
[ el Motion.animatePresence {}
|
||||
[ guard (props.value)
|
||||
$ styled Motion.div
|
||||
{ className: "ry-toggle-text-on-container"
|
||||
, css: Style.toggleOnText
|
||||
, key: "ry-toggle-text-on-container"
|
||||
, initial: Motion.initial $ css { scale: 0, opacity: 0 }
|
||||
, animate: Motion.animate $ css { scale: 1, opacity: 1 }
|
||||
, exit: Motion.exit $ css { scale: 0, opacity: 0 }
|
||||
}
|
||||
[ props.on ?|| R.text "I" ]
|
||||
]
|
||||
]
|
||||
, styled R.div'
|
||||
{ className: "ry-toggle-text-off"
|
||||
, css: Style.toggleText
|
||||
}
|
||||
[ el Motion.animatePresence {}
|
||||
[ guard (not props.value)
|
||||
$ styled Motion.div
|
||||
{ className: "ry-toggle-text-on-container"
|
||||
, css: Style.toggleOnText
|
||||
, key: "ry-toggle-text-on-container"
|
||||
, initial: Motion.initial $ css { scale: 0, opacity: 0 }
|
||||
, animate: Motion.animate $ css { scale: 1, opacity: 1 }
|
||||
, exit: Motion.exit $ css { scale: 0, opacity: 0 }
|
||||
}
|
||||
[ props.off ?|| R.text "O" ]
|
||||
]
|
||||
]
|
||||
]
|
||||
, styled Motion.div
|
||||
textContainer =
|
||||
styled R.div'
|
||||
{ className: "ry-toggle-text"
|
||||
, css: Style.toggleTextContainer
|
||||
}
|
||||
textOnContainer =
|
||||
styled R.div'
|
||||
{ className: "ry-toggle-text-on"
|
||||
, css: Style.toggleText
|
||||
}
|
||||
textOffContainer =
|
||||
styled R.div'
|
||||
{ className: "ry-toggle-text-off"
|
||||
, css: Style.toggleText
|
||||
}
|
||||
textOn =
|
||||
el Motion.div
|
||||
{ className: "ry-toggle-text-container"
|
||||
, key: "ry-toggle-text-on-container"
|
||||
, initial: Motion.initial $ css { scale: 0, opacity: 0 }
|
||||
, animate: Motion.animate $ css { scale: 1, opacity: 1 }
|
||||
, exit: Motion.exit $ css { scale: 0, opacity: 0 }
|
||||
}
|
||||
textOff =
|
||||
el Motion.div
|
||||
{ className: "ry-toggle-text-container"
|
||||
, key: "ry-toggle-text-off-container"
|
||||
, initial: Motion.initial $ css { scale: 0, opacity: 0 }
|
||||
, animate: Motion.animate $ css { scale: 1, opacity: 1 }
|
||||
, exit: Motion.exit $ css { scale: 0, opacity: 0 }
|
||||
}
|
||||
animateTextPresence = el Motion.animatePresence {}
|
||||
toggle =
|
||||
el_ toggleCircle
|
||||
{ buttonRef
|
||||
, toggleRef
|
||||
, togglePosition: props.togglePosition
|
||||
, setTogglePosition: props.setTogglePosition
|
||||
, dragState
|
||||
, setDragState
|
||||
, tapState
|
||||
}
|
||||
pure result
|
||||
|
||||
toggleCircle ∷
|
||||
ReactComponent
|
||||
{ setTogglePosition ∷ TogglePosition -> Effect Unit
|
||||
, toggleRef ∷ NodeRef
|
||||
, buttonRef ∷ NodeRef
|
||||
, togglePosition ∷ TogglePosition
|
||||
, dragState ∷ DragState
|
||||
, setDragState ∷ DragState -> Effect Unit
|
||||
, tapState ∷ Ref TappingState
|
||||
}
|
||||
toggleCircle =
|
||||
unsafePerformEffect
|
||||
$ reactComponent "ToggleCircle" do
|
||||
\( { togglePosition
|
||||
, setTogglePosition
|
||||
, toggleRef
|
||||
, buttonRef
|
||||
, dragState
|
||||
, setDragState
|
||||
, tapState
|
||||
}
|
||||
) -> React.do
|
||||
maxLeft /\ setMaxLeft <- useState' Nothing
|
||||
useEffectAlways do
|
||||
when (maxLeft == Nothing) do
|
||||
runMaybeT_ do
|
||||
b <- getBoundingBoxFromRef buttonRef # MaybeT
|
||||
t <- getBoundingBoxFromRef toggleRef # MaybeT
|
||||
let ml = b.width - t.width - (2.0 * (t.left - b.left))
|
||||
setMaxLeft (Just ml) # lift
|
||||
mempty
|
||||
let
|
||||
toggleVariants =
|
||||
{ left: { x: 0.0 }
|
||||
, right: { x: maxLeft # fromMaybe 0.0 }
|
||||
}
|
||||
toggleVariant = Motion.makeVariantLabels toggleVariants
|
||||
pure
|
||||
$ styledLeaf Motion.div
|
||||
{ className: "ry-toggle-toggle"
|
||||
, css: Style.theToggle props
|
||||
, layout: Motion.layout true
|
||||
, onClick: handler stopPropagation mempty
|
||||
, onTouchStart: handler stopPropagation mempty
|
||||
, onTouchEnd: handler stopPropagation mempty
|
||||
, css: Style.theToggle
|
||||
, drag: Motion.drag "x"
|
||||
, dragMomentum: Motion.dragMomentum false
|
||||
, key: if isNothing maxLeft then "initialising" else "ready"
|
||||
, dragElastic: Motion.dragElastic false
|
||||
, dragConstraints:
|
||||
Motion.dragConstraints
|
||||
{ left: if props.value then negate maxLeft else zero
|
||||
, right: if props.value then zero else maxLeft
|
||||
{ left:
|
||||
case togglePosition of
|
||||
ToggleIsLeft -> zero
|
||||
ToggleIsRight -> negate (maxLeft # fromMaybe 0.0)
|
||||
, right:
|
||||
case togglePosition of
|
||||
ToggleIsRight -> zero
|
||||
ToggleIsLeft -> maxLeft # fromMaybe 0.0
|
||||
}
|
||||
, variants: Motion.variants toggleVariants
|
||||
, transition: Motion.transition { type: "tween", duration: 0.33, ease: "easeOut" }
|
||||
, whileTap: Motion.prop $ css { scale: 0.85, transition: { type: "tween", duration: 0.10, ease: "easeInOut" } }
|
||||
, whileTap: Motion.prop $ css { scale: 1.1, transition: { type: "tween", duration: 0.10, ease: "easeInOut" } }
|
||||
, onTapStart: Motion.onTapStart \_ _ -> writeRef tapState TapAllowed
|
||||
, onTap:
|
||||
Motion.onTap \_ pi -> do
|
||||
ts <- readRef tapState
|
||||
case ts of
|
||||
TapAllowed -> props.onToggle $ not props.value
|
||||
TapAllowed -> setTogglePosition (flipToggle togglePosition)
|
||||
_ -> mempty
|
||||
mempty
|
||||
, onTapCancel:
|
||||
Motion.onTapCancel \_ pi -> do
|
||||
writeRef tapState TapNotAllowed
|
||||
mempty
|
||||
, animate: Motion.animate if props.value then toggleVariant.on else toggleVariant.off
|
||||
, initial: Motion.initial false
|
||||
, animate:
|
||||
Motion.animate case togglePosition of
|
||||
ToggleIsLeft -> toggleVariant.left
|
||||
ToggleIsRight -> toggleVariant.right
|
||||
, onDragStart:
|
||||
Motion.onDragStart \_ pi -> do
|
||||
maybeBBox <- getBoundingBoxFromRef toggleRef
|
||||
let x = maybeBBox <#> \bbox -> bbox.left + (bbox.width / 2.0)
|
||||
setDragState $ Dragging { startX: x # fromMaybe pi.point.x }
|
||||
setDragState $ Dragging { startX: x # fromMaybe pi.point.x, currentX: pi.point.x }
|
||||
, onDrag:
|
||||
Motion.onDrag \_ pi -> do
|
||||
case dragState of
|
||||
Dragging { startX } -> do
|
||||
setDragState $ Dragging { startX, currentX: pi.point.x }
|
||||
other -> Console.warn $ i "Unexpected drag state " (show other) " in onDragEvent"
|
||||
, onDragEnd:
|
||||
Motion.onDragEnd \_ pi -> do
|
||||
case dragState of
|
||||
Dragging { startX } -> do
|
||||
maybeBBox <- getBoundingBoxFromRef toggleRef
|
||||
let x = maybeBBox <#> \bbox -> bbox.left + (bbox.width / 2.0)
|
||||
setDragState (DragDone { startX, endX: x # fromMaybe pi.point.x })
|
||||
setDragState (DragDone { startX, endX: x # fromMaybe' \_ -> unsafeCrashWith "shit" })
|
||||
other -> Console.warn $ i "Unexpected drag state " (show other) " in onDragEvent"
|
||||
, ref: toggleRef
|
||||
}
|
||||
[]
|
||||
]
|
||||
|
5
src/Yoga/Block/Atom/Tooltip.purs
Normal file
5
src/Yoga/Block/Atom/Tooltip.purs
Normal file
@ -0,0 +1,5 @@
|
||||
module Yoga.Block.Atom.Tooltip
|
||||
( module Yoga.Block.Atom.Tooltip.View
|
||||
) where
|
||||
|
||||
import Yoga.Block.Atom.Tooltip.View (component, Props)
|
16
src/Yoga/Block/Atom/Tooltip/Spec.purs
Normal file
16
src/Yoga/Block/Atom/Tooltip/Spec.purs
Normal file
@ -0,0 +1,16 @@
|
||||
module Yoga.Block.Atom.Tooltip.Spec where
|
||||
|
||||
import Yoga.Prelude.Spec
|
||||
import React.Basic.DOM as R
|
||||
import Yoga.Block.Atom.Tooltip as Tooltip
|
||||
|
||||
spec ∷ Spec Unit
|
||||
spec =
|
||||
after_ cleanup do
|
||||
describe "The tooltip" do
|
||||
it "renders without errors" do
|
||||
void
|
||||
$ renderComponent Tooltip.component
|
||||
{ theTip: R.text "Tip"
|
||||
, target: R.text "Target"
|
||||
}
|
39
src/Yoga/Block/Atom/Tooltip/Story.purs
Normal file
39
src/Yoga/Block/Atom/Tooltip/Story.purs
Normal file
@ -0,0 +1,39 @@
|
||||
module Yoga.Block.Atom.Tooltip.Story where
|
||||
|
||||
import Prelude
|
||||
import Effect (Effect)
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import React.Basic (JSX, element, fragment)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Emotion as E
|
||||
import Yoga (el)
|
||||
import Yoga.Block.Atom.Tooltip as Tooltip
|
||||
import Yoga.Block.Container.Style as Styles
|
||||
|
||||
default ∷
|
||||
{ decorators ∷ Array (Effect JSX -> JSX)
|
||||
, title ∷ String
|
||||
}
|
||||
default =
|
||||
{ title: "Atom/Tooltip"
|
||||
, decorators:
|
||||
[ \storyFn ->
|
||||
R.div_
|
||||
[ element E.global { styles: Styles.global }
|
||||
, unsafePerformEffect storyFn
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
tooltip ∷ Effect JSX
|
||||
tooltip = do
|
||||
pure
|
||||
$ fragment
|
||||
[ R.div_
|
||||
[ R.h2_ [ R.text "Basics" ]
|
||||
, element Tooltip.component
|
||||
{ theTip: R.text "Hi"
|
||||
, target: el R.button' {} [ R.text "Holzkop" ]
|
||||
}
|
||||
]
|
||||
]
|
57
src/Yoga/Block/Atom/Tooltip/Style.purs
Normal file
57
src/Yoga/Block/Atom/Tooltip/Style.purs
Normal file
@ -0,0 +1,57 @@
|
||||
module Yoga.Block.Atom.Tooltip.Style where
|
||||
|
||||
import Yoga.Prelude.Style
|
||||
import Yoga.Block.Container.Style (colour)
|
||||
|
||||
type Props f r =
|
||||
( css ∷ f Style
|
||||
, backgroundColour ∷ f Color
|
||||
| r
|
||||
)
|
||||
|
||||
backgroundColour ∷ String
|
||||
backgroundColour = colour.text
|
||||
|
||||
arrow ∷ ∀ r. { | Props OptionalProp r } -> Style
|
||||
arrow props =
|
||||
css
|
||||
{ position: str "absolute"
|
||||
, width: str "12px"
|
||||
, height: str "12px"
|
||||
, zIndex: str "0"
|
||||
, "&::before":
|
||||
nest
|
||||
{ position: str "absolute"
|
||||
, width: str "12px"
|
||||
, height: str "12px"
|
||||
, borderRadius: str "2px"
|
||||
, content: str "''"
|
||||
, transform: str "rotate(45deg)"
|
||||
, background: str $ (cssStringRGBA <$> props.backgroundColour) ?|| backgroundColour
|
||||
}
|
||||
}
|
||||
|
||||
content ∷ ∀ r. { | Props OptionalProp r } -> Style
|
||||
content props =
|
||||
css
|
||||
{ background: str $ (cssStringRGBA <$> props.backgroundColour) ?|| backgroundColour
|
||||
, minWidth: str "50px"
|
||||
, padding: str "6px"
|
||||
, zIndex: str "-1"
|
||||
, color: str colour.background0
|
||||
, boxShadow: str "0 1px 8px rgba(0,0,0,0.33)"
|
||||
, borderRadius: var "--s-2"
|
||||
}
|
||||
|
||||
popper ∷ Style
|
||||
popper =
|
||||
css
|
||||
{ "&[data-popper-placement^='top'] > * > .popper-arrow":
|
||||
nest { bottom: str "-4px" }
|
||||
, "&[data-popper-placement^='bottom'] > * > .popper-arrow":
|
||||
nest { top: str "-4px" }
|
||||
, "&[data-popper-placement^='left'] > * > .popper-arrow":
|
||||
nest { right: str "-4px" }
|
||||
, "&[data-popper-placement^='right'] > * > .popper-arrow":
|
||||
nest { left: str "-4px" }
|
||||
}
|
129
src/Yoga/Block/Atom/Tooltip/View.purs
Normal file
129
src/Yoga/Block/Atom/Tooltip/View.purs
Normal file
@ -0,0 +1,129 @@
|
||||
module Yoga.Block.Atom.Tooltip.View (component, MandatoryProps, Props, PropsF) where
|
||||
|
||||
import Yoga.Prelude.View
|
||||
import Debug.Trace (spy)
|
||||
import Effect.Aff (Milliseconds(..), delay)
|
||||
import Effect.Uncurried (mkEffectFn1)
|
||||
import Framer.Motion as Motion
|
||||
import React.Basic.DOM (css)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Hooks as React
|
||||
import React.Basic.Hooks.Aff (useAff)
|
||||
import React.Basic.Popper.Hook (usePopper)
|
||||
import React.Basic.Popper.Types (modifierArrow, modifierOffset, nullRef)
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Yoga.Block.Atom.Tooltip.Style as Style
|
||||
|
||||
type PropsF f =
|
||||
( className ∷ f String
|
||||
, hideDelay ∷ f Milliseconds
|
||||
| Style.Props f (MandatoryProps ())
|
||||
)
|
||||
|
||||
type MandatoryProps r =
|
||||
( theTip ∷ JSX
|
||||
, target ∷ JSX
|
||||
| r
|
||||
)
|
||||
|
||||
type Props =
|
||||
PropsF Id
|
||||
|
||||
type PropsOptional =
|
||||
PropsF OptionalProp
|
||||
|
||||
component ∷ ∀ p p_. Union p p_ Props => ReactComponent { | MandatoryProps p }
|
||||
component = rawComponent
|
||||
|
||||
rawComponent ∷ ∀ p. ReactComponent (Record p)
|
||||
rawComponent =
|
||||
mkForwardRefComponent "Tooltip" do
|
||||
\(props ∷ { | PropsOptional }) ref -> React.do
|
||||
-- Hooks
|
||||
referenceElement /\ setReferenceElement <- React.useState' nullRef
|
||||
popperElement /\ setPopperElement <- React.useState' nullRef
|
||||
arrowElement /\ setArrowElement <- React.useState' nullRef
|
||||
{ styles, attributes } <-
|
||||
usePopper referenceElement popperElement
|
||||
{ modifiers:
|
||||
[ modifierArrow arrowElement
|
||||
, modifierOffset { x: 0.0, y: 12.0 }
|
||||
]
|
||||
}
|
||||
visible /\ setVisible <- React.useState' false
|
||||
touching /\ setTouching <- React.useState' false
|
||||
hovering /\ setHovering <- React.useState' false
|
||||
useAff hovering do
|
||||
if hovering then
|
||||
setVisible true # liftEffect
|
||||
else do
|
||||
delay (props.hideDelay ?|| (0.0 # Milliseconds))
|
||||
setVisible false # liftEffect
|
||||
useAff touching do
|
||||
if touching then do
|
||||
let _ = spy "sausage" touching
|
||||
delay (1000.0 # Milliseconds)
|
||||
setVisible true # liftEffect
|
||||
else do
|
||||
delay (props.hideDelay ?|| (450.0 # Milliseconds))
|
||||
setVisible false # liftEffect
|
||||
-- Handlers
|
||||
let
|
||||
hoveredIn = setHovering true
|
||||
hoveredOut = setHovering false
|
||||
touchStarted = setTouching true
|
||||
touchEnded = setTouching false
|
||||
-- Elements
|
||||
let
|
||||
result =
|
||||
fragment
|
||||
$ [ refElem
|
||||
, popperEl
|
||||
[ animatePresence
|
||||
$ guard visible
|
||||
[ content
|
||||
[ props.theTip
|
||||
, arrow
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
animatePresence = el Motion.animatePresence { initial: false }
|
||||
content =
|
||||
styled Motion.div
|
||||
{ className: "popper-element-content"
|
||||
, css: Style.content props
|
||||
, initial: Motion.initial $ R.css { opacity: [ 1.0, 0.8, 0.0 ], scale: [ 1.0, 0.85 ] }
|
||||
, animate: Motion.animate $ R.css { opacity: [ 0.0, 0.3, 1.0 ], scale: [ 0.0, 1.05, 1.0, 0.98, 1.01, 1.0 ] }
|
||||
, exit: Motion.exit $ R.css { opacity: [ 1.0, 0.8, 0.0 ], scale: [ 1.0, 0.85 ] }
|
||||
, transition: Motion.transition { duration: 0.2 }
|
||||
, key: "container"
|
||||
}
|
||||
popperEl =
|
||||
styled R.div'
|
||||
{ className: "popper-element"
|
||||
, css: Style.popper
|
||||
, ref: unsafeCoerce (mkEffectFn1 setPopperElement)
|
||||
, style: styles.popper
|
||||
, _data: attributes.popper
|
||||
}
|
||||
arrow =
|
||||
styledLeaf R.div'
|
||||
{ className: "popper-arrow"
|
||||
, id: "arrow"
|
||||
, css: Style.arrow props
|
||||
, ref: unsafeCoerce (mkEffectFn1 setArrowElement)
|
||||
, style: styles.arrow
|
||||
, _data: attributes.arrow
|
||||
}
|
||||
refElem =
|
||||
element Motion.div
|
||||
{ ref: unsafeCoerce (mkEffectFn1 setReferenceElement)
|
||||
, style: css { display: "inline-block" }
|
||||
, children: [ props.target ]
|
||||
, onHoverStart: Motion.onHoverStart \_ _ -> hoveredIn
|
||||
, onHoverEnd: Motion.onHoverEnd \_ _ -> hoveredOut
|
||||
, onTouchStart: handler_ touchStarted
|
||||
, onTouchEnd: handler_ touchEnded
|
||||
}
|
||||
pure result
|
@ -50,7 +50,7 @@ mkGlobal maybeMode =
|
||||
, body:
|
||||
nested
|
||||
$ css
|
||||
{ fontFamily: str "var(--mainFont)"
|
||||
{ fontFamily: str "var(--main-font)"
|
||||
, background: str colour.background0
|
||||
, color: str colour.text
|
||||
, margin: str "0"
|
||||
@ -61,7 +61,7 @@ mkGlobal maybeMode =
|
||||
Just LightMode -> lightModeStyle
|
||||
, "pre,code":
|
||||
nest
|
||||
{ fontFamily: str "var(--monoFont)"
|
||||
{ fontFamily: str "var(--mono-font)"
|
||||
}
|
||||
, "h1,h2,h3,h4,h5":
|
||||
nest
|
||||
@ -76,7 +76,6 @@ mkGlobal maybeMode =
|
||||
$ css
|
||||
{ boxSizing: str "inherit"
|
||||
}
|
||||
, input
|
||||
, form:
|
||||
nested
|
||||
$ css
|
||||
@ -155,7 +154,7 @@ defaultColours =
|
||||
-- highlight = Color.rgb 0x10 0x45 0x4A
|
||||
darkBg = Color.rgb 0 0 0
|
||||
|
||||
lightBg = Color.rgb 255 255 255
|
||||
lightBg = Color.rgb 250 250 250
|
||||
|
||||
type FlatTheme a =
|
||||
{ background0 ∷ a
|
||||
@ -262,22 +261,8 @@ variables =
|
||||
fontVariables ∷ { main ∷ String, mono ∷ String } -> Style
|
||||
fontVariables { main, mono } =
|
||||
css
|
||||
{ "--mainFont": str $ main <> """, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""""
|
||||
, "--monoFont": str $ mono <> ", monospace, monospace"
|
||||
}
|
||||
|
||||
input ∷ StyleProperty
|
||||
input =
|
||||
nest
|
||||
{ backgroundColor: "var(--input-bg-col)" # str
|
||||
, padding: "5px" # str
|
||||
, border: str "1px solid var(--bg-col)"
|
||||
, borderRadius: "5px" # str
|
||||
, fontSize: "12px" # str
|
||||
, paddingBottom: "4px" # str
|
||||
, paddingLeft: "8px" # str
|
||||
, "&:disabled": nest { color: str "var(--input-text-col-disabled)" }
|
||||
, "&:focus": nested inputFocus
|
||||
{ "--main-font": str $ main <> """, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""""
|
||||
, "--mono-font": str $ mono <> ", monospace, monospace"
|
||||
}
|
||||
|
||||
-- Standalone style for storybook
|
||||
|
32
src/Yoga/Block/Icon/SVG/EyeClosed.purs
Normal file
32
src/Yoga/Block/Icon/SVG/EyeClosed.purs
Normal file
@ -0,0 +1,32 @@
|
||||
module Yoga.Block.Icon.SVG.EyeClosed where
|
||||
|
||||
import React.Basic (JSX)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
|
||||
eyeClosed ∷ JSX
|
||||
eyeClosed =
|
||||
SVG.svg
|
||||
{ viewBox: "0 0 100 100"
|
||||
, xmlns: "http://www.w3.org/2000/svg"
|
||||
, fillRule: "evenodd"
|
||||
, clipRule: "evenodd"
|
||||
, strokeLinejoin: "round"
|
||||
, strokeMiterlimit: "1.5"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ fill: "none"
|
||||
, d: "M0 0h100v100H0z"
|
||||
}
|
||||
, SVG.path
|
||||
{ d: "M5.492 63.902c-1.539-2.426-2.587-11.465-1.593-13.076.352.369 4.353-.86 4.732-.54 24.519 20.777 51.057 22.859 83.889.676.892-.603 2.312-1.948 3.567-.637.892 2.137 2.479 6.187 2.439 10.011-.858 3.046-4.013 8.107-6.554 10.666.091-3.033-1.654-9.054-2.787-11.919-1.169 1.053-4.237 3.361-5.557 4.507 2.021 6.439 3.704 10.343 4.342 13.77-1.418 2.716-6.433 6.382-8.172 6.837-.695-3.519-3.589-12.626-4.791-16.545-1.721 1.014-7.746 2.85-7.739 2.967.294 5.01 1.269 11.753 3.159 17.431-2.331 1.521-7.403 2.045-10.644 2.233-1.477-3.05-1.902-13.039-2.221-17.74-1.768.532-6.838.5-8.865.679-.682 5.829-.99 11.62-.47 17.094-2.634-.024-8.846-1.614-10.179-2.127-.34-.886.675-13.622.808-16.23-1.442-.074-7.906-2.268-8.801-2.513-.501 3.058-1.153 12.152-.578 14.598-1.516-.601-8.651-6.109-9.148-6.3-.617-3.543-.097-9.17.23-12.361-.919-.313-5.78-3.571-6.551-4.211-.87 8.919-.1 11.254.106 11.869-1.502-1.338-7.45-7.873-8.622-9.139z"
|
||||
, fill: "var(--stroke-colour)"
|
||||
}
|
||||
, SVG.path
|
||||
{ d: "M50.026 26.996c23.346 0 42.3 24.595 42.3 24.595s-18.954 17.592-42.3 17.592c-23.347 0-42.301-17.592-42.301-17.592s18.954-24.595 42.301-24.595z"
|
||||
, fill: "none"
|
||||
, stroke: "var(--stroke-colour)"
|
||||
, strokeWidth: "8"
|
||||
}
|
||||
]
|
||||
}
|
44
src/Yoga/Block/Icon/SVG/EyeOpen.purs
Normal file
44
src/Yoga/Block/Icon/SVG/EyeOpen.purs
Normal file
@ -0,0 +1,44 @@
|
||||
module Yoga.Block.Icon.SVG.EyeOpen where
|
||||
|
||||
import React.Basic (JSX)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
|
||||
eyeOpen ∷ JSX
|
||||
eyeOpen =
|
||||
SVG.svg
|
||||
{ viewBox: "0 0 100 100"
|
||||
, xmlns: "http://www.w3.org/2000/svg"
|
||||
, fillRule: "evenodd"
|
||||
, clipRule: "evenodd"
|
||||
, strokeLinejoin: "round"
|
||||
, strokeMiterlimit: "1.5"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ fill: "none"
|
||||
, d: "M0 0h100v100H0z"
|
||||
}
|
||||
, SVG.path
|
||||
{ d: "M50.173 21.996c23.346 0 42.3 27.978 42.3 27.978s-18.954 27.979-42.3 27.979c-23.346 0-42.301-27.979-42.301-27.979s18.955-27.978 42.301-27.978z"
|
||||
, fill: "none"
|
||||
, stroke: "var(--stroke-colour)"
|
||||
, strokeWidth: "8"
|
||||
}
|
||||
, SVG.circle
|
||||
{ cx: "49.963"
|
||||
, cy: "50.087"
|
||||
, r: "24.205"
|
||||
, fill: "none"
|
||||
, stroke: "var(--stroke-colour)"
|
||||
, strokeWidth: "6"
|
||||
}
|
||||
, SVG.circle
|
||||
{ cx: "49.963"
|
||||
, cy: "50.087"
|
||||
, r: "9.748"
|
||||
, fill: "var(--stroke-colour)"
|
||||
, stroke: "var(--stroke-colour)"
|
||||
, strokeWidth: "8"
|
||||
}
|
||||
]
|
||||
}
|
13
src/Yoga/Block/Icon/SVG/Icon.purs
Normal file
13
src/Yoga/Block/Icon/SVG/Icon.purs
Normal file
@ -0,0 +1,13 @@
|
||||
module Yoga.Block.Icon.SVG
|
||||
( module Yoga.Block.Icon.SVG.On
|
||||
, module Yoga.Block.Icon.SVG.Off
|
||||
, module Yoga.Block.Icon.SVG.MagnifyingGlass
|
||||
, module Yoga.Block.Icon.SVG.EyeClosed
|
||||
, module Yoga.Block.Icon.SVG.EyeOpen
|
||||
) where
|
||||
|
||||
import Yoga.Block.Icon.SVG.On (on)
|
||||
import Yoga.Block.Icon.SVG.Off (off)
|
||||
import Yoga.Block.Icon.SVG.MagnifyingGlass (magnifyingGlass)
|
||||
import Yoga.Block.Icon.SVG.EyeClosed (eyeClosed)
|
||||
import Yoga.Block.Icon.SVG.EyeOpen (eyeOpen)
|
36
src/Yoga/Block/Icon/SVG/MagnifyingGlass.purs
Normal file
36
src/Yoga/Block/Icon/SVG/MagnifyingGlass.purs
Normal file
@ -0,0 +1,36 @@
|
||||
module Yoga.Block.Icon.SVG.MagnifyingGlass where
|
||||
|
||||
import React.Basic (JSX)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
|
||||
magnifyingGlass ∷ JSX
|
||||
magnifyingGlass =
|
||||
SVG.svg
|
||||
{ viewBox: "0 0 100 100"
|
||||
, xmlns: "http://www.w3.org/2000/svg"
|
||||
, fillRule: "evenodd"
|
||||
, clipRule: "evenodd"
|
||||
, strokeLinejoin: "round"
|
||||
, strokeMiterlimit: "1.5"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ fill: "none"
|
||||
, d: "M0 0h100v100H0z"
|
||||
}
|
||||
, SVG.circle
|
||||
{ cx: "42.994"
|
||||
, cy: "42.837"
|
||||
, r: "30.313"
|
||||
, fill: "none"
|
||||
, stroke: "var(--stroke-colour)"
|
||||
, strokeWidth: "10"
|
||||
}
|
||||
, SVG.path
|
||||
{ d: "M66.723 66.665l24.062 24.062"
|
||||
, fill: "none"
|
||||
, stroke: "var(--stroke-colour)"
|
||||
, strokeWidth: "8"
|
||||
}
|
||||
]
|
||||
}
|
30
src/Yoga/Block/Icon/SVG/Off.purs
Normal file
30
src/Yoga/Block/Icon/SVG/Off.purs
Normal file
@ -0,0 +1,30 @@
|
||||
module Yoga.Block.Icon.SVG.Off where
|
||||
|
||||
import React.Basic (JSX)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
|
||||
off ∷ JSX
|
||||
off =
|
||||
SVG.svg
|
||||
{ viewBox: "0 0 100 100"
|
||||
, xmlns: "http://www.w3.org/2000/svg"
|
||||
, fillRule: "evenodd"
|
||||
, clipRule: "evenodd"
|
||||
, strokeLinejoin: "round"
|
||||
, strokeMiterlimit: "1.5"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ fill: "none"
|
||||
, d: "M0 0h100v100H0z"
|
||||
}
|
||||
, SVG.circle
|
||||
{ cx: "50"
|
||||
, cy: "50"
|
||||
, r: "37.808"
|
||||
, fill: "none"
|
||||
, stroke: "var(--stroke-colour)"
|
||||
, strokeWidth: "20"
|
||||
}
|
||||
]
|
||||
}
|
41
src/Yoga/Block/Icon/SVG/On.purs
Normal file
41
src/Yoga/Block/Icon/SVG/On.purs
Normal file
@ -0,0 +1,41 @@
|
||||
module Yoga.Block.Icon.SVG.On where
|
||||
|
||||
import React.Basic (JSX)
|
||||
-- import React.Basic.DOM as R
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
|
||||
on ∷ JSX
|
||||
on =
|
||||
SVG.svg
|
||||
{ viewBox: "0 0 100 100"
|
||||
, xmlns: "http://www.w3.org/2000/svg"
|
||||
, fillRule: "evenodd"
|
||||
, clipRule: "evenodd"
|
||||
, strokeLinejoin: "round"
|
||||
, strokeMiterlimit: "1.5"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ fill: "none"
|
||||
, d: "M0 0h100v100H0z"
|
||||
}
|
||||
, SVG.clipPath
|
||||
{ id: "a"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ d: "M0 0h100v100H0z"
|
||||
}
|
||||
]
|
||||
}
|
||||
, SVG.g
|
||||
{ clipPath: "url(#a)"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ d: "M50 1.921v96.261"
|
||||
, fill: "none"
|
||||
, stroke: "var(--stroke-colour)"
|
||||
, strokeWidth: "20"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
25
src/Yoga/Block/Icon/SVG/QuestionMark.purs
Normal file
25
src/Yoga/Block/Icon/SVG/QuestionMark.purs
Normal file
@ -0,0 +1,25 @@
|
||||
module Yoga.Block.Icon.SVG.QuestionMark where
|
||||
|
||||
import React.Basic (JSX)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.SVG as SVG
|
||||
|
||||
questionMark :: JSX
|
||||
questionMark = SVG.svg
|
||||
{ viewBox: "0 0 100 100"
|
||||
, xmlns: "http://www.w3.org/2000/svg"
|
||||
, fillRule: "evenodd"
|
||||
, clipRule: "evenodd"
|
||||
, strokeLinejoin: "round"
|
||||
, strokeMiterlimit: "2"
|
||||
, children:
|
||||
[ SVG.path
|
||||
{ fill: "none"
|
||||
, d: "M0 0h100v100H0z"
|
||||
}
|
||||
, SVG.path
|
||||
{ d: "M50 10.037c22.056 0 39.963 17.907 39.963 39.963S72.056 89.963 50 89.963 10.037 72.056 10.037 50 27.944 10.037 50 10.037zM48.871 77.03c2.87 0 5.326-2.384 5.351-5.351-.025-2.918-2.481-5.301-5.351-5.301-2.967 0-5.374 2.383-5.35 5.301-.024 2.967 2.383 5.351 5.35 5.351zm-4.255-15.176h8.098v-.632c.049-5.156 1.727-7.515 5.691-9.947 4.474-2.675 7.271-6.323 7.271-11.892 0-8.22-6.396-13.375-15.686-13.375-8.512 0-15.418 4.718-15.661 13.959h8.657c.219-4.572 3.526-6.761 6.955-6.761 3.721 0 6.713 2.481 6.713 6.299 0 3.405-2.262 5.739-5.205 7.587-4.304 2.676-6.785 5.375-6.833 14.13v.632z"
|
||||
, fill: "#333"
|
||||
}
|
||||
]
|
||||
}
|
1
src/Yoga/Block/Icon/SVG/eyeClosed.svg
Normal file
1
src/Yoga/Block/Icon/SVG/eyeClosed.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.5"><path fill="none" d="M0 0h100v100H0z"/><path d="M5.492 63.902c-1.539-2.426-2.587-11.465-1.593-13.076.352.369 4.353-.86 4.732-.54 24.519 20.777 51.057 22.859 83.889.676.892-.603 2.312-1.948 3.567-.637.892 2.137 2.479 6.187 2.439 10.011-.858 3.046-4.013 8.107-6.554 10.666.091-3.033-1.654-9.054-2.787-11.919-1.169 1.053-4.237 3.361-5.557 4.507 2.021 6.439 3.704 10.343 4.342 13.77-1.418 2.716-6.433 6.382-8.172 6.837-.695-3.519-3.589-12.626-4.791-16.545-1.721 1.014-7.746 2.85-7.739 2.967.294 5.01 1.269 11.753 3.159 17.431-2.331 1.521-7.403 2.045-10.644 2.233-1.477-3.05-1.902-13.039-2.221-17.74-1.768.532-6.838.5-8.865.679-.682 5.829-.99 11.62-.47 17.094-2.634-.024-8.846-1.614-10.179-2.127-.34-.886.675-13.622.808-16.23-1.442-.074-7.906-2.268-8.801-2.513-.501 3.058-1.153 12.152-.578 14.598-1.516-.601-8.651-6.109-9.148-6.3-.617-3.543-.097-9.17.23-12.361-.919-.313-5.78-3.571-6.551-4.211-.87 8.919-.1 11.254.106 11.869-1.502-1.338-7.45-7.873-8.622-9.139z" fill="#333"/><path d="M50.026 26.996c23.346 0 42.3 24.595 42.3 24.595s-18.954 17.592-42.3 17.592c-23.347 0-42.301-17.592-42.301-17.592s18.954-24.595 42.301-24.595z" fill="none" stroke="#333" stroke-width="8"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
src/Yoga/Block/Icon/SVG/eyeOpen.svg
Normal file
1
src/Yoga/Block/Icon/SVG/eyeOpen.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.5"><path fill="none" d="M0 0h100v100H0z"/><path d="M50.173 21.996c23.346 0 42.3 27.978 42.3 27.978s-18.954 27.979-42.3 27.979c-23.346 0-42.301-27.979-42.301-27.979s18.955-27.978 42.301-27.978z" fill="none" stroke="#333" stroke-width="8"/><circle cx="49.963" cy="50.087" r="24.205" fill="none" stroke="#333" stroke-width="6"/><circle cx="49.963" cy="50.087" r="9.748" fill="#333" stroke="#333" stroke-width="8"/></svg>
|
After Width: | Height: | Size: 564 B |
1
src/Yoga/Block/Icon/SVG/magnifyingGlass.svg
Normal file
1
src/Yoga/Block/Icon/SVG/magnifyingGlass.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.5"><path fill="none" d="M0 0h100v100H0z"/><circle cx="42.994" cy="42.837" r="30.313" fill="none" stroke="#333" stroke-width="10"/><path d="M66.723 66.665l24.062 24.062" fill="none" stroke="#333" stroke-width="8"/></svg>
|
After Width: | Height: | Size: 366 B |
1
src/Yoga/Block/Icon/SVG/off.svg
Normal file
1
src/Yoga/Block/Icon/SVG/off.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.5"><path fill="none" d="M0 0h100v100H0z"/><circle cx="50" cy="50" r="37.808" fill="none" stroke="#333" stroke-width="20"/></svg>
|
After Width: | Height: | Size: 275 B |
1
src/Yoga/Block/Icon/SVG/on.svg
Normal file
1
src/Yoga/Block/Icon/SVG/on.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.5"><path fill="none" d="M0 0h100v100H0z"/><clipPath id="a"><path d="M0 0h100v100H0z"/></clipPath><g clip-path="url(#a)"><path d="M50 1.921v96.261" fill="none" stroke="#333" stroke-width="20"/></g></svg>
|
After Width: | Height: | Size: 349 B |
1
src/Yoga/Block/Icon/SVG/questionMark.svg
Normal file
1
src/Yoga/Block/Icon/SVG/questionMark.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"><path fill="none" d="M0 0h100v100H0z"/><path d="M50 10.037c22.056 0 39.963 17.907 39.963 39.963S72.056 89.963 50 89.963 10.037 72.056 10.037 50 27.944 10.037 50 10.037zM48.871 77.03c2.87 0 5.326-2.384 5.351-5.351-.025-2.918-2.481-5.301-5.351-5.301-2.967 0-5.374 2.383-5.35 5.301-.024 2.967 2.383 5.351 5.35 5.351zm-4.255-15.176h8.098v-.632c.049-5.156 1.727-7.515 5.691-9.947 4.474-2.675 7.271-6.323 7.271-11.892 0-8.22-6.396-13.375-15.686-13.375-8.512 0-15.418 4.718-15.661 13.959h8.657c.219-4.572 3.526-6.761 6.955-6.761 3.721 0 6.713 2.481 6.713 6.299 0 3.405-2.262 5.739-5.205 7.587-4.304 2.676-6.785 5.375-6.833 14.13v.632z" fill="#333"/></svg>
|
After Width: | Height: | Size: 796 B |
@ -11,6 +11,7 @@ module Yoga.Prelude.Default
|
||||
, module Data.Foldable
|
||||
, module Data.FoldableWithIndex
|
||||
, module Data.FunctorWithIndex
|
||||
, runMaybeT_
|
||||
) where
|
||||
|
||||
import Prelude
|
||||
@ -25,3 +26,6 @@ import Data.Maybe (Maybe(..), fromMaybe, fromMaybe', isJust, maybe)
|
||||
import Data.Monoid (guard)
|
||||
import Effect (Effect)
|
||||
import Effect.Class (liftEffect)
|
||||
|
||||
runMaybeT_ ∷ ∀ f a. Functor f => MaybeT f a -> f Unit
|
||||
runMaybeT_ = void <<< runMaybeT
|
||||
|
46
yarn.lock
46
yarn.lock
@ -4854,25 +4854,23 @@ fragment-cache@^0.2.1:
|
||||
dependencies:
|
||||
map-cache "^0.2.2"
|
||||
|
||||
framer-motion@^2.7.0:
|
||||
version "2.9.5"
|
||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-2.9.5.tgz#bbb185325d531c57f494cf3f6cf7719fc2c225c7"
|
||||
integrity sha512-epSX4Co1YbDv0mjfHouuY0q361TpHE7WQzCp/xMTilxy4kXd+Z23uJzPVorfzbm1a/9q1Yu8T5bndaw65NI4Tg==
|
||||
framer-motion@^3.0.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-3.1.1.tgz#a8a779501213b7ce02cc35beb27621d73cc2f1e7"
|
||||
integrity sha512-Gm1QSb0xUxuhcPar5FIs5Ws+STrhLZ6XZf2Io8dVwFofe1OzwkL9asGFVu7z3y6WqC4Hvnxm7wsW5SBHlxZDYw==
|
||||
dependencies:
|
||||
framesync "^4.1.0"
|
||||
framesync "^5.0.0"
|
||||
hey-listen "^1.0.8"
|
||||
popmotion "9.0.0-rc.20"
|
||||
style-value-types "^3.1.9"
|
||||
popmotion "^9.0.2"
|
||||
style-value-types "^3.2.0"
|
||||
tslib "^1.10.0"
|
||||
optionalDependencies:
|
||||
"@emotion/is-prop-valid" "^0.8.2"
|
||||
|
||||
framesync@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/framesync/-/framesync-4.1.0.tgz#69a8db3ca432dc70d6a76ba882684a1497ef068a"
|
||||
integrity sha512-MmgZ4wCoeVxNbx2xp5hN/zPDCbLSKiDt4BbbslK7j/pM2lg5S0vhTNv1v8BCVb99JPIo6hXBFdwzU7Q4qcAaoQ==
|
||||
dependencies:
|
||||
hey-listen "^1.0.5"
|
||||
framesync@5.0.0, framesync@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/framesync/-/framesync-5.0.0.tgz#7de8caedf53ac441118e79680f1beb7391c328b6"
|
||||
integrity sha512-wd8t+JsQGisluSv1twiEeDv0aNGpavGb9q7xgIk9fGbcIWkNXF/KVtrjnOrCwBWJuiXxlJfNkcvGudsI32FxYA==
|
||||
|
||||
fresh@0.5.2:
|
||||
version "0.5.2"
|
||||
@ -5315,7 +5313,7 @@ he@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
hey-listen@^1.0.5, hey-listen@^1.0.8:
|
||||
hey-listen@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68"
|
||||
integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==
|
||||
@ -7489,14 +7487,14 @@ polished@^3.4.4:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.9.2"
|
||||
|
||||
popmotion@9.0.0-rc.20:
|
||||
version "9.0.0-rc.20"
|
||||
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.0-rc.20.tgz#f3550042ae31957b5416793ae8723200951ad39d"
|
||||
integrity sha512-f98sny03WuA+c8ckBjNNXotJD4G2utG/I3Q23NU69OEafrXtxxSukAaJBxzbtxwDvz3vtZK69pu9ojdkMoBNTg==
|
||||
popmotion@^9.0.2:
|
||||
version "9.0.2"
|
||||
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.2.tgz#477650c3b4af97161011809223d9ca6860f3a2b5"
|
||||
integrity sha512-WfSg8IfoUwYIP9uqeqbgncIsMHLAKWqebT2IP1aGAI6gdSJqTPy/H8NvP4ZyDtDCUCx5Yh3Pth/7iUJjIwR7LA==
|
||||
dependencies:
|
||||
framesync "^4.1.0"
|
||||
framesync "5.0.0"
|
||||
hey-listen "^1.0.8"
|
||||
style-value-types "^3.1.9"
|
||||
style-value-types "3.2.0"
|
||||
tslib "^1.10.0"
|
||||
|
||||
portfinder@^1.0.26:
|
||||
@ -9087,10 +9085,10 @@ style-loader@^1.2.1:
|
||||
loader-utils "^2.0.0"
|
||||
schema-utils "^2.7.0"
|
||||
|
||||
style-value-types@^3.1.9:
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-3.1.9.tgz#faf7da660d3f284ed695cff61ea197d85b9122cc"
|
||||
integrity sha512-050uqgB7WdvtgacoQKm+4EgKzJExVq0sieKBQQtJiU3Muh6MYcCp4T3M8+dfl6VOF2LR0NNwXBP1QYEed8DfIw==
|
||||
style-value-types@3.2.0, style-value-types@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-3.2.0.tgz#eb89cab1340823fa7876f3e289d29d99c92111bb"
|
||||
integrity sha512-ih0mGsrYYmVvdDi++/66O6BaQPRPRMQHoZevNNdMMcPlP/cH28Rnfsqf1UEba/Bwfuw9T8BmIMwbGdzsPwQKrQ==
|
||||
dependencies:
|
||||
hey-listen "^1.0.8"
|
||||
tslib "^1.10.0"
|
||||
|
Loading…
Reference in New Issue
Block a user