mirror of
https://github.com/rowtype-yoga/ry-blocks.git
synced 2024-08-18 01:30:31 +03:00
Updates
This commit is contained in:
parent
371b0e437f
commit
12380cadc4
3
.idea/.gitignore
vendored
Normal file
3
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
6
.idea/misc.xml
Normal file
6
.idea/misc.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/ry-blocks.iml" filepath="$PROJECT_DIR$/.idea/ry-blocks.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
9
.idea/ry-blocks.iml
Normal file
9
.idea/ry-blocks.iml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -1 +0,0 @@
|
||||
import Prelude
|
21
README.md
21
README.md
@ -1,3 +1,24 @@
|
||||
# PureScript Yoga Blocks
|
||||
|
||||
> *Ring the bells that still can ring*</br>
|
||||
> *Forget your perfect offering*</br>
|
||||
> *There is a crack in everything*</br>
|
||||
> *That's how the light gets in* *<span style="float: right"> — Leonard Cohen, Anthem </span>*
|
||||
|
||||
## Digital User Interfaces
|
||||
|
||||
### Producing information
|
||||
|
||||
- Familiar
|
||||
- Intuitive
|
||||
- Quick
|
||||
- Clear (not confusing)
|
||||
|
||||
### Creating and changing information
|
||||
|
||||
- Familiar
|
||||
- Intuitive
|
||||
|
||||
## Adding new icons
|
||||
|
||||
Place the svg in `src/Yoga/Blocks/Icon/SVG
|
||||
|
@ -1,43 +0,0 @@
|
||||
module React.Downshift where
|
||||
|
||||
import Prelude
|
||||
import Data.Maybe (Maybe)
|
||||
import Effect (Effect)
|
||||
import Effect.Uncurried (runEffectFn1)
|
||||
import Prim.Row (class Union)
|
||||
import React.Basic.Hooks (Hook, unsafeHook)
|
||||
import React.Downshift.Internal (useSelectImpl)
|
||||
import React.Downshift.Types (UseSelectDataImpl, UseSelectPropsImpl)
|
||||
import React.Downshift.Types.StateChangeType (StateChangeType)
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Yoga.Block.Internal (OptionalProp, Id)
|
||||
|
||||
type UseSelectPropsR f a =
|
||||
( items ∷ Array a
|
||||
, itemToString ∷ f (a -> String)
|
||||
, onSelectedItemChange ∷ f ({ type ∷ StateChangeType, selectedItem ∷ Maybe a } -> Effect Unit)
|
||||
)
|
||||
|
||||
type UseSelectProps f a =
|
||||
Record (UseSelectPropsR f a)
|
||||
|
||||
type UseSelectData a =
|
||||
UseSelectDataImpl a
|
||||
|
||||
-- https://gist.github.com/reactormonk/974797077929efd5ae899b9e8eaac65d
|
||||
useSelect ∷ ∀ a p q. Union p q (UseSelectPropsR Id a) => { items ∷ Array a | p } -> Hook (UseSelect a) (UseSelectData a)
|
||||
useSelect props =
|
||||
map toUseSelectData
|
||||
$ unsafeHook
|
||||
$ runEffectFn1 useSelectImpl (toUseSelectProps props)
|
||||
|
||||
toUseSelectData ∷ ∀ a. UseSelectDataImpl a -> UseSelectData a
|
||||
toUseSelectData = identity
|
||||
|
||||
toUseSelectProps ∷ ∀ a. ∀ p q. Union p q (UseSelectPropsR Id a) => { items ∷ Array a | p } -> UseSelectPropsImpl a
|
||||
toUseSelectProps realProps = unsafeCoerce props
|
||||
where
|
||||
props ∷ { | UseSelectPropsR OptionalProp a }
|
||||
props = unsafeCoerce realProps
|
||||
|
||||
foreign import data UseSelect ∷ Type -> Type -> Type
|
@ -1,2 +0,0 @@
|
||||
import { useSelect } from "downshift"
|
||||
export const useSelectImpl = useSelect
|
@ -1,10 +0,0 @@
|
||||
module React.Downshift.Internal where
|
||||
|
||||
import Effect.Uncurried (EffectFn1)
|
||||
import React.Downshift.Types (UseSelectPropsImpl, UseSelectDataImpl)
|
||||
|
||||
foreign import useSelectImpl
|
||||
∷ ∀ a
|
||||
. EffectFn1
|
||||
(UseSelectPropsImpl a)
|
||||
(UseSelectDataImpl a)
|
@ -1,54 +0,0 @@
|
||||
module React.Downshift.Types where
|
||||
|
||||
import Prelude
|
||||
import Data.Nullable (Nullable)
|
||||
import Effect (Effect)
|
||||
import Effect.Uncurried (EffectFn1)
|
||||
import Foreign (Foreign)
|
||||
import React.Downshift.Types.StateChangeType (StateChangeType)
|
||||
|
||||
type UseSelectDataImpl a =
|
||||
{ isOpen ∷ Boolean
|
||||
, selectedItem ∷ a
|
||||
, closeMenu ∷ Effect Unit
|
||||
, getItemProps ∷ { item ∷ a, index ∷ Int } -> Foreign
|
||||
, getLabelProps ∷ Foreign --ƒ (labelProps)
|
||||
, getMenuProps ∷ Foreign -- ƒ (_temp, _temp2)
|
||||
, getToggleButtonProps ∷ Foreign -- ƒ (_temp3, _temp4)
|
||||
, highlightedIndex ∷ Int
|
||||
, inputValue ∷ String
|
||||
, isOpen ∷ Boolean
|
||||
, openMenu ∷ Effect Unit
|
||||
, reset ∷ Effect Unit
|
||||
, selectItem ∷ EffectFn1 a Unit
|
||||
, selectedItem ∷ Nullable a
|
||||
, setHighlightedIndex ∷ EffectFn1 Int Unit
|
||||
, setInputValue ∷ EffectFn1 String Unit
|
||||
, toggleMenu ∷ Effect Unit
|
||||
}
|
||||
|
||||
type A11yMessageInfoImpl a =
|
||||
{ highlightedIndex ∷ Int
|
||||
, highlightedItem ∷ Nullable a
|
||||
, inputValue ∷ String
|
||||
, isOpen ∷ Boolean
|
||||
, itemToString ∷ a -> String
|
||||
, previousResultCount ∷ Int
|
||||
, resultCount ∷ Int
|
||||
, selectedItem ∷ Nullable a
|
||||
}
|
||||
|
||||
type UseSelectPropsImpl a =
|
||||
{ items ∷ Array a
|
||||
, itemToString ∷ a -> String
|
||||
, onSelectedItemChange ∷ EffectFn1 { type ∷ StateChangeType, selectedItem ∷ Nullable a } Unit
|
||||
, initialSelectedItem ∷ a -- defaults to null
|
||||
, initialIsOpen ∷ Boolean -- defaults to false
|
||||
, initialHighlightedIndex ∷ Int -- defaults to -1
|
||||
, defaultSelectedItem ∷ a -- defaults to null
|
||||
, defaultIsOpen ∷ Boolean -- defaults to false
|
||||
, defaultHighlightedIndex ∷ Int -- defaults to -1
|
||||
, getA11yStatusMessage ∷ Foreign -> Foreign -- defaults to undefined
|
||||
, getA11ySelectionMessage ∷ Foreign -> Foreign -- defaults to undefined
|
||||
, onHighlightedIndexChange ∷ Foreign -> Foreign -- defaults to undefined
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
const stateChangeTypes = require("downshift").useSelect.stateChangeTypes
|
||||
|
||||
export const menuKeyDownArrowDown = stateChangeTypes.MenuKeyDownArrowDown
|
||||
export const menuKeyDownArrowUp = stateChangeTypes.MenuKeyDownArrowUp
|
||||
export const menuKeyDownEscape = stateChangeTypes.MenuKeyDownEscape
|
||||
export const menuKeyDownHome = stateChangeTypes.MenuKeyDownHome
|
||||
export const menuKeyDownEnd = stateChangeTypes.MenuKeyDownEnd
|
||||
export const menuKeyDownEnter = stateChangeTypes.MenuKeyDownEnter
|
||||
export const menuKeyDownSpaceButton = stateChangeTypes.MenuKeyDownSpaceButton
|
||||
export const menuKeyDownCharacter = stateChangeTypes.MenuKeyDownCharacter
|
||||
export const menuBlur = stateChangeTypes.MenuBlur
|
||||
export const menuMouseLeave = stateChangeTypes.MenuMouseLeave
|
||||
export const itemMouseMove = stateChangeTypes.ItemMouseMove
|
||||
export const itemClick = stateChangeTypes.ItemClick
|
||||
export const toggleButtonClick = stateChangeTypes.ToggleButtonClick
|
||||
export const toggleButtonKeyDownCharacter =
|
||||
stateChangeTypes.ToggleButtonKeyDownCharacter
|
||||
export const toggleButtonKeyDownArrowDown =
|
||||
stateChangeTypes.ToggleButtonKeyDownArrowDown
|
||||
export const toggleButtonKeyDownArrowUp =
|
||||
stateChangeTypes.ToggleButtonKeyDownArrowUp
|
||||
export const functionToggleMenu = stateChangeTypes.FunctionToggleMenu
|
||||
export const functionOpenMenu = stateChangeTypes.FunctionOpenMenu
|
||||
export const functionCloseMenu = stateChangeTypes.FunctionCloseMenu
|
||||
export const functionSetHighlightedIndex =
|
||||
stateChangeTypes.FunctionSetHighlightedIndex
|
||||
export const functionSelectItem = stateChangeTypes.FunctionSelectItem
|
||||
export const functionSetInputValue = stateChangeTypes.FunctionSetInputValue
|
||||
export const functionReset = stateChangeTypes.FunctionReset
|
@ -1,49 +0,0 @@
|
||||
module React.Downshift.Types.StateChangeType where
|
||||
|
||||
foreign import data StateChangeType ∷ Type
|
||||
|
||||
foreign import menuKeyDownArrowDown ∷ StateChangeType
|
||||
|
||||
foreign import menuKeyDownArrowUp ∷ StateChangeType
|
||||
|
||||
foreign import menuKeyDownEscape ∷ StateChangeType
|
||||
|
||||
foreign import menuKeyDownHome ∷ StateChangeType
|
||||
|
||||
foreign import menuKeyDownEnd ∷ StateChangeType
|
||||
|
||||
foreign import menuKeyDownEnter ∷ StateChangeType
|
||||
|
||||
foreign import menuKeyDownSpaceButton ∷ StateChangeType
|
||||
|
||||
foreign import menuKeyDownCharacter ∷ StateChangeType
|
||||
|
||||
foreign import menuBlur ∷ StateChangeType
|
||||
|
||||
foreign import menuMouseLeave ∷ StateChangeType
|
||||
|
||||
foreign import itemMouseMove ∷ StateChangeType
|
||||
|
||||
foreign import itemClick ∷ StateChangeType
|
||||
|
||||
foreign import toggleButtonClick ∷ StateChangeType
|
||||
|
||||
foreign import toggleButtonKeyDownCharacter ∷ StateChangeType
|
||||
|
||||
foreign import toggleButtonKeyDownArrowDown ∷ StateChangeType
|
||||
|
||||
foreign import toggleButtonKeyDownArrowUp ∷ StateChangeType
|
||||
|
||||
foreign import functionToggleMenu ∷ StateChangeType
|
||||
|
||||
foreign import functionOpenMenu ∷ StateChangeType
|
||||
|
||||
foreign import functionCloseMenu ∷ StateChangeType
|
||||
|
||||
foreign import functionSetHighlightedIndex ∷ StateChangeType
|
||||
|
||||
foreign import functionSelectItem ∷ StateChangeType
|
||||
|
||||
foreign import functionSetInputValue ∷ StateChangeType
|
||||
|
||||
foreign import functionReset ∷ StateChangeType
|
@ -33,6 +33,7 @@ default =
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
button ∷ Effect JSX
|
||||
button = do
|
||||
pure
|
||||
|
@ -1,5 +0,0 @@
|
||||
module Yoga.Block.Atom.CodeInput
|
||||
( module Yoga.Block.Atom.CodeInput.View
|
||||
) where
|
||||
|
||||
import Yoga.Block.Atom.CodeInput.View (component, Props)
|
@ -1,20 +0,0 @@
|
||||
module Yoga.Block.Atom.CodeInput.Spec where
|
||||
|
||||
import Yoga.Prelude.Spec
|
||||
import Foreign.Object as Object
|
||||
import Yoga.Block.Atom.CodeInput as CodeInput
|
||||
|
||||
spec ∷ Spec Unit
|
||||
spec =
|
||||
after_ cleanup do
|
||||
describe "The codeInput" do
|
||||
it "renders without errors" do
|
||||
renderComponent CodeInput.component {} # void
|
||||
it "accepts input props" do
|
||||
{ findByTestId } <-
|
||||
renderComponent CodeInput.component
|
||||
{ disabled: true
|
||||
, _data: Object.singleton "testid" "code-input"
|
||||
}
|
||||
elem <- findByTestId "code-input"
|
||||
elem `shouldHaveAttribute` "disabled"
|
@ -1,83 +0,0 @@
|
||||
module Yoga.Block.Atom.CodeInput.Story where
|
||||
|
||||
import Prelude
|
||||
import Control.Monad.Maybe.Trans (lift, runMaybeT)
|
||||
import Data.Foldable (traverse_)
|
||||
import Data.Newtype (wrap)
|
||||
import Data.Nullable as Nullable
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Effect (Effect)
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import React.Basic (JSX, element, elementKeyed, fragment)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.DOM.Events (targetValue)
|
||||
import React.Basic.Emotion as E
|
||||
import React.Basic.Events (handler)
|
||||
import React.Basic.Hooks (reactComponent)
|
||||
import React.Basic.Hooks as React
|
||||
import Web.HTML.HTMLElement (focus)
|
||||
import Web.HTML.HTMLElement as HTMLElement
|
||||
import Yoga.Block.Atom.CodeInput as CodeInput
|
||||
import Yoga.Block.Container.Style as Styles
|
||||
|
||||
default ∷
|
||||
{ decorators ∷ Array (Effect JSX -> JSX)
|
||||
, title ∷ String
|
||||
}
|
||||
default =
|
||||
{ title: "Atom/CodeInput"
|
||||
, decorators:
|
||||
[ \storyFn ->
|
||||
R.div_
|
||||
[ element E.global { styles: Styles.global }
|
||||
, unsafePerformEffect storyFn
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
codeInput ∷ Effect JSX
|
||||
codeInput = do
|
||||
pure
|
||||
$ fragment
|
||||
[ R.h2_ [ R.text "No Options" ]
|
||||
, element CodeInput.component
|
||||
{}
|
||||
, element CodeInput.component
|
||||
{ maxLength: 3 }
|
||||
, React.element refCompo {}
|
||||
, React.element controlled {}
|
||||
]
|
||||
where
|
||||
refCompo =
|
||||
unsafePerformEffect
|
||||
$ reactComponent "Code Input Story" \{} -> React.do
|
||||
ref <- React.useRef Nullable.null
|
||||
React.useEffectAlways
|
||||
$ do
|
||||
_ <-
|
||||
runMaybeT do
|
||||
node <- React.readRefMaybe ref # wrap
|
||||
elem <- HTMLElement.fromNode node # pure # wrap
|
||||
focus elem # lift
|
||||
mempty
|
||||
pure
|
||||
$ fragment
|
||||
[ R.h2_ [ R.text "With Ref" ]
|
||||
, element CodeInput.component
|
||||
{ ref
|
||||
}
|
||||
]
|
||||
|
||||
controlled =
|
||||
unsafePerformEffect
|
||||
$ reactComponent "Code Input Controlled Story" \{} -> React.do
|
||||
text /\ setText <- React.useState' ""
|
||||
pure
|
||||
$ fragment
|
||||
[ R.h2_ [ R.text "Controlled" ]
|
||||
, elementKeyed CodeInput.component
|
||||
{ value: text
|
||||
, onChange: handler targetValue (traverse_ setText)
|
||||
, key: "robinson-crusoe"
|
||||
}
|
||||
]
|
@ -1,54 +0,0 @@
|
||||
module Yoga.Block.Atom.CodeInput.Style where
|
||||
|
||||
import Yoga.Prelude.Style
|
||||
import Data.Interpolate (i)
|
||||
import Yoga.Block.Container.Style (colour)
|
||||
|
||||
type Props :: forall k. (Type -> k) -> Row k -> Row k
|
||||
type Props f r =
|
||||
( css ∷ f Style
|
||||
| r
|
||||
)
|
||||
|
||||
codeInput ∷ ∀ p. { maxLength ∷ OptionalProp Int | Props OptionalProp p } -> Style
|
||||
codeInput props = styles <>? props.css
|
||||
where
|
||||
styles =
|
||||
overflowVisible <>
|
||||
css
|
||||
{ boxSizing: borderBox
|
||||
, verticalAlign: baseline
|
||||
, background: str colour.inputBackground
|
||||
, border: str $ i "solid 1px " colour.inputBorder
|
||||
, borderRadius: str "var(--s-2)"
|
||||
, fontFamily: str "var(--mono-font)"
|
||||
, fontSize: str "var(--s0)"
|
||||
, lineHeight: str "var(--s0)"
|
||||
, width: str $ i "calc(" (props.maxLength ?|| 10) "ch + 4.3 * var(--s-5))"
|
||||
, padding: str "calc(var(--s-4) - 1px)"
|
||||
, color: str colour.text
|
||||
, "&:focus":
|
||||
nest
|
||||
{ outline: none
|
||||
}
|
||||
, "&:focus-visible":
|
||||
nest
|
||||
{ animation: plopAnimation <> str " 260ms ease-in"
|
||||
, border: str $ "solid var(--s-4) " <> colour.highlight
|
||||
, padding: _0
|
||||
}
|
||||
}
|
||||
|
||||
plopAnimation ∷ StyleProperty
|
||||
plopAnimation =
|
||||
keyframes
|
||||
$
|
||||
{ "from": css { transform: str "scale3d(0.85,0.85,0.85)" }
|
||||
, "33%": css { transform: str "scale3d(1.07,1.07,1.07)" }
|
||||
, "67.7%": css { transform: str "scale3d(0.93,0.93,0.93)" }
|
||||
, "86.7%": css { transform: str "scale3d(1.02,1.02,1.02)" }
|
||||
, "to": css { transform: str "scale3d(1,1,1)" }
|
||||
}
|
||||
|
||||
codeInputWrapper ∷ Style
|
||||
codeInputWrapper = inlineBlock
|
@ -1,42 +0,0 @@
|
||||
module Yoga.Block.Atom.CodeInput.View
|
||||
( component
|
||||
, Props
|
||||
, PropsF
|
||||
, EmotionProps
|
||||
) where
|
||||
|
||||
import Yoga.Prelude.View
|
||||
import React.Basic.Emotion (Style)
|
||||
import Yoga.Block.Atom.CodeInput.Style as Style
|
||||
|
||||
type PropsF f =
|
||||
(
|
||||
| Style.Props f (InputWritablePropsF f EmotionProps)
|
||||
)
|
||||
|
||||
type Props =
|
||||
PropsF Id
|
||||
|
||||
type PropsOptional =
|
||||
PropsF OptionalProp
|
||||
|
||||
type EmotionProps =
|
||||
( className ∷ String, css ∷ Style )
|
||||
|
||||
component ∷ ∀ p q. Union p q Props => ReactComponent { | p }
|
||||
component = rawComponent
|
||||
|
||||
rawComponent ∷ ∀ r. ReactComponent { | r }
|
||||
rawComponent =
|
||||
mkForwardRefComponent "CodeInput" do
|
||||
\(props ∷ { | PropsOptional }) ref -> React.do
|
||||
pure
|
||||
$ emotionInput ref
|
||||
props
|
||||
{ className: "ry-inline-code"
|
||||
, css: Style.codeInput props
|
||||
, spellCheck: false
|
||||
, autoComplete: "false"
|
||||
, autoCorrect: "off"
|
||||
, autoCapitalize: "off"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
module Yoga.Block.Molecule.TableOfContents
|
||||
( module Yoga.Block.Molecule.TableOfContents.View
|
||||
) where
|
||||
|
||||
import Yoga.Block.Molecule.TableOfContents.View (component, Props, MandatoryProps)
|
@ -1,14 +0,0 @@
|
||||
module Yoga.Block.Molecule.TableOfContents.Spec where
|
||||
|
||||
import Yoga.Prelude.Spec
|
||||
import Yoga.Block.Molecule.TableOfContents as TableOfContents
|
||||
|
||||
spec ∷ Spec Unit
|
||||
spec =
|
||||
after_ cleanup do
|
||||
describe "The tableOfContents" do
|
||||
it "renders without errors" do
|
||||
void
|
||||
$ renderComponent TableOfContents.component
|
||||
{ items: []
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
module Yoga.Block.Molecule.TableOfContents.Story where
|
||||
|
||||
import Prelude
|
||||
import Control.Comonad.Cofree as Cofree
|
||||
import Data.Array (foldMap)
|
||||
import Data.Foldable (fold)
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Data.Monoid (power)
|
||||
import Data.Traversable (traverse)
|
||||
import Yoga.Tree (Forest, Tree, mkLeaf, mkTree)
|
||||
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.Hooks as React
|
||||
import Yoga ((/>), (</))
|
||||
import Yoga.Block.Container.Style as Styles
|
||||
import Yoga.Block.Internal (createRef)
|
||||
import Yoga.Block.Molecule.TableOfContents as TableOfContents
|
||||
|
||||
default
|
||||
∷ { decorators ∷ Array (Effect JSX -> JSX)
|
||||
, title ∷ String
|
||||
}
|
||||
default =
|
||||
{ title: "Molecule/TableOfContents"
|
||||
, decorators:
|
||||
[ \storyFn ->
|
||||
R.div_
|
||||
[ element E.global { styles: Styles.global }
|
||||
, unsafePerformEffect storyFn
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
tableOfContents ∷ Effect JSX
|
||||
tableOfContents = do
|
||||
example <- mkBasicExample
|
||||
pure
|
||||
$ fragment
|
||||
[ R.div_
|
||||
[ R.h2_ [ R.text "Table of Contents" ]
|
||||
, element example {}
|
||||
]
|
||||
]
|
||||
where
|
||||
mkBasicExample =
|
||||
React.reactComponent "TableOfContents example" \_ -> React.do
|
||||
let
|
||||
startHeadings ∷ Forest { label ∷ String }
|
||||
startHeadings =
|
||||
[ mkTree { label: "Heading 1" }
|
||||
[ mkTree { label: "SubHeading 1" }
|
||||
[ mkLeaf { label: "SubsubHeading 1.1" }
|
||||
, mkLeaf { label: "SubsubHeading 1.2" }
|
||||
]
|
||||
]
|
||||
, mkTree { label: "Heading 2" } []
|
||||
]
|
||||
(tocData ∷ (Forest ({ label ∷ String, ref ∷ _ }))) /\ setTocData <- React.useState' []
|
||||
React.useEffectOnce do
|
||||
(newHeadings ∷ Forest { label ∷ String, ref ∷ _ }) <-
|
||||
startHeadings
|
||||
# (traverse >>> traverse) \{ label } -> do
|
||||
createRef # map { label, ref: _ }
|
||||
setTocData newHeadings
|
||||
mempty
|
||||
pure do
|
||||
let toc = element TableOfContents.component { items: tocData }
|
||||
let
|
||||
treeToHeading ∷ Tree _ -> JSX
|
||||
treeToHeading = go 1
|
||||
where
|
||||
go ∷ Int -> Tree _ -> JSX
|
||||
go depth tree = case Cofree.head tree, Cofree.tail tree of
|
||||
{ label, ref }, children -> do
|
||||
let
|
||||
heading = case depth of
|
||||
1 -> R.h1'
|
||||
2 -> R.h2'
|
||||
3 -> R.h3'
|
||||
_ -> R.h4'
|
||||
(fragment [ heading </ { ref } /> [ R.text label ], blabla depth ])
|
||||
<> foldMap (go (depth + 1)) children
|
||||
|
||||
content ∷ Array JSX
|
||||
content = tocData <#> treeToHeading
|
||||
toc <> fold content
|
||||
|
||||
blabla ∷ Int -> JSX
|
||||
blabla n =
|
||||
R.p_
|
||||
[ R.text
|
||||
( n
|
||||
# power
|
||||
"""
|
||||
As a follow up to my post about Zippers for lists and binary trees, I wanted to create a zipper for a slightly more complex data structure. The Rose Tree is a tree structure where the number of branches a node may have is variable. An example of a rose tree would be the directory structure on your computer: each directory may contain 0 or more sub directories which, in turn, may contain addition subdirectories. With this example in mind, the zipper is analagous to you moving through your computers file system: starting at the root directory and using cd to move down a branch and cd .. to move back.
|
||||
"""
|
||||
)
|
||||
]
|
@ -1,93 +0,0 @@
|
||||
module Yoga.Block.Molecule.TableOfContents.Style where
|
||||
|
||||
import Yoga.Prelude.Style
|
||||
import Yoga.Block.Container.Style (colour)
|
||||
|
||||
type Props :: forall k. (Type -> k) -> Row k -> Row k
|
||||
type Props f r =
|
||||
( css ∷ f Style
|
||||
, backgroundLeft ∷ f Color
|
||||
, backgroundRight ∷ f Color
|
||||
| r
|
||||
)
|
||||
|
||||
button ∷ Style
|
||||
button =
|
||||
css
|
||||
{ position: relative
|
||||
, "&:focus": nest { outline: str "none" }
|
||||
, border: str $ "1px solid " <> colour.backgroundLayer2
|
||||
, "&:focus-visible":
|
||||
nest
|
||||
{ boxShadow: str $ "0 0 0 var(--s-4) " <> colour.highlight
|
||||
}
|
||||
, borderRadius: str "calc(var(--s2) / 2)"
|
||||
, height: var "--s2"
|
||||
, width: str "calc(var(--s2) + var(--s1))"
|
||||
, margin: _0
|
||||
, padding: _0
|
||||
}
|
||||
|
||||
tableOfContentsLeft ∷ String
|
||||
tableOfContentsLeft = "calc(var(--s-2) * 0.3)"
|
||||
|
||||
dragWidthDelta ∷ Number
|
||||
dragWidthDelta = 10.0
|
||||
|
||||
theTableOfContents ∷ Style
|
||||
theTableOfContents =
|
||||
css
|
||||
{ width: str "calc(var(--s2) * 0.85)"
|
||||
, height: str "calc(var(--s2) * 0.85)"
|
||||
, background: str $ colour.backgroundLayer4
|
||||
, border: none
|
||||
, borderRadius: str $ "calc(var(--s2) / 2)"
|
||||
, position: absolute
|
||||
, top: str "calc(var(--s-2) * 0.35)"
|
||||
, left: str tableOfContentsLeft
|
||||
, margin: _0
|
||||
, boxShadow: str "0 0.5px 3px rgba(0,0,0,0.50)"
|
||||
}
|
||||
|
||||
tableOfContentsTextContainer ∷ Style
|
||||
tableOfContentsTextContainer =
|
||||
flex <>
|
||||
css
|
||||
{ width: _100percent
|
||||
, border: none
|
||||
, fontWeight: str "bold"
|
||||
, position: absolute
|
||||
, top: str "1px"
|
||||
, fontSize: str "calc(var(--s2) * 0.5)"
|
||||
, lineHeight: str "calc(var(--s2) * 0.5)"
|
||||
, textAlign: center
|
||||
, height: var "--s2"
|
||||
, justifyContent: center
|
||||
, alignItems: center
|
||||
, margin: _0
|
||||
, padding: _0
|
||||
}
|
||||
|
||||
successTextColour ∷ StyleProperty
|
||||
successTextColour = str colour.successText
|
||||
|
||||
disabledTextColour ∷ StyleProperty
|
||||
disabledTextColour = str colour.interfaceTextDisabled
|
||||
|
||||
tableOfContentsText ∷ Style
|
||||
tableOfContentsText =
|
||||
flex <>
|
||||
css
|
||||
{ textAlign: str "left"
|
||||
, margin: _0
|
||||
, padding: _0
|
||||
, width: str "50%"
|
||||
, height: str "100%"
|
||||
, justifyContent: center
|
||||
, alignItems: center
|
||||
, color: disabledTextColour
|
||||
, "& > *":
|
||||
nest
|
||||
{ color: successTextColour
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
module Yoga.Block.Molecule.TableOfContents.Types where
|
||||
|
||||
import Prelude
|
||||
|
||||
data TableOfContentsPosition
|
||||
= TableOfContentsIsLeft
|
||||
| TableOfContentsIsRight
|
||||
derive instance eqTableOfContentsPosition ∷ Eq TableOfContentsPosition
|
||||
|
||||
instance showTableOfContentsPosition ∷ Show TableOfContentsPosition where
|
||||
show = case _ of
|
||||
TableOfContentsIsLeft -> "TableOfContentsIsLeft"
|
||||
TableOfContentsIsRight -> "TableOfContentsIsRight"
|
||||
|
||||
flipTableOfContents ∷ TableOfContentsPosition -> TableOfContentsPosition
|
||||
flipTableOfContents = case _ of
|
||||
TableOfContentsIsLeft -> TableOfContentsIsRight
|
||||
TableOfContentsIsRight -> TableOfContentsIsLeft
|
@ -1,68 +0,0 @@
|
||||
module Yoga.Block.Molecule.TableOfContents.View
|
||||
( component
|
||||
, MandatoryProps
|
||||
, Props
|
||||
, PropsF
|
||||
) where
|
||||
|
||||
import Yoga.Tree (Forest)
|
||||
import React.Basic.DOM (css)
|
||||
import React.Basic.DOM as R
|
||||
import Yoga.Block.Container.Style (colour)
|
||||
import Yoga.Block.Molecule.TableOfContents.Style as Style
|
||||
import Yoga.Prelude.View (class Union, Id, InputWritableProps, JSX, NodeRef, OptionalProp, ReactComponent, mkForwardRefComponent, pure, (/>), (</))
|
||||
|
||||
type PropsF f =
|
||||
( className ∷ f String
|
||||
, left ∷ f JSX
|
||||
, right ∷ f JSX
|
||||
| Style.Props f (MandatoryProps InputWritableProps)
|
||||
)
|
||||
|
||||
type MandatoryProps r =
|
||||
( items ∷ Forest { label ∷ String, ref ∷ NodeRef }
|
||||
| r
|
||||
)
|
||||
|
||||
type Props =
|
||||
PropsF Id
|
||||
|
||||
type PropsOptional =
|
||||
PropsF OptionalProp
|
||||
|
||||
component ∷ ∀ p q. Union p q Props => ReactComponent { | MandatoryProps p }
|
||||
component = rawComponent
|
||||
|
||||
rawComponent ∷ ∀ p. ReactComponent (Record p)
|
||||
rawComponent =
|
||||
mkForwardRefComponent "TableOfContents" do
|
||||
\(_ ∷ { | PropsOptional }) ref -> React.do
|
||||
pure do
|
||||
R.div'
|
||||
</
|
||||
{ style:
|
||||
css
|
||||
{ position: "fixed"
|
||||
, background: colour.backgroundLayer2
|
||||
, padding: 0
|
||||
, margin: 0
|
||||
}
|
||||
, ref
|
||||
}
|
||||
/>
|
||||
[ R.div'
|
||||
</
|
||||
{ style:
|
||||
css
|
||||
{ display: "flex"
|
||||
, flexDirection: "row"
|
||||
, alignItems: "stretch"
|
||||
, justifyContent: "flex-start"
|
||||
, padding: 0
|
||||
, margin: 0
|
||||
}
|
||||
}
|
||||
/>
|
||||
[ R.text "Hi"
|
||||
]
|
||||
]
|
Loading…
Reference in New Issue
Block a user