git.iko.soy/rowtype-yoga/ry-blocks
on main help sign in
More pretty
commitadf1cc55826bd1cd9d4990607457a1b48e86d783 authorMark Eibes <mark.eibes@gmail.com> dateTue 13 Apr 2021, 16:43 (6 years ago) parent24ac4cc
8 files changed+177−33
package.json+5−1 src/React/DndKit.js+4−2 src/React/DndKit.purs+79−14 src/Yoga/Block/Atom/Input/Style.purs+1−1 src/Yoga/Block/Atom/Input/View/Container.purs+12−8 src/Yoga/Block/Organism/Form.purs+32−3 src/Yoga/Block/Organism/Form/Validation.purs+3−4 yarn.lock+41
package.json+5−1
@@ -48,6 +48,10 @@
4848 "build-storybook": "build-storybook"
4949 },
5050 "dependencies": {
51+ "@dnd-kit/core": "^2.1.2",
52+ "@dnd-kit/modifiers": "^1.0.5",
53+ "@dnd-kit/sortable": "^2.0.1",
54+ "@dnd-kit/utilities": "^1.0.3",
5155 "@emotion/core": "^10.0.28",
5256 "@popperjs/core": "^2.6.0",
5357 "focus-trap-react": "^8.4.2",
@@ -57,4 +61,4 @@
5761 "react-popper": "^2.2.4",
5862 "react-syntax-highlighter": "^15.3.1"
5963 }
60−}
64+}
src/React/DndKit.js+4−2
@@ -2,8 +2,10 @@ const dndKitCore = require('@dnd-kit/core')
22const dndKitSortable = require('@dnd-kit/sortable')
33const dndKitModifiers = require('@dnd-kit/modifiers')
44const dndKitUtilities = require('@dnd-kit/utilities')
5−exports.dndContext = dndKitCore.DndContext
6−exports.sortableContext = dndKitSortable.SortableContext
5+exports.dndContextImpl = dndKitCore.DndContext
6+exports.closestCenter = dndKitCore.closestCenter
7+exports.closestCorners = dndKitCore.closestCorners
8+exports.sortableContextImpl = dndKitSortable.SortableContext
79exports.useSortableImpl = dndKitSortable.useSortable
810exports.arrayMoveImpl = dndKitSortable.arrayMove
911exports.restrictToHorizontalAxis = dndKitModifiers.restrictToHorizontalAxis
src/React/DndKit.purs+79−14
@@ -6,18 +6,42 @@ import Data.Maybe (Maybe)
66import Data.Nullable (Nullable, toMaybe)
77import Effect.Uncurried (EffectFn1, runEffectFn1)
88import Foreign (Foreign)
9+import Foreign.Object (Object)
10+import Foreign.Object as Object
11+import Prim.Row (class Union)
912import React.Basic (Ref)
1013import React.Basic.Events (EventFn, EventHandler, SyntheticEvent, unsafeEventFn)
1114import React.Basic.Hooks (Hook, JSX, ReactComponent, unsafeHook)
15+import Record.Builder as Builder
16+import Type.Prelude (Proxy(..))
1217import Unsafe.Coerce (unsafeCoerce)
1318import Web.DOM (Node)
1419
15−foreign import dndContext ∷
16− ReactComponent
17− { children ∷ Array JSX
18− , onDragEnd ∷ EventHandler
19− , modifiers ∷ Array Modifier
20− }
20+foreign import dndContextImpl ∷ ∀ props. ReactComponent { | props }
21+
22+type DndContextProps =
23+ ( children ∷ Array JSX
24+ , onDragEnd ∷ EventHandler
25+ , modifiers ∷ Array Modifier
26+ , sensors ∷ ∀ a. Array (SensorDescriptor a)
27+ , collisionDetection ∷ CollisionDetection
28+ -- , onDragStart: ?(event: DragStartEvent): void
29+ -- , onDragMove?(event: DragMoveEvent): void
30+ -- , onDragOver?(event: DragOverEvent): void
31+ -- , onDragEnd?(event: DragEndEvent): void
32+ -- , onDragCancel?(): void
33+ )
34+
35+foreign import data CollisionDetection ∷ Type
36+
37+foreign import closestCenter ∷ CollisionDetection
38+
39+foreign import closestCorners ∷ CollisionDetection
40+
41+foreign import data SensorDescriptor ∷ Type -> Type
42+
43+dndContext ∷ ∀ p q. Union p q DndContextProps => ReactComponent { | p }
44+dndContext = dndContextImpl
2145
2246active ∷ EventFn SyntheticEvent Draggable
2347active = unsafeEventFn \e -> (unsafeCoerce e).active
@@ -28,16 +52,21 @@ over = unsafeEventFn \e -> toMaybe (unsafeCoerce e).over
2852type Draggable =
2953 { id ∷ String }
3054
55+type SortableContextProps =
56+ ( children ∷ Array JSX
57+ , items ∷ Array String
58+ )
59+
3160-- | `items` is the sorted array of the unique ids associated to each sortable item
32−foreign import sortableContext ∷
33− ReactComponent
34− { children ∷ Array JSX
35− , items ∷ Array String
36− }
61+foreign import sortableContextImpl ∷ ∀ props. ReactComponent { | props }
62+
63+sortableContext ∷ ∀ p q. Union p q SortableContextProps => ReactComponent { | p }
64+sortableContext = sortableContextImpl
3765
3866useSortable ∷ SortableArgs -> Hook (UseSortable SortableArgs) SortableResult
3967useSortable args =
40− unsafeHook
68+ map toSortableResult
69+ $ unsafeHook
4170 $ runEffectFn1 useSortableImpl args
4271
4372foreign import data UseSortable ∷ Type -> Type -> Type
@@ -45,13 +74,13 @@ foreign import data UseSortable ∷ Type -> Type -> Type
4574foreign import useSortableImpl ∷
4675 EffectFn1
4776 SortableArgs
48− SortableResult
77+ SortableResultImpl
4978
5079type SortableArgs =
5180 { id ∷ String
5281 }
5382
54−type SortableResult =
83+type SortableResultImpl =
5584 { attributes ∷
5685 { "aria-describedby" ∷ String
5786 , "aria-pressed" ∷ String
@@ -68,6 +97,42 @@ type SortableResult =
6897 , transition ∷ Foreign
6998 }
7099
100+type SortableResult =
101+ { attributes ∷
102+ { _aria ∷ Object String
103+ , role ∷ String
104+ , tabIndex ∷ Int
105+ }
106+ , listeners ∷
107+ { onKeyDown ∷ EventHandler
108+ , onPointerDown ∷ EventHandler
109+ }
110+ , setNodeRef ∷ Ref (Nullable Node)
111+ , transform ∷ Foreign
112+ , transition ∷ Foreign
113+ }
114+
115+toSortableResult ∷ SortableResultImpl -> SortableResult
116+toSortableResult sri =
117+ Builder.build
118+ ( Builder.modify (Proxy ∷ _ "attributes")
119+ ( Builder.build
120+ ( Builder.delete
121+ (Proxy ∷ _ "aria-describedby")
122+ <<< Builder.delete (Proxy ∷ _ "aria-pressed")
123+ <<< Builder.delete (Proxy ∷ _ "aria-roledescription")
124+ <<< Builder.insert (Proxy ∷ _ "_aria")
125+ ( Object.fromHomogeneous
126+ { describedby: sri.attributes."aria-describedby"
127+ , pressed: sri.attributes."aria-pressed"
128+ , roledescription: sri.attributes."aria-roledescription"
129+ }
130+ )
131+ )
132+ )
133+ )
134+ sri
135+
71136foreign import data Modifier ∷ Type
72137
73138foreign import restrictToHorizontalAxis ∷ Modifier
src/Yoga/Block/Atom/Input/Style.purs+1−1
@@ -187,7 +187,7 @@ inputContainer props = theCss <>? props.css
187187 , """&[data-invalid="true"]""":
188188 nest
189189 { borderColor: str colour.invalid
190− , "--border-width": str "2px)"
190+ , "--border-width": str "2px"
191191 }
192192 , "&:focus-within":
193193 nest
src/Yoga/Block/Atom/Input/View/Container.purs+12−8
@@ -102,20 +102,24 @@ mkPath { width, height } = do
102102 , {- ⌜ -} p outerCornerBorder border
103103 ]
104104 outside =
105− [ {-⌜ -} p zero zero
106− , {-⌞ -} p zero heightWith2xBorder
105+ [ {-⌜ -} p topBorder topBorder
106+ , {-⌜ -} p topBorder topBorder
107+ , {-⌜ -} p topBorder topBorder
108+ , {-⌞ -} p topBorder heightWith2xBorder
107109 , {- . -} p (widthWith2xBorder * 0.25) heightWith2xBorder
108110 , {- . -} p (widthWith2xBorder * 0.5) heightWith2xBorder
109111 , {- . -} p (widthWith2xBorder * 0.75) heightWith2xBorder
110112 , {- ⌟-} p widthWith2xBorder heightWith2xBorder
111− , {- ⌝-} p widthWith2xBorder zero
112− , {- ^ -} p (widthWith2xBorder * 0.25) zero
113− , {- ^ -} p (widthWith2xBorder * 0.5) zero
114− , {- ^ -} p (widthWith2xBorder * 0.75) zero
115− , {-⌜ -} p zero zero
113+ , {- ⌝-} p widthWith2xBorder topBorder
114+ , {- ^ -} p (widthWith2xBorder * 0.25) topBorder
115+ , {- ^ -} p (widthWith2xBorder * 0.5) topBorder
116+ , {- ^ -} p (widthWith2xBorder * 0.75) topBorder
117+ , {-⌜ -} p topBorder topBorder
116118 ]
117119 inside <> outside <> (Array.reverse inside)
118120 where
121+ topBorder = -border - border
122+
119123 widthWith2xBorder = width + border + border
120124
121125 heightWith2xBorder = height + border + border
@@ -158,7 +162,7 @@ mkContainerVariants dimensions =
158162 where
159163 path = mkPath dimensions
160164
161− clipPathFocussed = 12 Array... (Array.length path) <#> \ln -> drawPathUntil dimensions ln path
165+ clipPathFocussed = 13 Array... (Array.length path) <#> \ln -> drawPathUntil dimensions ln path
162166
163167type Point =
164168 { x ∷ Number, y ∷ Number }
src/Yoga/Block/Organism/Form.purs+32−3
@@ -43,7 +43,9 @@ import React.Basic.DOM as R
4343import React.Basic.Emotion as E
4444import React.Basic.Hooks (reactComponent)
4545import React.Basic.Hooks as Hooks
46+import React.DndKit as Dnd
4647import Record (disjointUnion)
48+import Record.Builder as RB
4749import Unsafe.Coerce (unsafeCoerce)
4850import Yoga.Block as Block
4951import Yoga.Block.Atom.Input as Input
@@ -564,7 +566,10 @@ array { label, addLabel, defaultValue, editor } =
564566 wrapper children =
565567 [ Wrapper
566568 { key: Nothing
567− , wrap: Block.box </ { style: R.css { paddingTop: 0 } }
569+ , wrap:
570+ \kids ->
571+ Block.box </ { style: R.css { paddingTop: 0 } }
572+ /> kids
568573 , children
569574 }
570575 ]
@@ -606,10 +611,34 @@ array { label, addLabel, defaultValue, editor } =
606611 /> [ Block.button
607612 </ { onClick: handler preventDefault (const (onChange $ flip append [ defaultValue ]))
608613 }
609− /> [ R.text $ "+ " <> addLabel
610− ]
614+ /> [ R.text $ "+ " <> addLabel ]
611615 ]
612616 }
613617 )
614618 , validate: traverse (un FormBuilder editor props >>> _.validate) xs
615619 }
620+ where
621+ itemComponent =
622+ unsafePerformEffect
623+ $ reactComponent "Form Array" \(props ∷ { id ∷ String }) -> Hooks.do
624+ { attributes, listeners, setNodeRef, transform, transition } <- Dnd.useSortable { id: props.id }
625+ let
626+ style = R.css { transform: Dnd.cssToString, transition }
627+ attrs =
628+ RB.build
629+ ( RB.disjointUnion listeners
630+ >>> RB.disjointUnion attributes
631+ )
632+ { ref: setNodeRef, style }
633+ pure $ R.li'
634+ </ attrs
635+ /> []
636+
637+ arrayComponent =
638+ unsafePerformEffect
639+ $ reactComponent "Form Array" \(props ∷ { kids ∷ Array JSX }) -> React.do
640+ pure $ Dnd.dndContext </ {}
641+ /> [ Dnd.sortableContext
642+ </ {}
643+ /> props.kids
644+ ]
src/Yoga/Block/Organism/Form/Validation.purs+3−4
@@ -424,7 +424,7 @@ errorChild =
424424 E.css
425425 { fontSize: E.str "calc(var(--s0) * 0.8)"
426426 , fontWeight: E.str "400"
427− , height: E.str "calc(var(--s0) + var(--s-4))"
427+ , height: E.str "calc(var(--s0) + var(--s-3))"
428428 , margin: E.str "0 var(--s-1) 0 var(--s-1)"
429429 , overflow: E.str $ if expanded then "visible" else "hidden"
430430 }
@@ -442,9 +442,8 @@ errorChild =
442442 E.css
443443 { color: E.str colour.invalidText
444444 , background: E.str colour.invalid
445− , padding: E.str "4px"
446− , paddingTop: E.str "2px"
447− , borderRadius: E.str "0 0 8px 8px"
445+ , padding: E.str "var(--s-5) var(--s-3) var(--s-4) var(--s-3)"
446+ , borderRadius: E.str "0 0 var(--s-3) var(--s-3)"
448447 }
449448 }
450449 /> [ motionReadMore
yarn.lock+41
@@ -994,6 +994,47 @@
994994 resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
995995 integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==
996996
997+"@dnd-kit/accessibility@^2.0.0":
998+ version "2.0.0"
999+ resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-2.0.0.tgz#d1f265ebedde6a66b71bb69fd8bc900b5138a8e2"
1000+ integrity sha512-L0KOQnqFR0MJ/IwJIS1A0tvgr47LrWzclJy7wW5i8/3rkdixUzkiD78rYnX7TrFnFNtuEgVxiGSsX2oIlulmUg==
1001+ dependencies:
1002+ tslib "^2.0.0"
1003+
1004+"@dnd-kit/core@^2.0.0", "@dnd-kit/core@^2.1.0", "@dnd-kit/core@^2.1.2":
1005+ version "2.1.2"
1006+ resolved "https://registry.yarnpkg.com/@dnd-kit/core/-/core-2.1.2.tgz#08d1fede9dd4c5a0f084cc2b95a434813ee9fda7"
1007+ integrity sha512-mJFKQUWOWq/yuD3jfPON4DuwWVGN/eS8s7GX9I5GbjG3i7Udt8I6ij1ZFinISSTTZxNVdBBcRKO4ctRecDkNKA==
1008+ dependencies:
1009+ "@dnd-kit/accessibility" "^2.0.0"
1010+ "@dnd-kit/utilities" "^1.0.2"
1011+ tslib "^2.0.0"
1012+
1013+"@dnd-kit/modifiers@^1.0.5":
1014+ version "1.0.5"
1015+ resolved "https://registry.yarnpkg.com/@dnd-kit/modifiers/-/modifiers-1.0.5.tgz#207d071ba1715ab5a04aa0a7ba9197cd1d160961"
1016+ integrity sha512-MEy2a6rwCuQs0I7HYYgYGNwoI2F9QeIKdOWwnnDpsnJ+/d+W8MynTCdjrIYAc3yqwXg5dPpQJkSJMSpaHpt0Jw==
1017+ dependencies:
1018+ "@dnd-kit/core" "^2.0.0"
1019+ "@dnd-kit/utilities" "^1.0.3"
1020+ tslib "^2.0.0"
1021+
1022+"@dnd-kit/sortable@^2.0.1":
1023+ version "2.0.1"
1024+ resolved "https://registry.yarnpkg.com/@dnd-kit/sortable/-/sortable-2.0.1.tgz#27da1a4b8f4e248d794964c5fd8734b000be5791"
1025+ integrity sha512-HfrIKkIXu+lZge8rRALeELJJA7zhWHubU1bCBAnVgKRhPmPYomN4X6szG81uquSD9Fvq04qBbwyw+uuBp1aJJg==
1026+ dependencies:
1027+ "@dnd-kit/core" "^2.1.0"
1028+ "@dnd-kit/utilities" "^1.0.2"
1029+ tslib "^2.0.0"
1030+
1031+"@dnd-kit/utilities@^1.0.2", "@dnd-kit/utilities@^1.0.3":
1032+ version "1.0.3"
1033+ resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-1.0.3.tgz#9742d229a095bfd08d120b28657c936fb911237f"
1034+ integrity sha512-TlbsZ3pSiJ6jTDVuGDLY7yoHAjaiFyBWctxDslxAocUeCQVDlcpkGXcPtUKYyGczruUoYapsKlZS5rhLDR+RUg==
1035+ dependencies:
1036+ tslib "^2.0.0"
1037+
9971038"@emotion/cache@^10.0.27":
9981039 version "10.0.29"
9991040 resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"