git.iko.soy/rowtype-yoga/ry-blocks
on main help sign in
I have changed the code files
commit56087af264f39e890fa8deb7837a4a9eb5039763 authorMark Eibes <mark.eibes@gmail.com> dateMon 21 Nov 2022, 09:13 (4 years ago) parentc0c9705
12 files changed+267−304
.vscode/settings.json+1−1 src/Yoga/Block.purs+1−2 src/Yoga/Block/Atom/Modal.purs−5 src/Yoga/Block/Atom/Modal/Style.purs−15 src/Yoga/Block/Atom/Modal/View.purs−90 src/Yoga/Block/Molecule/Modal/Story.purs−79 src/Yoga/Block/Molecule/Modal/Style.purs+9−22 src/Yoga/Block/Molecule/Modal/View.purs+77−79 stories/Story/Yoga/Block/Atom/Range.purs+53 stories/Story/Yoga/Block/Atom/Segmented.purs+51 stories/Story/Yoga/Block/Atom/Toggle.purs+69 stories/Story/Yoga/Block/Atom/Modal.purs → stories/Story/Yoga/Block/Molecule/Modal.purs+6−11
.vscode/settings.json+1−1
@@ -1,6 +1,6 @@
11{
22 "editor.formatOnSave": true,
3− "workbench.colorTheme": "Espresso Soda",
3+ "workbench.colorTheme": "Halcyon",
44 "search.useGlobalIgnoreFiles": true,
55 "files.watcherExclude": {
66 "**/.spago/**": true,
src/Yoga/Block.purs+1−2
@@ -22,7 +22,7 @@ import Yoga.Block.Layout.Imposter as Imposter
2222import Yoga.Block.Layout.Sidebar as Sidebar
2323import Yoga.Block.Layout.Stack as Stack
2424import Yoga.Block.Layout.Switcher as Switcher
25−import Yoga.Block.Atom.Modal as Modal
25+import Yoga.Block.Molecule.Modal as Modal
2626import Yoga.Block.Molecule.ReadMore as ReadMore
2727import Yoga.Block.Quark.Layer as Layer
2828
@@ -207,4 +207,3 @@ toggle = Toggle.component
207207
208208readMore ∷ ∀ p q. Union p q ReadMore.Props ⇒ ReactComponent (Record p)
209209readMore = ReadMore.component
210−
src/Yoga/Block/Atom/Modal.pursdeleted−5
@@ -1,5 +0,0 @@
1−module Yoga.Block.Atom.Modal
2− ( module Yoga.Block.Atom.Modal.View
3− ) where
4−
5−import Yoga.Block.Atom.Modal.View (component, Props)
src/Yoga/Block/Atom/Modal/Style.pursdeleted−15
@@ -1,15 +0,0 @@
1−module Yoga.Block.Atom.Modal.Style where
2−
3−import Yoga.Prelude.Style
4−
5−clickAway ∷ Style
6−clickAway =
7− widthScreen
8− <> heightScreen
9− <> positionFixed
10− <> left zero
11− <> top zero
12− <> acceptClicks
13−
14−modal ∷ Style
15−modal = acceptClicks
src/Yoga/Block/Atom/Modal/View.pursdeleted−90
@@ -1,90 +0,0 @@
1−module Yoga.Block.Atom.Modal.View where
2−
3−import Yoga.Prelude.View
4−
5−import Effect.Unsafe (unsafePerformEffect)
6−import Fahrtwind.Style.Color.Background (background)
7−import Fahrtwind.Style.Color.Tailwind as TW
8−import Fahrtwind.Style.Color.Util (withAlpha)
9−import Framer.Motion as M
10−import React.Basic.DOM as R
11−import React.Basic.Hooks as React
12−import Yoga.Block.Atom.Modal.Style as Style
13−import Yoga.Block.Hook.UseRenderInPortal (useRenderInPortal)
14−import Yoga.Block.Layout.Centre.View as Centre
15−import Yoga.Block.Layout.Cover.View as Cover
16−import Yoga.Block.Quark.ClickAway.View as ClickAway
17−
18−type ModalIds = { clickAwayId ∷ String, modalContainerId ∷ String }
19−
20−type Props =
21− { hide ∷ Effect Unit
22− , isVisible ∷ Boolean
23− , content ∷ JSX
24− , allowClickAway ∷ Boolean
25− , clickAwayId ∷ String
26− , modalContainerId ∷ String
27− }
28−
29−component ∷ ReactComponent Props
30−component = unsafePerformEffect do
31− React.reactComponent "Modal" \props → React.do
32− let
33− { hide
34− , isVisible
35− , content
36− , allowClickAway
37− , clickAwayId
38− , modalContainerId
39− } = props
40− renderInPortal ← useRenderInPortal modalContainerId
41− let
42− child = div "ry-modal" Style.modal [ content ]
43− pure $ fragment
44− [ ClickAway.component </>
45− { css: background (TW.gray._900 # withAlpha 0.5)
46− , hide: if allowClickAway then hide else mempty
47− , isVisible
48− , clickAwayId
49− }
50− , renderInPortal
51− $ Cover.component
52− </ {}
53− />
54− [ Centre.component </ {} />
55− [ M.animatePresence </ {} />
56− [ guard isVisible
57− $ M.div
58− </
59− { key: "popOver"
60− , initial: M.initial
61− ( R.css
62− { opacity: 0.0
63− , scale: 0.3
64− }
65− )
66− , animate: M.animate
67− ( R.css
68− { opacity: 1
69− , scale: 1.0
70− , transition:
71− { duration: 0.4, type: "spring" }
72− }
73− )
74− , exit: M.exit
75− ( R.css
76− { opacity: 0
77− , scale: 0.3
78− , transition: { duration: 0.2 }
79− }
80− )
81− -- , onAnimationComplete
82− -- , onAnimationStart
83− -- , ref: motionRef
84− }
85− />
86− [ child ]
87− ]
88− ]
89− ]
90− ]
src/Yoga/Block/Molecule/Modal/Story.pursdeleted−79
@@ -1,79 +0,0 @@
1−module Yoga.Block.Molecule.Modal.Story where
2−
3−import Prelude
4−import Data.Foldable (foldMap)
5−import Data.Maybe (Maybe(..), isNothing)
6−import Data.String.NonEmpty.Internal (NonEmptyString(..))
7−import Data.Tuple.Nested ((/\))
8−import Effect (Effect)
9−import Effect.Unsafe (unsafePerformEffect)
10−import React.Basic (JSX, element, fragment)
11−import React.Basic.DOM as R
12−import React.Basic.Emotion as E
13−import React.Basic.Events (handler_)
14−import React.Basic.Hooks (reactComponent, useEffectAlways)
15−import React.Basic.Hooks as React
16−import Web.DOM (Element)
17−import Web.DOM.NonElementParentNode (getElementById)
18−import Web.HTML (window)
19−import Web.HTML.HTMLDocument (toNonElementParentNode)
20−import Web.HTML.Window (document)
21−import Yoga as Y
22−import Yoga.Block as Block
23−import Yoga.Block.Container.Style (colour)
24−import Yoga.Block.Container.Style as Styles
25−import Yoga.Block.Molecule.Modal as Modal
26−
27−default ∷
28− { decorators ∷ Array (Effect JSX -> JSX)
29− , title ∷ String
30− }
31−default =
32− { title: "Molecule/Modal"
33− , decorators:
34− [ \storyFn ->
35− R.div_
36− [ element E.global { styles: Styles.global }
37− , unsafePerformEffect storyFn
38− ]
39− ]
40− }
41−
42−modal ∷ Effect JSX
43−modal = do
44− pure $ React.element compo {}
45− where
46− compo =
47− unsafePerformEffect
48− $ reactComponent "Modal Story" \{} -> React.do
49− isOpen /\ setIsOpen <- React.useState' true
50− maybeModalElement /\ setModalElement <- React.useState' Nothing
51− useEffectAlways do
52− when (isNothing maybeModalElement) do
53− container <- getElementById "modal-container" =<< (map toNonElementParentNode $ document =<< window)
54− setModalElement container
55− mempty
56− pure
57− $ fragment
58− [ R.h2_ [ R.text "No Options" ]
59− , Y.el R.button'
60− { onClick: handler_ (setIsOpen true)
61− }
62− [ R.text "Show Modal"
63− ]
64− , R.div { id: "modal-container" }
65− , maybeModalElement
66− # foldMap \(modalElement ∷ Element) ->
67− element Modal.component
68− { content:
69− Block.box
70− { borderRadius: E.str "var(--s3)"
71− , background: colour.backgroundLayer1
72− , padding: E.str "var(--s3) var(--s2)"
73− }
74− [ Y.leaf Block.input { label: NonEmptyString "A label that should fit" } ]
75− , isOpen
76− , onDismiss: setIsOpen false
77− , target: modalElement
78− }
79− ]
src/Yoga/Block/Molecule/Modal/Style.purs+9−22
@@ -2,27 +2,14 @@ module Yoga.Block.Molecule.Modal.Style where
22
33import Yoga.Prelude.Style
44
5−type Props :: forall k. (Type -> k) -> Row k -> Row k
6−type Props f r =
7− ( css ∷ f Style
8− | r
9− )
5+clickAway ∷ Style
6+clickAway =
7+ widthScreen
8+ <> heightScreen
9+ <> positionFixed
10+ <> left zero
11+ <> top zero
12+ <> acceptClicks
1013
1114modal ∷ Style
12−modal = styles
13− where
14− styles =
15− css
16− {}
17−
18−clickaway ∷ Style
19−clickaway =
20− css
21− { width: 100.0 # vw
22− , height: 100.0 # vh
23− , position: fixed
24− , left: _0
25− , top: _0
26− , backdropFilter: str "blur(4px) brightness(80%)"
27− , zIndex: str "3"
28− }
15+modal = acceptClicks
src/Yoga/Block/Molecule/Modal/View.purs+77−79
@@ -1,92 +1,90 @@
1−module Yoga.Block.Molecule.Modal.View (component, Props) where
1+module Yoga.Block.Molecule.Modal.View where
22
33import Yoga.Prelude.View
4−import Data.Nullable as Nullable
4+
55import Effect.Unsafe (unsafePerformEffect)
6−import Framer.Motion (withMotion)
7−import Framer.Motion as Motion
8−import React.Basic.DOM (createPortal, css)
6+import Fahrtwind.Style.Color.Background (background)
7+import Fahrtwind.Style.Color.Tailwind as TW
8+import Fahrtwind.Style.Color.Util (withAlpha)
9+import Framer.Motion as M
910import React.Basic.DOM as R
10−import React.Basic.Emotion as Emotion
11−import React.Basic.Hooks (reactComponent)
1211import React.Basic.Hooks as React
13−import Web.DOM (Element)
14−import Yoga.Block.Hook.Key as KeyCode
15−import Yoga.Block.Hook.UseKeyDown (useKeyDown)
16−import Yoga.Block.Layout.Imposter as Imposter
1712import Yoga.Block.Molecule.Modal.Style as Style
13+import Yoga.Block.Hook.UseRenderInPortal (useRenderInPortal)
14+import Yoga.Block.Layout.Centre.View as Centre
15+import Yoga.Block.Layout.Cover.View as Cover
16+import Yoga.Block.Quark.ClickAway.View as ClickAway
17+
18+type ModalIds = { clickAwayId ∷ String, modalContainerId ∷ String }
1819
1920type Props =
20− { content ∷ JSX
21− , isOpen ∷ Boolean
22− , onDismiss ∷ Effect Unit
23− , target ∷ Element
24− | ()
21+ { hide ∷ Effect Unit
22+ , isVisible ∷ Boolean
23+ , content ∷ JSX
24+ , allowClickAway ∷ Boolean
25+ , clickAwayId ∷ String
26+ , modalContainerId ∷ String
2527 }
2628
2729component ∷ ReactComponent Props
28−component =
29− unsafePerformEffect
30− $ reactComponent "Modal Wrapper" \{ content, isOpen, onDismiss, target } -> React.do
31− useKeyDown $ \_ _ -> case _ of
32− KeyCode.Escape -> onDismiss
33− _ -> mempty
34− clickAwayRef <- React.useRef Nullable.null
35− let
36− toRender ∷ JSX
37− toRender =
38− R.div' </ {}
39− />
40− [ Motion.animatePresence </ {} /> [ guard isOpen $ element clickaway { theRef: clickAwayRef, onDismiss } ]
41− , Motion.animatePresence </ {} /> [ guard isOpen $ element window { clickAwayRef, onDismiss, content } ]
42− ]
43− pure (createPortal toRender target)
44−
45−clickaway ∷ ReactComponent { theRef ∷ Ref (Nullable Node), onDismiss ∷ Effect Unit }
46−clickaway =
47− unsafePerformEffect
48− $ reactComponent "Modal Clickaway" \{ theRef, onDismiss } -> React.do
49− pure $ Emotion.elementKeyed Motion.div
50− $
51− { key: "ry-modal-clickaway"
52− , onClick: handler_ onDismiss
53− , className: "ry-modal-clickaway"
54− , css: Style.clickaway
55− , initial: Motion.prop $ css { opacity: 0.0 }
56− , animate: Motion.prop $ css { opacity: 1.0 }
57− , exit: Motion.prop $ css { opacity: 0.0 }
58− , ref: theRef
59− }
60−
61−window ∷ ReactComponent { clickAwayRef ∷ NodeRef, content ∷ JSX, onDismiss ∷ Effect Unit }
62−window =
63− unsafePerformEffect
64− $ reactComponent "Modal Window" \{ clickAwayRef, content, onDismiss } -> React.do
65− imposterRef <- useRef null
66− pure
67− $ Emotion.element motionImposter
68− ( { className: "ry-modal-window"
69− , css: Style.modal
70− , ref: imposterRef
71− , onClick: handler_ onDismiss
72− , children:
73− [ Motion.div
74− </*
75− { className: "ry-modal"
76− , css: Style.modal
77− , drag: Motion.prop true
78− , dragMomentum: Motion.prop false
79− , dragConstraints: Motion.prop clickAwayRef
80− , onClick: handler stopPropagation mempty
30+component = unsafePerformEffect do
31+ React.reactComponent "Modal" \props → React.do
32+ let
33+ { hide
34+ , isVisible
35+ , content
36+ , allowClickAway
37+ , clickAwayId
38+ , modalContainerId
39+ } = props
40+ renderInPortal ← useRenderInPortal modalContainerId
41+ let
42+ child = div "ry-modal" Style.modal [ content ]
43+ pure $ fragment
44+ [ ClickAway.component </>
45+ { css: background (TW.gray._900 # withAlpha 0.5)
46+ , hide: if allowClickAway then hide else mempty
47+ , isVisible
48+ , clickAwayId
49+ }
50+ , renderInPortal
51+ $ Cover.component
52+ </ {}
53+ />
54+ [ Centre.component </ {} />
55+ [ M.animatePresence </ {} />
56+ [ guard isVisible
57+ $ M.div
58+ </
59+ { key: "popOver"
60+ , initial: M.initial
61+ ( R.css
62+ { opacity: 0.0
63+ , scale: 0.3
64+ }
65+ )
66+ , animate: M.animate
67+ ( R.css
68+ { opacity: 1
69+ , scale: 1.0
70+ , transition:
71+ { duration: 0.4, type: "spring" }
72+ }
73+ )
74+ , exit: M.exit
75+ ( R.css
76+ { opacity: 0
77+ , scale: 0.3
78+ , transition: { duration: 0.2 }
79+ }
80+ )
81+ -- , onAnimationComplete
82+ -- , onAnimationStart
83+ -- , ref: motionRef
8184 }
82− /> [ content ]
85+ />
86+ [ child ]
8387 ]
84− }
85− `withMotion`
86− { initial: css { transform: "translate(-50%, -50%) scale3d(0.1,0.1,0.1)", opacity: 0 }
87− , animate: css { transform: "translate(-50%, -50%) scale3d(1,1,1)", opacity: 1 }
88− , exit: css { transform: "translate(-50%, -50%) scale3d(0.1,0.1,0.1)", opacity: 0 }
89− }
90− )
91− where
92− motionImposter = unsafePerformEffect $ Motion.custom Imposter.component
88+ ]
89+ ]
90+ ]
stories/Story/Yoga/Block/Atom/Range.pursnew file+53
@@ -0,0 +1,53 @@
1+module Story.Yoga.Block.Atom.Range where
2+
3+import Prelude
4+import Yoga.Block.Container.Style as Styles
5+import Yoga.Block.Atom.Range as Range
6+import Effect (Effect)
7+import Effect.Unsafe (unsafePerformEffect)
8+import React.Basic (JSX, element, fragment)
9+import React.Basic.DOM (css)
10+import React.Basic.DOM as R
11+import React.Basic.Emotion as E
12+
13+default ∷
14+ { decorators ∷ Array (Effect JSX → JSX)
15+ , title ∷ String
16+ }
17+default =
18+ { title: "Atom/Range"
19+ , decorators:
20+ [ \storyFn →
21+ R.div_
22+ [ element E.global { styles: Styles.global }
23+ , unsafePerformEffect storyFn
24+ ]
25+ ]
26+ }
27+
28+range ∷ Effect JSX
29+range =
30+ pure
31+ $ fragment
32+ [ R.div_
33+ [ R.h2_ [ R.text "No Options" ]
34+ , element Range.component
35+ {}
36+ , R.h2_ [ R.text "Min and max" ]
37+ , element Range.component
38+ { min: 2
39+ , max: 10
40+ }
41+ , R.h2_ [ R.text "Controlled" ]
42+ , element Range.component
43+ { value: 88
44+ , style: css { width: "200px" }
45+ }
46+ , R.h2_ [ R.text "Disabled" ]
47+ , element Range.component
48+ { value: 88
49+ , style: css { width: "200px" }
50+ , disabled: true
51+ }
52+ ]
53+ ]
stories/Story/Yoga/Block/Atom/Segmented.pursnew file+51
@@ -0,0 +1,51 @@
1+module Story.Yoga.Block.Atom.Segmented where
2+
3+import Prelude
4+import Data.Tuple.Nested ((/\))
5+import Data.TwoOrMore (twoOrMore)
6+import Effect (Effect)
7+import Effect.Unsafe (unsafePerformEffect)
8+import React.Basic (JSX, element)
9+import React.Basic.DOM as R
10+import React.Basic.Emotion as E
11+import React.Basic.Hooks (reactComponent, useState')
12+import React.Basic.Hooks as React
13+import Yoga.Block.Atom.Segmented as Segmented
14+import Yoga.Block.Container.Style as Styles
15+
16+default ∷
17+ { decorators ∷ Array (Effect JSX → JSX)
18+ , title ∷ String
19+ }
20+default =
21+ { title: "Atom/Segmented"
22+ , decorators:
23+ [ \storyFn →
24+ R.div_
25+ [ element E.global { styles: Styles.global }
26+ , unsafePerformEffect storyFn
27+ ]
28+ ]
29+ }
30+
31+segmented ∷ Effect JSX
32+segmented = do
33+ demoComponent ← makeDemoComponent
34+ pure $ element demoComponent {}
35+ where
36+ makeDemoComponent =
37+ reactComponent "Segmented Demo" \{} → React.do
38+ activeIndex /\ setElementIndex ← useState' 2
39+ pure
40+ $ element Segmented.component
41+ { activeIndex
42+ , updateActiveItem: const setElementIndex
43+ , buttonContents:
44+ twoOrMore
45+ { id: "gag", value: "2" }
46+ { id: "nag", value: "1" }
47+ [ { id: "two", value: "Another option" }
48+ , { id: "four", value: "2" }
49+ , { id: "one", value: "1" }
50+ ]
51+ }
stories/Story/Yoga/Block/Atom/Toggle.pursnew file+69
@@ -0,0 +1,69 @@
1+module Story.Yoga.Block.Atom.Toggle where
2+
3+import Prelude
4+import Color as Color
5+import Data.Maybe (Maybe(..))
6+import Data.Tuple.Nested ((/\))
7+import Effect (Effect)
8+import React.Basic (JSX, element, fragment)
9+import React.Basic.DOM as R
10+import React.Basic.Hooks as React
11+import Yoga ((/>), (</))
12+import Yoga.Block as Block
13+import Yoga.Block.Atom.Toggle as Toggle
14+import Yoga.Block.Atom.Toggle.Types (TogglePosition(..))
15+import Yoga.Block.Container.Style (DarkOrLightMode(..))
16+
17+default ∷ { title ∷ String }
18+default = { title: "Atom/Toggle" }
19+
20+toggle ∷ Effect JSX
21+toggle = do
22+ example ← mkBasicExample
23+ darkLight ← mkDarkLightToggle
24+ pure
25+ $ fragment
26+ [ R.div_
27+ [ R.h2_ [ R.text "Basics" ]
28+ , element example {}
29+ , R.h2_ [ R.text "Dark Light toggle" ]
30+ , element darkLight {}
31+ ]
32+ ]
33+ where
34+ mkBasicExample =
35+ React.reactComponent "Toggle example" \_p → React.do
36+ togglePosition /\ setTogglePosition ← React.useState' ToggleIsRight
37+ pure
38+ $ element Toggle.component
39+ { value: togglePosition
40+ , onChange: setTogglePosition
41+ , ariaLabel: "dark-light-toggle"
42+ }
43+
44+ mkDarkLightToggle =
45+ React.reactComponent "Toggle dark night example" \_p → React.do
46+ togglePosition /\ setTogglePosition ← React.useState' ToggleIsLeft
47+ theme /\ setTheme ← React.useState' Nothing
48+ let
49+ content =
50+ element Toggle.component
51+ { value: togglePosition
52+ , ariaLabel: "dark-light-toggle"
53+ , onChange:
54+ \newTogglePosition → do
55+ setTogglePosition newTogglePosition
56+ setTheme case newTogglePosition of
57+ ToggleIsRight → Just DarkMode
58+ ToggleIsLeft → Just LightMode
59+ , left: R.text "🌒"
60+ , right: R.text "🌞"
61+ , backgroundLeft:
62+ Color.hsl 205.0 1.0 0.83
63+ , backgroundRight:
64+ Color.hsl 260.0 0.7 0.45
65+ }
66+ pure
67+ $ Block.container
68+ </ { themeVariant: theme }
69+ /> [ content ]
stories/Story/Yoga/Block/Atom/Modal.purs → stories/Story/Yoga/Block/Molecule/Modal.pursrenamed+6−11
@@ -1,32 +1,27 @@
1−module Story.Yoga.Block.Atom.Modal.Story (default, modal) where
1+module Story.Yoga.Block.Molecule.Modal.Story (default, modal) where
22
33import Prelude
44
5−import Data.Monoid (guard)
65import Data.Tuple.Nested ((/\))
76import Effect (Effect)
8−import Effect.Unsafe (unsafePerformEffect)
9−import Fahrtwind (background', mXY, pXY, roundedLg, textXl)
7+import Fahrtwind (background', mXY, roundedLg, textXl)
108import React.Basic (JSX, element, fragment)
11−import React.Basic as React
129import React.Basic.DOM as R
1310import React.Basic.Emotion as E
1411import React.Basic.Events (handler_)
15−import React.Basic.Hooks as React
16−import Record (merge)
12+import React.Basic.Hooks (bind, component, element, useState') as React
1713import Storybook (Meta, meta, metaDecorator)
18−import Storybook.Addon.Actions (action)
1914import Yoga ((/>), (</*), (</>))
2015import Yoga.Block as Block
21−import Yoga.Block.Atom.Modal as Modal
22−import Yoga.Block.Container.Style (col, colour)
16+import Yoga.Block.Molecule.Modal as Modal
17+import Yoga.Block.Container.Style (col)
2318import Yoga.Block.Container.Style as Styles
2419import Yoga.Block.Icon.SVG as SVGIcon
2520import Yoga.Block.Layout.Types (JustifyContent(..))
2621
2722default ∷ Meta Modal.Props
2823default = meta
29− { title: "Atom/Modal"
24+ { title: "Molecule/Modal"
3025 , component: (pure <<< React.element) Modal.component
3126 , decorators:
3227 [ metaDecorator \storyFn →