lue-bird/elm-emptiness-typed/6.0.0

NOTE: the latest version is 9.2.1

Scroll

📜 Items rolled up on both sides of a focus

→ good fit for dynamic choice selection: tabs, playlist, timeline...

Scroll can even focus a gap Down or Up from every item.

Not what you were looking for? Check out alternatives.

type Scroll item focusedOnGapTag possiblyOrNever
= BeforeFocusAfter
(Emptiable (Stacked item) Possibly)
(Emptiable item possiblyOrNever)
(Emptiable (Stacked item) Possibly)

📜 Items rolled up on both sides of a focus

→ good fit for dynamic choice selection: tabs, playlist, ...

Scroll can even focus a gap Down and Up every item:

  • 🍍 🍓 <🍊> 🍉 🍇: Scroll ... FocusGap Never

  • 🍍 🍓 <?> 🍉 🍇: Scroll ... Possibly FocusGap

    <?> means both are possible:

    • 🍍 🍓 <> 🍉 🍇: a gap between items ... Heh.
    • 🍍 🍓 <🍊> 🍉 🍇

in arguments

empty : Scroll item_ FocusGap Possibly

in types

type alias Model =
    RecordWithoutConstructorFunction
        { choice : Scroll Option FocusGap Never
        }

where RecordWithoutConstructorFunction stops the compiler from creating a constructor function for Model.

A word in every Scroll type:

  • 🍍 🍓 <🍊> 🍉 🍇: Scroll ... FocusGap Never

  • 🍍 🍓 <?> 🍉 🍇: Scroll ... Possibly FocusGap

    <?> means both are possible:

    • 🍍 🍓 <> 🍉 🍇: a gap between items ... Heh.
    • 🍍 🍓 <🍊> 🍉 🍇

position

= AtSide DirectionLinear Int
| AtFocus

Position in a Scroll relative to its focus.

import Linear exposing (DirectionLinear(..))
import Emptiable exposing (Emptiable, filled, fillMap, fillMapFlat)
import Stack exposing (topDown)


Scroll.only 0
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.to (Scroll.AtSide Up 2)
    |> fillMap Scroll.focusItem
--> filled 3
--: Emptiable (Stacked number_) Possibly
nearest : DirectionLinear -> Location

The Location directly Down|Up the focus.

import Emptiable exposing (Emptiable, filled, fillMap)
import Stack exposing (onTopLay, topDown)
import Scroll exposing (Scroll, FocusGap)
import Linear exposing (DirectionLinear(..))


Scroll.only "hello"
    |> Scroll.sideAlter
        ( Up, \_ -> topDown "scrollable" [ "world" ] )
    |> Scroll.toEnd Up
    |> Scroll.to (Down |> Scroll.nearest)
    |> fillMap Scroll.focusItem
--> filled "scrollable"
--: Emptiable (Scroll String FocusGap Never) Possibly


Scroll.empty
    |> Scroll.sideAlter
        ( Down, \_ -> topDown "world" [ "scrollable" ] )
    |> Scroll.to (Down |> Scroll.nearest)
--> Scroll.only "world"
-->     |> Scroll.sideAlter
-->         ( Down, \_ -> Stack.only "scrollable" )
-->     |> filled
--: Emptiable (Scroll String FocusGap Never) Possibly


Scroll.empty
    |> Scroll.sideAlter
        ( Up, onTopLay "foo" )
    |> Scroll.to (Up |> Scroll.nearest)
--> filled (Scroll.only "foo")
--: Emptiable (Scroll String FocusGap Never) Possibly


nearest =
    \side ->
        Scroll.AtSide side 0

create

empty : Scroll item_ FocusGap Possibly

An empty Scroll on a gap with nothing before and after it. It's the loneliest of all Scrolls.

<>
import Emptiable


Scroll.empty |> Scroll.toStack
--> Emptiable.empty
only : element -> Scroll element FocusGap never_

A Scroll with a single focussed item in it, nothing Down and Up it.

🍊  ->  <🍊>
import Stack


Scroll.only "wat" |> Scroll.focusItem
--> "wat"


Scroll.only "wat" |> Scroll.toStack
--> Stack.only "wat"

scan

focusItem : Scroll item FocusGap Never -> item

The focused item.

🍍 🍓 <🍊> 🍉 🍇  ->  🍊
import Stack exposing (topDown)
import Linear exposing (DirectionLinear(..))


