{"id":15059524,"url":"https://github.com/jeongoon/elmnt-scrollpicker","last_synced_at":"2026-01-01T23:38:59.893Z","repository":{"id":62418589,"uuid":"434540470","full_name":"jeongoon/elmnt-scrollpicker","owner":"jeongoon","description":"elm-ui compatible scroll picker","archived":false,"fork":false,"pushed_at":"2022-01-30T10:46:16.000Z","size":288,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-21T17:09:58.083Z","etag":null,"topics":["elm","elm-lang","elm-ui","picker","scroll"],"latest_commit_sha":null,"homepage":"https://package.elm-lang.org/packages/jeongoon/elmnt-scrollpicker/latest/","language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"osl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeongoon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-12-03T09:36:01.000Z","updated_at":"2021-12-10T09:39:38.000Z","dependencies_parsed_at":"2022-11-01T16:46:19.323Z","dependency_job_id":null,"html_url":"https://github.com/jeongoon/elmnt-scrollpicker","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeongoon%2Felmnt-scrollpicker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeongoon%2Felmnt-scrollpicker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeongoon%2Felmnt-scrollpicker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeongoon%2Felmnt-scrollpicker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeongoon","download_url":"https://codeload.github.com/jeongoon/elmnt-scrollpicker/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243668239,"owners_count":20328042,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elm","elm-lang","elm-ui","picker","scroll"],"created_at":"2024-09-24T22:44:57.603Z","updated_at":"2026-01-01T23:38:54.862Z","avatar_url":"https://github.com/jeongoon.png","language":"Elm","funding_links":[],"categories":[],"sub_categories":[],"readme":"[setOptions]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#setOptions\n[initMinimalState]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#initMinimalState\n[setScrollStopCheckTime]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#setScrollStopCheckTime\n[subscriptionsWith]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#subscriptionsWith\n[defaultTheme]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#defaultTheme\n[MinimalState]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#MinimalState\n[Option]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#Option\n[Msg]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#Msg\n[anyNewOptionSelected]: /packages/jeongoon/elmnt-scrollpicker/latest/Elmnt-BaseScrollPicker#anyNewOptionSelected\n[exampleUrl]: https://jeongoon.github.io/examples/7Dec2021.BaseScrollPicker.html\n\n# An Elm-Ui friendly Scroll Picker\n\n```shell\nelm install jeongoon/elmnt-scrollpicker\n```\n\n`elmnt-scrollpicker` provides an scroll picker with some animation. `elmnt`\nis stands for [`Element`](https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/)\nso you can use the View(widget) as an element in elm-ui.\n\n[See it in action here.][exampleUrl]\n\n# Usage\n\nThis is low level module, So let me examplain fully. however If you are familiar\nwith other *Elm architecture* style module, it is easier. Or you have\nchance to get used to it.\n\n## Import\n\n```elm\nimport Element exposing (..)\nimport Dict exposing (Dict)\n                     -- ^ options are stored in Dict\nimport Elmnt.BaseScrollPicker as ScrollPicker\n                                 -- ^ or as you'd like\n```\n\n## Make your own Model and Msg\n\n```elm\ntype AppMsg\n     = ScrollPickerMessage String\n       (ScrollPicker.Msg Int AppMsg)\n```\n\nScrollPicker.Msg type involves the type of Your own message (AppMsg)\nand also the type of options that we'd like to pick from.\n`Int` is used for [`Option`][Option] in this case.\n\nSome states of picker are required to store in internal record.\nyou might need to declare your own message wrapper\nconstructor *ScrollPickerMessage* is an wrapper constructor (or map function) to\ncreate messages which is compatible to your own module message.\n\n\nLet's say we are making a simple time picker, we need two seprate\npickers for hour and minute value. If you want a Dict or List\ngo for it!\n\n\n```elm\ntype alias Model -- which is your own model\n    = { firstPickerState\n         : ScrollPicker.MinimalState Int AppMsg\n      , secondPickerState\n         : ScrollPicker.MinimalState Int AppMsg\n      , messageMapWith\n         : String -\u003e (ScrollPicker.Msg Int AppMsg) -\u003e\n           AppMsg\n      , pickerDirection\n         : ScrollPicker.Direction -- Horizontal or Vertical\n      }\n```\n\n\n## Model\n\n[`MinimalState`][MinimalState] shows the minimal states required to work\nas a scroll picker. And even if you put *more* fields in your record,\nall the function will still works with yours. Because the most of API\nuse partial record annotation.\n\nFor example [`setOptions`][setOptions] function has the definition like below.\n\n```elm\nsetOptions\n    : (vt -\u003e String) -\u003e -- vt stands for 'value type'\n      List (vt, Element msg) -\u003e\n      { state |\n        idString  : String\n      , optionIds : List String\n      , optionIdToRecordDict : Dict String\n                               (Option vt msg)\n      } -\u003e -- At least, those fields are required\n           -- in the state record\n      { state |\n        idString  : String\n      , optionIds : List String\n      , optionIdToRecordDict : Dict String\n                               (Option vt msg)\n      } --\u003e will return the same structure of\n        --  the state record\n  ```\n\nwhich makes setOptions can be provided with a subset of MinimalState.\n\n\n## Init\nLet's initialise our example model. Each picker model(or state) could be\ninitialised with functions such as [`initMinimalState`][initMinimalState],\n[`setOptions`][setOptions] and [`setScrollStopCheckTime`][setScrollStopCheckTime]\n\n\n```elm\nexampleInit : () -\u003e ( Model, Cmd AppMsg )\nexampleInit flags\n    = ( { firstPickerState -- for hour value\n              = ScrollPicker.initMinimalState\n                \"firstScrollPicker\" -- id\n              |\u003e ScrollPicker.setOptions\n                 (String.fromInt)\n                 (List.range 1 12\n                    |\u003e List.map\n                       ( \\n -\u003e\n                            ( n\n                            , n\n                              |\u003e ( String.fromInt \u003e\u003e text )\n                            )\n                       )\n                 )\n              |\u003e ScrollPicker.setScrollStopCheckTime 75\n                 -- ^ a bit more quicker to check\n\n        , secondPickerState -- for minute value\n              = ScrollPicker.initMinimalState\n                \"secondScrollPicker\"\n              |\u003e ScrollPicker.setOptions\n                 (String.fromInt)\n                 (List.range 0 59\n                    |\u003e List.map\n                       ( \\n -\u003e\n                           ( n\n                           , n\n                             |\u003e ( String.fromInt\n                                    \u003e\u003e String.padLeft 2 '0'\n                                    \u003e\u003e text\n                                )\n                           )\n                       )\n                 )\n\n        , messageMapWith\n            = ScrollPickerMessage\n          -- ^ a map function to wrap the picker messages\n          --   into the Msg\n\n        , pickerDirection\n            = ScrollPicker.Vertical\n        }              \n```\n\n## Update\n\nIn your own update function, you might need to check picker Id and update\nthe matched picker state(or model) accordingly.\n\n```elm\nexampleUpdate : AppMsg -\u003e Model -\u003e\n                ( Model, Cmd AppMsg )\nexampleUpdate msg model\n    = let update\n              = ScrollPicker.updateWith model\n      in\n      case msg of\n          ScrollPickerMessage idString pickerMsg -\u003e\n              case idString of\n                  \"firstScrollPicker\" -\u003e\n                      let ( firstPickerState, cmd )\n                              = update pickerMsg\n                                  model.firstPickerState\n\n                          newModel\n                              = { model |\n                                  firstPickerState\n                                      = firstPickerState\n                                }\n                              \n                      in ( case ScrollPicker.anyNewOptionSelected\n                                  pickerMsg of\n\n                               Just option -\u003e\n                                   { newModel |\n                                     hourValue\n                                         = option.value\n                                   }\n                               Nothing -\u003e\n                                   newModel\n                           , cmd\n                         )\n\n                  \"secondScrollPicker\" -\u003e\n                      let ( secondPickerState, cmd )\n                              = update pickerMsg\n                                  model.secondPickerState\n\n                          newModel\n                              = { model |\n                                  secondPickerState\n                                      = secondPickerState\n                                }\n                              \n                      in ( case ScrollPicker.anyNewOptionSelected\n                                  pickerMsg of\n\n                               Just option -\u003e\n                                   { newModel |\n                                     minuteValue\n                                        = option.value\n                                   }\n                               Nothing -\u003e\n                                   newModel\n                           , cmd\n                         )\n\n                  _ -\u003e\n                      ( model, Cmd.none )\n```\n\nAnd picker model itself *does not* hold selected option, you also need to\ncheck some message [`Elmnt.BasePickerState.ScrollPickerSuccess`][Msg]\nor you can use [`anyNewOptionSelected`][anyNewOptionSelected] function like above code.\n\n## View\n\nHere is an example\n\n```elm\nexampleView : Model -\u003e Html AppMsg\nexampleView model\n    = let\n        theme\n            = defaultTheme\n\n        palette\n            = theme.palette\n\n        pickerHelper\n            = ScrollPicker.viewAsElement model theme\n\n   in\n       layout [ Background.color\n                (palette.on.surface \n                    -- ^ use same color as shade\n                    |\u003e palette.toElmUiColor)\n              ] \u003c|\n           column [ centerX\n                  , centerY\n                  ]\n               [ row [ spacing 1\n                     ]\n                     [ pickerHelper model.firstPickerState\n                     , pickerHelper model.secondPickerState\n                     ]\n\n               , el [ paddingEach\n                        { top    = 20\n                        , right  = 0\n                        , bottom = 0\n                        , left   = 0\n                        }\n                    , Font.size\n                        ( (modular 16 1.25 8)\n                              |\u003e (*) 0.7\n                              |\u003e truncate\n                        )\n                    , Font.color\n                          ( palette.secondary\n                                |\u003e palette.toElmUiColor )\n                    , centerX\n                    ] \u003c|\n                   text \u003c| \"It's \" ++\n                       ( model.hourValue\n                            |\u003e String.fromInt\n                       ) ++ \":\" ++\n                       ( model.minuteValue\n                            |\u003e String.fromInt\n                            |\u003e String.padLeft 2 '0'\n                       )\n           ]\n```\n\n## Subscriptions\n\nAnimation relies on subscriptions. elm-style-animation also does so.\n[`subscriptionsWith`][subscriptionsWith] helps how to subscribe.\n\n```elm\nexampleSubscriptions : Model -\u003e Sub AppMsg\nexampleSubscriptions model\n    = model |\u003e\n      ScrollPicker.subscriptionsWith\n      [ model.firstPickerState\n      , model.secondPickerState\n      ]\n```\n\n## Main\n\nFinally you can wire thems up in the elm architecture.\n\n```elm\nmain : Program () Model AppMsg\nmain\n    = Browser.element\n      { init = exampleInit\n      , view = exampleView\n      , update = exampleUpdate\n      , subscriptions = exampleSubscriptions\n      }\n```\n\n# Testing Environment\n\n- Firefox (currently 94.0.1) on Arch linux\n- Vivaldi\n- [`Gnome Web Epiphany`](https://apps.gnome.org/en-GB/app/org.gnome.Epiphany/)\n\nI'm a chef and not a professional programmer but have been still using Linux\nsince 2001. My 8 years old laptop can only run Linux smoothly.\nAnd I don't have enough chance to check things on Apple product, either.\n\nso, if you need more techincal support on other platform, please contribute\nyour solution.\n\n\n# More Information\n**Why elm-style-animation?** [`elm-style-animation`](/packages/mdgriffith/elm-style-animation/latest)\nis not quite designed for low level animation. but you could use the module\nfor any other css-style based animation. So you could possibly add other\nanimation in your app without any additional module.\n\n[`elm-animation`](/packages/mgold/elm-animation/latest) was also considered,\nand *it is* pretty straight-foward.\nHowever the module cannot live together in the same application due to name\ncolision.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeongoon%2Felmnt-scrollpicker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeongoon%2Felmnt-scrollpicker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeongoon%2Felmnt-scrollpicker/lists"}