Scroll.only "hi there" |> Scroll.focusItem
--> "hi there"


Scroll.only 1
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ 3, 4 ] )
    |> Scroll.toEnd Up
    |> Scroll.focusItem
--> 4
Scroll item FocusGap possiblyOrNever
-> Emptiable item possiblyOrNever

The focused item or gap.

🍍 🍓 <🍊> 🍉 🍇  ->  🍊
🍍 🍓 <> 🍉 🍇  ->  _
import Emptiable exposing (filled, fill)


Scroll.empty |> Scroll.focus
--> Emptiable.empty


Scroll.only "hi there" |> Scroll.focus |> fill
--> "hi there"

focusItem is short for focus |> fill.

DirectionLinear
-> Scroll item FocusGap possiblyOrNever_
-> Emptiable (Stacked item) Possibly

The Stack to one side of the focus.

Down

🍍←🍓) <🍊> 🍉 🍇

Up

🍍 🍓 <🍊> (🍉→🍇
import Emptiable exposing (Emptiable, fillMapFlat)
import Stack exposing (Stacked, topDown)
import Linear exposing (DirectionLinear(..))


Scroll.only 0
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.to (Up |> Scroll.nearest)
    |> fillMapFlat (Scroll.to (Up |> Scroll.nearest))
    |> fillMapFlat (Scroll.side Down)
--> topDown 1 [ 0 ]
--: Emptiable (Stacked number_) Possibly


Scroll.only 0
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.to (Up |> Scroll.nearest)
    |> fillMapFlat (Scroll.side Up)
--> topDown 2 [ 3 ]
--: Emptiable (Stacked number_) Possibly
length : Scroll item_ FocusGap possiblyOrNever_ -> Int

Counting all contained items.

import Stack exposing (topDown)
import Linear exposing (DirectionLinear(..))


Scroll.only 0
    |> Scroll.sideAlter
        ( Down, \_ -> topDown -1 [ -2 ] )
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.length
--> 6


Scroll.empty
    |> Scroll.sideAlter
        ( Down, \_ -> topDown -1 [ -2 ] )
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.length
--> 5

move the focus

to :
-> Scroll item FocusGap possiblyOrNever_
-> Emptiable (Scroll item FocusGap never_) Possibly

Try to move the focus to the item at a given Scroll.Location.

Scroll.to (Down |> Scroll.nearest)

🍊 <🍉> 🍇  ->  <🍊> 🍉 🍇
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (Emptiable, filled, fillMap)
import Scroll exposing (Scroll, FocusGap)


Scroll.empty |> Scroll.to (Down |> Scroll.nearest)
--> Emptiable.empty


Scroll.only "hello"
    |> Scroll.sideAlter
        ( Up, \_ -> topDown "scrollable" [ "world" ] )
    |> Scroll.toEnd Up
    |> Scroll.to (Down |> Scroll.nearest)
    |> fillMap Scroll.focusItem
--> filled "scrollable"
--: Emptiable (Scroll String FocusGap Never) Possibly

This also works from within gaps:

🍊 🍉 <> 🍇  ->  🍊 <🍉> 🍇
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (Emptiable, filled)
import Stack exposing (onTopLay)
import Scroll exposing (Scroll, FocusGap)


Scroll.empty
    |> Scroll.sideAlter
        ( Down, onTopLay "foo" )
    |> Scroll.to (Down |> Scroll.nearest)
--> filled (Scroll.only "foo")
--: Emptiable (Scroll String FocusGap Never) Possibly

Scroll.to (Up |> Scroll.nearest)

<🍊> 🍉 🍇  ->  🍊 <🍉> 🍇
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (Emptiable, filled, fillMap)
import Scroll exposing (Scroll, FocusGap)


Scroll.only 0
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.to (Up |> Scroll.nearest)
    |> fillMap Scroll.focusItem
--> filled 1
--: Emptiable number_ Possibly

This also works from within gaps:

🍊 <> 🍉 🍇  ->  🍊 <🍉> 🍇
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (Emptiable, filled)
import Stack exposing (onTopLay)
import Scroll exposing (Scroll, FocusGap)


Scroll.empty
    |> Scroll.sideAlter
        ( Up, \_ -> Stack.only "foo" )
    |> Scroll.to (Up |> Scroll.nearest)
--> filled (Scroll.only "foo")
--: Emptiable (Scroll String FocusGap Never) Possibly

If there is no next item, the result is empty.

import Linear exposing (DirectionLinear(..))
import Emptiable
import Stack exposing (topDown)


Scroll.empty |> Scroll.to (Up |> Scroll.nearest)
--> Emptiable.empty


Scroll.only 0
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.toEnd Up
    |> Scroll.to (Up |> Scroll.nearest)
--> Emptiable.empty

Scroll.to Location

import Element as Ui
import Element.Input as UIn
import Emptiable exposing (fillMap)
import RecordWithoutConstructorFunction exposing (RecordWithoutConstructorFunction)
import Scroll exposing (FocusGap, Scroll)
import Stack


type alias Model =
    RecordWithoutConstructorFunction
        { numbers : Scroll Int FocusGap Never
        }


type Event
    = NumberClicked Scroll.Location


update : Event -> Model -> ( Model, Cmd Event )
update event model =
    case event of
        NumberClicked location ->
            ( { model
                | numbers =
                    model.numbers
                        |> Scroll.to location
                        |> Emptiable.fillElseOnEmpty (\_ -> model.numbers)
                        |> Scroll.focusAlter (fillMap (\n -> n + 1))
              }
            , Cmd.none
            )


interface : Model -> Ui.Element Event
interface =
    \{ numbers } ->
        numbers
            |> Scroll.map numberInterface
            |> Scroll.toList
            |> Ui.column []


numberInterface :
    Scroll.Location
    -> Int
    -> Ui.Element Event
numberInterface location =
    \number ->
        UIn.button []
            { onPress = NumberClicked location |> Just
            , label =
                number
                    |> String.fromInt
                    |> Ui.text
            }

The same functionality is often provided as duplicate : Scroll item ... -> Scroll (Scroll item) ...

Saving a Scroll with every item becomes expensive for long Scrolls, though!

DirectionLinear
-> Scroll item FocusGap Never
-> Scroll item FocusGap Possibly

Move the focus to the gap directly Down|Up. Feel free to plug that gap right up!

Scroll.toGap Down

🍍 <🍊> 🍉  ->  🍍 <> 🍊 🍉
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled)
import Stack exposing (topDown)


Scroll.only "world"
    |> Scroll.toGap Down
    |> Scroll.focusAlter (\_ -> "hello" |> filled)
    |> Scroll.toStack
--> topDown "hello" [ "world" ]

Scroll.toGap Up

🍍 <🍊> 🍉  ->  🍍 🍊 <> 🍉
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled)
import Stack exposing (topDown)


Scroll.only "hello"
    |> Scroll.sideAlter
        ( Up, \_ -> Stack.only "world" )
    |> Scroll.toGap Up
    |> Scroll.focusAlter (\_ -> filled "scrollable")
    |> Scroll.toStack
--> topDown "hello" [ "scrollable", "world" ]
DirectionLinear
-> Scroll item FocusGap possiblyOrNever
-> Scroll item FocusGap possiblyOrNever

Focus the furthest item Down/Up the focus.

Down

🍍 🍓 <🍊> 🍉  ->  <🍍> 🍓 🍊 🍉

Up

🍓 <🍊> 🍉 🍇  ->  🍓 🍊 🍉 <🍇>
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (Emptiable)
import Stack exposing (Stacked, topDown)


Scroll.only 1
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ 3, 4 ] )
    |> Scroll.sideAlter
        ( Down, \_ -> topDown 4 [ 3, 2 ] )
    |> Scroll.toEnd Down
    |> Scroll.focusItem
--> 2


Scroll.only 1
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ 3, 4 ] )
    |> Scroll.toEnd Up
    |> Scroll.focusItem
--> 4


Scroll.only 1
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ 3, 4 ] )
    |> Scroll.toEnd Up
    |> Scroll.side Down
--> topDown 3 [ 2, 1 ]
--: Emptiable (Stacked number_) Possibly
DirectionLinear
-> Scroll item FocusGap possiblyOrNever_
-> Scroll item FocusGap Possibly

Focus the gap beyond the furthest item Down|Up. Remember that gaps surround everything!

Down

🍍 🍓 <🍊> 🍉  ->  <> 🍍 🍓 🍊 🍉

Up

🍓 <🍊> 🍉  ->  🍓 🍊 🍉 <>
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled)
import Stack exposing (topDown)


Scroll.only 1
        -- <1>
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 3 [ 4 ] )
        -- <1> 3 4
    |> Scroll.toGap Up
        -- 1 <> 3 4
    |> Scroll.focusAlter (\_ -> filled 2)
        -- 1 <2> 3 4
    |> Scroll.toEndGap Down
        -- <> 1 2 3 4
    |> Scroll.focusAlter (\_ -> filled 0)
        -- <0> 1 2 3 4
    |> Scroll.toStack
--> topDown 0 [ 1, 2, 3, 4 ]


Scroll.only 1
        -- <1>
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ 3 ] )
        -- <1> 2 3
    |> Scroll.toEndGap Up
        -- 1 2 3 <>
    |> Scroll.focusAlter (\_ -> filled 4)
        -- 1 2 3 <4>
    |> Scroll.toStack
--> topDown 1 [ 2, 3, 4 ]
( DirectionLinear, { index : Int } -> item -> Bool )
-> Scroll item FocusGap possiblyOrNever_
-> Emptiable (Scroll item FocusGap never_) Possibly

Move the focus to the nearest item Down|Up that matches a predicate. If no such item was found return with Emptiable.empty.

import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled, fillMap)
import Stack exposing (topDown)
import Linear exposing (DirectionLinear(..))


Scroll.only 4
    |> Scroll.sideAlter
        ( Down, \_ -> topDown 2 [ -1, 0, 3 ] )
    |> Scroll.toWhere ( Down, \_ item -> item < 0 )
    |> Emptiable.fillMap Scroll.focusItem
--> filled -1


Scroll.only 4
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ -1, 0, 3 ] )
    |> Scroll.toWhere ( Up, \_ item -> item < 0 )
    |> fillMap focusItem
--> filled -1


Scroll.only -4
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ -1, 0, 3 ] )
    |> Scroll.toWhere ( Up, \_ item -> item < 0 )
    |> fillMap focusItem
--> filled -4
DirectionLinear
-> Scroll item FocusGap possiblyOrNever
-> Emptiable (Scroll item FocusGap possiblyOrNever) Possibly

Try to move the focus to the nearest item Down|Up.

Down

🍊 🍉 <🍓> 🍇  ->  🍊 <🍓> 🍉 🍇
🍊 🍉 <> 🍇  ->  🍊 <> 🍉 🍇

Up

🍊 <🍓> 🍉 🍇  ->  🍊 🍉 <🍓> 🍇
🍊 <> 🍉 🍇  ->  🍊 🍉 <> 🍇
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (Emptiable, fillMapFlat)
import Scroll exposing (Scroll, FocusGap)


Scroll.only 0
    |> Scroll.sideAlter
        ( Down, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.focusDrag Down
    |> fillMapFlat Scroll.toStack
--> topDown 3 [ 2, 0, 1 ]
--: Emptiable (Stacked number_) Possibly


Scroll.only 0
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.focusDrag Up
    |> fillMapFlat Scroll.toStack
--> topDown 1 [ 0, 2, 3 ]
--: Emptiable (Stacked number_) Possibly

If there is no nearest item, the result is empty.

import Linear exposing (DirectionLinear(..))
import Emptiable
import Stack exposing (topDown)


Scroll.only 0
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.focusDrag Down
--> Emptiable.empty


Scroll.only 0
    |> Scroll.sideAlter
        ( Down, \_ -> topDown 1 [ 2, 3 ] )
    |> Scroll.focusDrag Up
--> Emptiable.empty

transform

Scroll item FocusGap possiblyOrNever
-> Emptiable (Scroll item FocusGap never_) possiblyOrNever

Emptiable.empty if the current focussed thing is a gap, Emptiable.filled if it's an item.

import Emptiable
import Stack exposing (topDown)
import Linear exposing (DirectionLinear(..))


Scroll.only 3
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ 1 ] )
    |> Scroll.toGap Up
    |> Scroll.focusItemTry
--> Emptiable.empty
map :
(Location -> item -> mappedItem)
-> Scroll item FocusGap possiblyOrNever
-> Scroll mappedItem FocusGap possiblyOrNever

Change every item based on its current value.

import Linear exposing (DirectionLinear(..))
import Stack exposing (topDown)


Scroll.only "first"
    |> Scroll.sideAlter
        ( Down, \_ -> Stack.only "zeroth" )
    |> Scroll.sideAlter
        ( Up, \_ -> topDown "second" [ "third" ] )
    |> Scroll.map (\_ -> String.toUpper)
    |> Scroll.toStack
--> topDown "ZEROTH" [ "FIRST", "SECOND", "THIRD" ]

focusSidesMap allows changing the individual parts separately.

{ focus :
Emptiable item possiblyOrNever
-> Emptiable mappedItem possiblyOrNeverMapped
, side :
DirectionLinear
-> Emptiable (Stacked item) Possibly
-> Emptiable (Stacked mappedItem) possiblyOrNeverMappedBefore_
}
-> Scroll item FocusGap possiblyOrNever
-> Scroll mappedItem FocusGap possiblyOrNeverMapped

Change the focus, the sides Down and Up using different functions.

import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled, fillMap)
import Stack exposing (topDown)


Scroll.only "first"
    |> Scroll.sideAlter
        ( Up, \_ -> Stack.only "second" )
    |> Scroll.toGap Up
    |> Scroll.focusAlter (\_ -> filled "one-and-a-halfth")
    |> Scroll.focusSidesMap
        { side =
            \side ->
                Stack.map
                    (\_ item ->
                        String.concat
                            [ side |> sideToString, ": ", item ]
                    )
        , focus =
            fillMap (\item -> "focused item: " ++ item)
        }
    |> Scroll.toStack
--→
topDown
    "before: first"
    [ "focused item: one-and-a-halfth"
    , "after: second"
    ]


sideToString =
    \side ->
        case side of
            Down ->
                "before"


            Up ->
                "after"

map transforms every item.

accumulationValue
-> DirectionLinear
-> (item -> accumulationValue -> accumulationValue)
-> Scroll item FocusGap Never
-> accumulationValue

Reduce in a direction.

import Linear exposing (DirectionLinear(..))
import Stack exposing (topDown)


Scroll.only 'e'
    |> Scroll.sideAlter
        ( Down, \_ -> topDown 'v' [ 'i', 'l' ] )
    |> Scroll.foldFrom "" Down String.cons
--> "live"


Scroll.only 'e'
    |> Scroll.sideAlter
        ( Down, \_ -> topDown 'v' [ 'i', 'l' ] )
    |> Scroll.foldFrom "" Up String.cons
--> "evil"
DirectionLinear
-> (item -> item -> item)
-> Scroll item FocusGap Never
-> item

Fold in a direction from the first item Up|Down as the initial accumulation value.

import Linear exposing (DirectionLinear(..))
import Stack exposing (topDown)


Scroll.only 234
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 345 [ 543 ] )
    |> Scroll.fold Up max
--> 543
Scroll item FocusGap possiblyOrNever
-> Emptiable (Stacked item) possiblyOrNever

Roll out the Scroll to both ends into a Stack:

import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled)
import Stack exposing (topDown)


Scroll.empty
    |> Scroll.toStack
--> Emptiable.empty


Scroll.only 123
    |> Scroll.sideAlter
        ( Up, \_ -> Stack.only 789 )
    |> Scroll.toGap Up
    |> Scroll.focusAlter (\_-> filled 456)
    |> Scroll.toStack
--> topDown 123 [ 456, 789 ]

the type information gets carried over, so

Never Scroll.FocusGap -> Stacked Never
Possibly Scroll.FocusGap -> Stacked Possibly
toList : Scroll item FocusGap possiblyOrNever_ -> List item

Converts it to a List, rolled out to both ends:

import Linear exposing (DirectionLinear(..))
import Stack


Scroll.only 456
    |> Scroll.sideAlter
        ( Down, \_ -> Stack.only 123 )
    |> Scroll.sideAlter
        ( Up, \_ -> Stack.only 789 )
    |> Scroll.toList
--> [ 123, 456, 789 ]

Only use this if you need a list in the end. Otherwise, use toStack to preserve some information about its length.

alter

Scroll item FocusGap possiblyOrNever
-> Scroll item FocusGap possiblyOrNever

Swap the stack on the side Down the focus with the stack on the side Up.

🍓 <🍊> 🍉 🍇  <->  🍇 🍉 <🍊> 🍓
import Linear exposing (DirectionLinear(..))
import Stack exposing (topDown)


Scroll.only 1
    |> Scroll.sideAlter
        ( Up, \_ -> topDown 2 [ 3, 4 ] )
    |> Scroll.sideAlter
        ( Down, \_ -> topDown 4 [ 3, 2 ] )

In contrast to List or stack, this can be done in O(1) time.

( Emptiable item possiblyOrNever
-> Emptiable item possiblyOrNeverAltered
)
-> Scroll item FocusGap possiblyOrNever
-> Scroll item FocusGap possiblyOrNeverAltered

Alter the focus – item or gap – based on its current value.

Scroll.focusAlter (\_ -> 🍊 |> filled)

🍊  ->  🍓 <?> 🍉  ->  🍓 <🍊> 🍉
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled, fillMap)
import Stack exposing (topDown, onTopLay)


Scroll.empty
        -- <>
    |> Scroll.sideAlter
        ( Down, onTopLay "🍓" )
        -- "🍓" <>
    |> Scroll.sideAlter
        ( Up, onTopLay "🍉" )
        -- "🍓" <> "🍉"
    |> Scroll.focusAlter (\_ -> "🍊" |> filled)
        -- "🍓" <"🍊"> "🍉"
    |> Scroll.toStack
--> topDown "🍓" [ "🍊", "🍉" ]

Scroll.focusAlter (\_ -> Emptiable.empty)

🍓 <?> 🍉  ->  🍓 <> 🍉
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled, fillMap)
import Stack exposing (topDown)


Scroll.only "hello"
    |> Scroll.sideAlter
        ( Up, \_ -> topDown "scrollable" [ "world" ] )
    |> Scroll.to (Up |> Scroll.nearest)
    |> fillMap (Scroll.focusAlter (\_ -> Emptiable.empty))
    |> fillMap Scroll.toList
--> filled [ "hello", "world" ]

Scroll.focusAlter (?🍒 -> ?🍊)

(?🍒 -> ?🍊)  ->  🍓 <?🍒> 🍉  ->  🍓 <?🍊> 🍉
import Linear exposing (DirectionLinear(..))
import Emptiable exposing (filled, fillMap)
import Stack exposing (topDown, onTopLay)


Scroll.empty
        -- <>
    |> Scroll.sideAlter
        ( Down, onTopLay "🍓" )
        -- "🍓" <>
    |> Scroll.sideAlter
        ( Up, onTopLay "🍉" )
        -- "🍓" <> "🍉"
    |> Scroll.focusAlter
        (\_ -> filled "🍊")
        -- "🍓" <"🍊"> "🍉"
    |> Scroll.toStack
--> topDown "🍓" [ "🍊", "🍉" ]


Scroll.only "first"
    |> Scroll.sideAlter
        ( Down, \_ -> Stack.only "zeroth" )
    |> Scroll.sideAlter
        ( Up, \_ -> topDown "second" [ "third" ] )
    |> Scroll.focusAlter (fillMap String.toUpper)
    |> Scroll.toStack
--> topDown "zeroth" [ "FIRST", "second", "third" ]
( DirectionLinear
, Emptiable (Stacked item) Possibly
-> Emptiable (Stacked item) possiblyOrNever_
)
-> Scroll item FocusGap possiblyOrNever
-> Scroll item FocusGap possiblyOrNever

Look Down|Up the focus and operate directly an the Stack you see.

sideAlter ( DirectionLinear, \_ -> 🍒🍋 )

Down

🍓 <🍊> 🍉
      ↓
🍋 🍒 <🍊> 🍉

Up

🍍 🍓 <🍊> 🍉
      ↓
🍍 🍓 <🍊> 🍒 🍋
import Linear exposing (DirectionLinear(..))
import Emptiable
import Stack exposing (topDown)


Scroll.only "selectoo"
    |> Scroll.sideAlter
        ( Down, \_ -> topDown "earlee" [ "agua", "enutai" ] )
    |> Scroll.sideAlter
        ( Up, \_ -> topDown "orangloo" [ "iquipy", "oice" ] )
    |> Scroll.sideAlter
        ( Up, \_ -> Emptiable.empty )
    |> Scroll.toStack
--> topDown "enutai" [ "agua", "earlee", "selectoo" ]

sideAlter ( DirectionLinear, Stack.map ... )

import Linear exposing (DirectionLinear(..))
import Stack exposing (topDown)


Scroll.only "second"
    |> Scroll.sideAlter
        ( Down, \_ -> topDown "first" [ "zeroth" ] )
    |> Scroll.sideAlter
        ( Down, Stack.map (\_ -> String.toUpper) )
    |> Scroll.toStack
--> topDown "ZEROTH" [ "FIRST", "second" ]


Scroll.only "zeroth"
    |> Scroll.sideAlter
        ( Up, \_ -> topDown "first" [ "second" ] )
    |> Scroll.sideAlter
        ( Up, Stack.map (\_ -> String.toUpper) )
    |> Scroll.toStack
--> topDown "zeroth" [ "FIRST", "SECOND" ]

Look to one side from the focus and slide items in directly at the nearest location.

sideAlter ( DirectionLinear, Stack.onTopGlue/onTopStack 🍒🍋 )

Down

      🍒🍋
🍍 🍓 \↓/ <🍊> 🍉

Up

        🍒🍋
🍓 <🍊> \↓/ 🍉 🍇
import Linear exposing (DirectionLinear(..))
import Stack exposing (topDown)


Scroll.only 0
    |> Scroll.sideAlter
        ( Down, Stack.onTopGlue [ -4, -5 ] )
    |> Scroll.sideAlter
        ( Down, Stack.onTopStack (topDown -1 [ -2, -3 ]) )
    |> Scroll.toStack
--> topDown -5 [ -4, -3, -2, -1, 0 ]


Scroll.only 0
    |> Scroll.sideAlter
        ( Up, Stack.onTopGlue [ 4, 5 ] )
    |> Scroll.sideAlter
        ( Up, Stack.onTopStack (topDown 1 [ 2, 3 ]) )
    |> Scroll.toStack
--> topDown 0 [ 1, 2, 3, 4, 5 ]

Scroll.sideAlter ( DirectionLinear, \side -> 🍒🍋 |> onTopStack side )

Down

🍋🍒
 \↓ 🍍 🍓 <🍊> 🍉

Up

              🍒🍋
🍓 <🍊> 🍉 🍇 ↓/
import Linear exposing (DirectionLinear(..))
import Stack exposing (topDown, onTopStack)


Scroll.only 1
    |> Scroll.sideAlter
        ( Up, \after -> topDown 2 [ 3, 4 ] |> onTopStack after )
    |> Scroll.toEnd Up
    |> Scroll.sideAlter
        ( Down, \before -> topDown 7 [ 6, 5 ] |> onTopStack before )
    |> Scroll.toStack
--> topDown 5 [ 6, 7, 1, 2, 3, 4 ]


Scroll.only 123
    |> Scroll.sideAlter
        ( Up, \after -> Stack.only 456 |> onTopStack after )
    |> Scroll.sideAlter
        ( Up, \after -> topDown 789 [ 0 ] |> onTopStack after )
    |> Scroll.toStack
--> topDown 123 [ 456, 789, 0 ]

sideAlter ( DirectionLinear,Stack.onTopLay ... )

Down

      🍒
🍍 🍓 ↓ <🍊> 🍉

Up

        🍒
🍓 <🍊> ↓ 🍉 🍇
import Linear exposing (DirectionLinear(..))
import Stack exposing (topDown, onTopLay)


Scroll.only 123
    |> Scroll.sideAlter
        ( Down, onTopLay 456 )
    |> Scroll.toStack
--> topDown 456 [ 123 ]


Scroll.only 123
    |> Scroll.sideAlter
        ( Up, \_ -> Stack.only 789 )
    |> Scroll.sideAlter
        ( Up, onTopLay 456 )
    |> Scroll.toStack
--> topDown 123 [ 456, 789 ]

type-level

(possiblyOrNever -> adaptedPossiblyOrNever)
-> Scroll item FocusGap possiblyOrNever
-> Scroll item FocusGap adaptedPossiblyOrNever

Change the possiblyOrNever type

  • A Scroll ... FocusGap possiblyOrNever can't be used as a Scroll ... Possibly?

    import Possibly exposing (Possibly(..))
    
    
    Scroll.focusGapAdapt (always Possible)
  • A Scroll ... FocusGap Never can't be unified with Scroll ... Possibly or FocusGap possiblyOrNever?

    Scroll.focusGapAdapt never

Please read more at Emptiable.emptyAdapt.

alternatives