├── .gitignore
├── examples
├── pwa
│ ├── assets
│ │ └── prod
│ │ │ ├── icons
│ │ │ ├── 128.png
│ │ │ ├── 144.png
│ │ │ ├── 152.png
│ │ │ ├── 16.png
│ │ │ ├── 192.png
│ │ │ ├── 256.png
│ │ │ ├── 32.png
│ │ │ ├── 512.png
│ │ │ └── 64.png
│ │ │ ├── fonts
│ │ │ ├── OCRA.otf
│ │ │ ├── RakutenSansUI_W_Bd.woff
│ │ │ ├── RakutenSansUI_W_Bd.woff2
│ │ │ ├── RakutenSansUI_W_Blk.woff
│ │ │ ├── RakutenSansUI_W_Blk.woff2
│ │ │ ├── RakutenSansUI_W_Lt.woff
│ │ │ ├── RakutenSansUI_W_Lt.woff2
│ │ │ ├── RakutenSansUI_W_Rg.woff
│ │ │ └── RakutenSansUI_W_Rg.woff2
│ │ │ └── images
│ │ │ ├── form.png
│ │ │ ├── r10.png
│ │ │ ├── view.png
│ │ │ ├── buttons.png
│ │ │ ├── makers.png
│ │ │ ├── palette.png
│ │ │ ├── base_500.png
│ │ │ ├── buttons300.png
│ │ │ ├── examples.png
│ │ │ ├── form-tree.png
│ │ │ ├── examples-600.png
│ │ │ ├── system-color.png
│ │ │ ├── material-colors.png
│ │ │ ├── okaimonopanda.gif
│ │ │ ├── colors-overview1.png
│ │ │ └── colors-overview400.png
│ ├── src-elm-starter
│ │ ├── Starter
│ │ │ ├── Version.elm
│ │ │ ├── Model.elm
│ │ │ ├── ConfMain.elm
│ │ │ ├── SnippetCss.elm
│ │ │ ├── Icon.elm
│ │ │ ├── FileNames.elm
│ │ │ ├── Cache.elm
│ │ │ ├── ConfMeta.elm
│ │ │ ├── Manifest.elm
│ │ │ ├── ServiceWorker.elm
│ │ │ ├── ElmGo.elm
│ │ │ └── SnippetJavascript.elm
│ │ ├── String
│ │ │ └── Conversions.elm
│ │ ├── Worker.elm
│ │ ├── Html
│ │ │ └── String
│ │ │ │ ├── Keyed.elm
│ │ │ │ ├── Extra.elm
│ │ │ │ └── Lazy.elm
│ │ └── Application.elm
│ ├── elm-analyse.json
│ ├── review
│ │ ├── elm.json
│ │ └── src
│ │ │ └── ReviewConfig.elm
│ ├── elm.json
│ ├── package.json
│ └── src
│ │ └── Pages
│ │ ├── Counter.elm
│ │ ├── Form_Example_PhoneSelector.elm
│ │ └── Form_Entities.elm
├── simpleView
│ ├── elm.json
│ └── src
│ │ └── Main.elm
├── simpleForm
│ ├── elm.json
│ └── src
│ │ └── Main.elm
└── creditCardForm
│ └── elm.json
├── src
└── R10
│ ├── Utils.elm
│ ├── Table
│ └── Internal
│ │ ├── Msg.elm
│ │ ├── Cell.elm
│ │ ├── State.elm
│ │ ├── Types.elm
│ │ ├── Style.elm
│ │ ├── Svg.elm
│ │ ├── Config.elm
│ │ ├── Sorter.elm
│ │ └── Placeholder.elm
│ ├── When.elm
│ ├── Form
│ ├── Internal
│ │ ├── QtySubmitAttempted.elm
│ │ ├── Dict.elm
│ │ ├── TempSubmitButton.elm
│ │ ├── ValidationCode.elm
│ │ ├── Key.elm
│ │ ├── StateForValues.elm
│ │ ├── Msg.elm
│ │ ├── MakerForValidationKeys.elm
│ │ ├── State.elm
│ │ └── MakerForValues.elm
│ └── README.md
│ ├── FormComponents
│ └── Internal
│ │ ├── UI
│ │ ├── Const.elm
│ │ └── Color.elm
│ │ ├── Style.elm
│ │ ├── Utils
│ │ └── FocusOut.elm
│ │ ├── TextColors.elm
│ │ ├── ExtraCss.elm
│ │ ├── IconButton.elm
│ │ ├── Phone
│ │ └── Common.elm
│ │ └── Single
│ │ └── Common.elm
│ ├── Theme.elm
│ ├── Link.elm
│ ├── FontSize.elm
│ ├── CountryCode.elm
│ ├── Mode.elm
│ ├── Transition.elm
│ ├── Card.elm
│ ├── Footer.elm
│ ├── Translations.elm
│ ├── Libu.elm
│ ├── Svg
│ └── Utils.elm
│ ├── Paragraph.elm
│ ├── ValidationDate.elm
│ ├── Color
│ ├── Utils.elm
│ └── AttrsBorder.elm
│ ├── LanguageSelector.elm
│ ├── Alert.elm
│ ├── Color.elm
│ ├── FormDebug.elm
│ └── DropDown.elm
├── LICENSE
├── elm.json
├── PUBLISHING.md
├── CHANGELOG.md
├── CONTRIBUTING.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | elm-stuff
2 | node_modules
3 | Elmjutsu*
4 | build
5 | elm.js
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/128.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/144.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/152.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/16.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/192.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/256.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/32.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/512.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/icons/64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/icons/64.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/OCRA.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/OCRA.otf
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/form.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/r10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/r10.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/view.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/buttons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/buttons.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/makers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/makers.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/palette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/palette.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/base_500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/base_500.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/buttons300.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/buttons300.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/examples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/examples.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/form-tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/form-tree.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/examples-600.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/examples-600.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/system-color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/system-color.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/material-colors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/material-colors.png
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/okaimonopanda.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/okaimonopanda.gif
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/colors-overview1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/colors-overview1.png
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/Version.elm:
--------------------------------------------------------------------------------
1 | module Starter.Version exposing (version)
2 |
3 |
4 | version : String
5 | version =
6 | "0.0.1"
7 |
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Bd.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Bd.woff
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Bd.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Bd.woff2
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Blk.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Blk.woff
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Blk.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Blk.woff2
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Lt.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Lt.woff
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Lt.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Lt.woff2
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Rg.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Rg.woff
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Rg.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/fonts/RakutenSansUI_W_Rg.woff2
--------------------------------------------------------------------------------
/examples/pwa/assets/prod/images/colors-overview400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rakutentech/r10/HEAD/examples/pwa/assets/prod/images/colors-overview400.png
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/Model.elm:
--------------------------------------------------------------------------------
1 | module Starter.Model exposing (Model)
2 |
3 | import Starter.Flags
4 |
5 |
6 | type alias Model =
7 | Starter.Flags.Flags
8 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/String/Conversions.elm:
--------------------------------------------------------------------------------
1 | module String.Conversions exposing (fromValue)
2 |
3 | import Json.Encode
4 |
5 |
6 | {-| Convert a Json.Decode.Value to a JSON String.
7 | -}
8 | fromValue : Json.Encode.Value -> String
9 | fromValue value =
10 | Json.Encode.encode 0 value
11 |
--------------------------------------------------------------------------------
/src/R10/Utils.elm:
--------------------------------------------------------------------------------
1 | module R10.Utils exposing (..)
2 |
3 | import Regex
4 |
5 |
6 | userReplace : String -> (Regex.Match -> String) -> String -> String
7 | userReplace userRegex replacer string =
8 | case Regex.fromString userRegex of
9 | Nothing ->
10 | string
11 |
12 | Just regex ->
13 | Regex.replace regex replacer string
14 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/Msg.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.Msg exposing (Msg(..))
2 |
3 | import R10.Form
4 | import R10.Table.Internal.Types
5 |
6 |
7 | type Msg
8 | = Sort String Bool
9 | | PaginatorNextPage
10 | | PaginatorPrevPage
11 | | PaginatorLengthOption Int
12 | | FiltersTogglePopup R10.Table.Internal.Types.Filter
13 | | FilterClear String
14 | | FiltersPopupFormMsg R10.Form.Msg
15 |
--------------------------------------------------------------------------------
/src/R10/When.elm:
--------------------------------------------------------------------------------
1 | module R10.When exposing (do, otherwise, when)
2 |
3 | -- To be used as
4 | --
5 | -- x = 10 == 10
6 | --
7 | -- when x do ... otherwise ...
8 |
9 |
10 | type Do
11 | = Do
12 |
13 |
14 | type Otherwise
15 | = Otherwise
16 |
17 |
18 | do : Do
19 | do =
20 | Do
21 |
22 |
23 | otherwise : Otherwise
24 | otherwise =
25 | Otherwise
26 |
27 |
28 | when : Bool -> Do -> b -> Otherwise -> b -> b
29 | when a _ b _ c =
30 | if a then
31 | b
32 |
33 | else
34 | c
35 |
--------------------------------------------------------------------------------
/examples/pwa/elm-analyse.json:
--------------------------------------------------------------------------------
1 | {
2 | "checks": {
3 | "ExposeAll": true,
4 | "SingleFieldRecord": false,
5 | "UnnecessaryParens": false,
6 | "ImportAll": false,
7 | "UseConsOverConcat": false,
8 | "MultiLineRecordFormatting": false,
9 | "MapNothingToNothing": false,
10 | "TriggerWords": false,
11 | "DropConcatOfLists": false
12 | },
13 | "TriggerWords": {
14 | "words": ["test"]
15 | },
16 | "excludedPaths": [
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/ConfMain.elm:
--------------------------------------------------------------------------------
1 | module Starter.ConfMain exposing
2 | ( Conf
3 | , encoder
4 | )
5 |
6 | import Json.Encode
7 |
8 |
9 | type alias Conf =
10 | { urls : List String
11 | , assetsToCache : List String
12 | }
13 |
14 |
15 | encoder : Conf -> Json.Encode.Value
16 | encoder mainConf_ =
17 | Json.Encode.object
18 | [ ( "urls", Json.Encode.list Json.Encode.string mainConf_.urls )
19 | , ( "assetsToCache", Json.Encode.list Json.Encode.string mainConf_.assetsToCache )
20 | ]
21 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Worker.elm:
--------------------------------------------------------------------------------
1 | port module Worker exposing (main)
2 |
3 | import Json.Encode
4 | import Starter.Conf
5 | import Starter.Flags
6 | import Starter.Model
7 |
8 |
9 | port dataFromElmToJavascript : Json.Encode.Value -> Cmd msg
10 |
11 |
12 | main : Program Starter.Flags.Flags Starter.Model.Model msg
13 | main =
14 | Platform.worker
15 | { init = \flags -> ( flags, dataFromElmToJavascript (Starter.Conf.conf_ flags) )
16 | , update = \_ model -> ( model, Cmd.none )
17 | , subscriptions = \_ -> Sub.none
18 | }
19 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/SnippetCss.elm:
--------------------------------------------------------------------------------
1 | module Starter.SnippetCss exposing (noJsAndLoadingNotifications)
2 |
3 |
4 | noJsAndLoadingNotifications : String -> String
5 | noJsAndLoadingNotifications classNotification =
6 | """
7 | .""" ++ classNotification ++ """
8 | { padding: 20px
9 | ; background-color: rgba(255,255,255,0.7)
10 | ; pointer-events: none
11 | ; color: black
12 | ; width: 100%
13 | ; text-align: center
14 | ; position: fixed
15 | ; left: 0
16 | ; z-index: 1
17 | ; box-sizing: border-box
18 | }
19 | """
20 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/Icon.elm:
--------------------------------------------------------------------------------
1 | module Starter.Icon exposing
2 | ( iconFileName
3 | , iconsForManifest
4 | , iconsToBeCached
5 | )
6 |
7 |
8 | iconsForManifest : List number
9 | iconsForManifest =
10 | [ 128, 144, 152, 192, 256, 512 ]
11 |
12 |
13 | iconsToBeCached : List number
14 | iconsToBeCached =
15 | [ 16, 32, 64 ] ++ iconsForManifest
16 |
17 |
18 | iconFileName : String -> Int -> String
19 | iconFileName relative size =
20 | let
21 | sizeString =
22 | String.fromInt size
23 | in
24 | relative ++ "/icons/" ++ sizeString ++ ".png"
25 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/QtySubmitAttempted.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.QtySubmitAttempted exposing
2 | ( QtySubmitAttempted
3 | , fromInt
4 | , increment
5 | , toInt
6 | )
7 |
8 |
9 | type QtySubmitAttempted
10 | = QtySubmitAttempted Int
11 |
12 |
13 | toInt : QtySubmitAttempted -> Int
14 | toInt (QtySubmitAttempted int) =
15 | int
16 |
17 |
18 | fromInt : Int -> QtySubmitAttempted
19 | fromInt int =
20 | QtySubmitAttempted int
21 |
22 |
23 | increment : QtySubmitAttempted -> QtySubmitAttempted
24 | increment qtySubmitAttempted =
25 | fromInt (toInt qtySubmitAttempted + 1)
26 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/Dict.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.Dict exposing
2 | ( get
3 | , insert
4 | , update
5 | )
6 |
7 | import Dict
8 | import R10.Form.Internal.Key
9 |
10 |
11 | get : R10.Form.Internal.Key.Key -> Dict.Dict String v -> Maybe v
12 | get key =
13 | Dict.get (R10.Form.Internal.Key.toString key)
14 |
15 |
16 | update : R10.Form.Internal.Key.Key -> (Maybe v -> Maybe v) -> Dict.Dict String v -> Dict.Dict String v
17 | update key =
18 | Dict.update (R10.Form.Internal.Key.toString key)
19 |
20 |
21 | insert : R10.Form.Internal.Key.Key -> v -> Dict.Dict String v -> Dict.Dict String v
22 | insert key =
23 | Dict.insert (R10.Form.Internal.Key.toString key)
24 |
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/UI/Const.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.UI.Const exposing
2 | ( inputTextFilledDown
3 | , inputTextFontSize
4 | , inputTextHeight
5 | )
6 |
7 | import R10.FontSize
8 |
9 |
10 | inputTextHeight : number
11 | inputTextHeight =
12 | -- This need to be at least 50 otherwise the
13 | -- Chrome auto-suggestion functionality
14 | -- is covering hiding the lower border
15 | --
16 | -- https://jira.rakuten-it.com/jira/browse/OMN-1936
17 | --
18 | 50
19 |
20 |
21 | inputTextFontSize : Int
22 | inputTextFontSize =
23 | R10.FontSize.normalAsInt
24 |
25 |
26 | inputTextFilledDown : number
27 | inputTextFilledDown =
28 | 8
29 |
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/Style.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.Style exposing (Style(..), default, fromString, toString)
2 |
3 |
4 | type Style
5 | = FloatingLabels
6 | | FixedLabels
7 |
8 |
9 | toString : Style -> String
10 | toString style =
11 | case style of
12 | FloatingLabels ->
13 | "floatingLabels"
14 |
15 | FixedLabels ->
16 | "fixedLabels"
17 |
18 |
19 | fromString : String -> Style
20 | fromString string =
21 | case string of
22 | "floatingLabels" ->
23 | FloatingLabels
24 |
25 | "fixedLabels" ->
26 | FixedLabels
27 |
28 | _ ->
29 | default
30 |
31 |
32 | default : Style
33 | default =
34 | FloatingLabels
35 |
--------------------------------------------------------------------------------
/src/R10/Theme.elm:
--------------------------------------------------------------------------------
1 | module R10.Theme exposing (Theme, fromFlags)
2 |
3 | {-| This is how we store information about the primary color used and if the site is in light or dark mode.
4 |
5 | Most of the application use only one primary color but some are configurable and can be used with different colors.
6 |
7 | @docs Theme, fromFlags
8 |
9 | -}
10 |
11 | import R10.Color.Internal.Primary
12 | import R10.Mode
13 |
14 |
15 | {-| -}
16 | type alias Theme =
17 | { mode : R10.Mode.Mode
18 | , primaryColor : R10.Color.Internal.Primary.Color
19 | }
20 |
21 |
22 | {-| Usually `mode` and `primaryColor` are stored in the flags. Use this helper to create a `Theme` from flags.
23 | -}
24 | fromFlags :
25 | { a
26 | | mode : R10.Mode.Mode
27 | , primaryColor : R10.Color.Internal.Primary.Color
28 | }
29 | -> Theme
30 | fromFlags flags =
31 | { mode = flags.mode
32 | , primaryColor = flags.primaryColor
33 | }
34 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/FileNames.elm:
--------------------------------------------------------------------------------
1 | module Starter.FileNames exposing
2 | ( FileNames
3 | , fileNames
4 | )
5 |
6 |
7 | type alias FileNames =
8 | { outputCompiledJs : String
9 | , outputCompiledJsProd : String
10 | , indexHtml : String
11 | , manifestJson : String
12 | , redirects : String
13 | , robotsTxt : String
14 | , serviceWorker : String
15 | , sitemap : String
16 | , snapshot : String
17 | }
18 |
19 |
20 | fileNames : String -> String -> FileNames
21 | fileNames version commit =
22 | { manifestJson = "/manifest.json"
23 | , redirects = "/_redirects"
24 | , robotsTxt = "/robots.txt"
25 | , outputCompiledJs = "/elm.js"
26 | , outputCompiledJsProd = "/elm-" ++ version ++ "-" ++ commit ++ ".min.js"
27 | , indexHtml = "/index.html"
28 | , serviceWorker = "/service-worker.js"
29 | , sitemap = "/sitemap.txt"
30 | , snapshot = "/snapshot.jpg"
31 | }
32 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/Cache.elm:
--------------------------------------------------------------------------------
1 | module Starter.Cache exposing (stuffToCache)
2 |
3 | import Main
4 | import Starter.FileNames
5 |
6 |
7 | stuffToCache : String -> String -> String -> List ( String, String ) -> List ( String, String )
8 | stuffToCache relative version commit assets =
9 | let
10 | fileNames =
11 | Starter.FileNames.fileNames version commit
12 | in
13 | []
14 | -- Production elm.js
15 | ++ [ ( relative ++ fileNames.outputCompiledJsProd, version ) ]
16 | -- manifest.json
17 | ++ [ ( relative ++ fileNames.manifestJson, version ) ]
18 | -- Static pages coming from src/Main.elm
19 | ++ List.map (\url -> ( url, version )) Main.conf.urls
20 | -- Extra stuff coming from src/Main.elm
21 | ++ List.map (\url -> ( url, version )) Main.conf.assetsToCache
22 | ++ assets
23 | |> List.map (\( url, hash ) -> ( String.replace "//" "/" url, hash ))
24 |
--------------------------------------------------------------------------------
/src/R10/Link.elm:
--------------------------------------------------------------------------------
1 | module R10.Link exposing (attrs, attrsUnderline)
2 |
3 | {-|
4 |
5 | @docs attrs, attrsUnderline
6 |
7 | -}
8 |
9 | import Element.WithContext exposing (..)
10 | import Element.WithContext.Font as Font
11 | import R10.Color.AttrsFont
12 | import R10.Context exposing (..)
13 | import R10.Transition
14 |
15 |
16 | {-| Attributes for links, useful if you need to make some text to render as if it was a link.
17 | -}
18 | attrs : List (Attr (R10.Context.ContextInternal z) () msg)
19 | attrs =
20 | [ R10.Color.AttrsFont.link
21 | , mouseOver [ R10.Color.AttrsFont.linkOver ]
22 | , transition
23 | ]
24 |
25 |
26 | {-| -}
27 | attrsUnderline : List (Attr (R10.Context.ContextInternal z) () msg)
28 | attrsUnderline =
29 | [ Font.underline
30 | , R10.Color.AttrsFont.link
31 | , mouseOver [ R10.Color.AttrsFont.linkOver ]
32 | , transition
33 | ]
34 |
35 |
36 | transition : Attribute (R10.Context.ContextInternal z) msg
37 | transition =
38 | R10.Transition.transition "color .2s ease-out, background-color .2s ease-out"
39 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/Cell.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.Cell exposing (simpleCell)
2 |
3 | import Element.WithContext exposing (..)
4 | import Element.WithContext.Font as Font
5 | import R10.Context exposing (..)
6 | import R10.FormComponents.Internal.UI.Color
7 | import R10.Palette
8 | import R10.Table.Internal.Placeholder
9 | import R10.Table.Internal.Style
10 |
11 |
12 | simpleCell : List (Attribute (R10.Context.ContextInternal z) msg) -> (Maybe data -> Maybe String) -> R10.Palette.Palette -> Maybe data -> Element (R10.Context.ContextInternal z) msg
13 | simpleCell attrs toStr palette maybeData =
14 | row
15 | (R10.Table.Internal.Style.defaultCellAttrs ++ attrs)
16 | (case toStr maybeData of
17 | Just str ->
18 | [ paragraph
19 | [ Font.color <| R10.FormComponents.Internal.UI.Color.onSurface palette ]
20 | [ text str ]
21 | ]
22 |
23 | Nothing ->
24 | [ R10.Table.Internal.Placeholder.view (R10.FormComponents.Internal.UI.Color.primary palette) [] ]
25 | )
26 |
--------------------------------------------------------------------------------
/examples/simpleView/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": [
4 | "src",
5 | "../../src"
6 | ],
7 | "elm-version": "0.19.1",
8 | "dependencies": {
9 | "direct": {
10 | "avh4/elm-color": "1.0.0",
11 | "elm/browser": "1.0.2",
12 | "elm/core": "1.0.5",
13 | "elm/html": "1.0.0",
14 | "elm/json": "1.1.3",
15 | "elm/regex": "1.0.0",
16 | "elm/svg": "1.0.1",
17 | "elm/url": "1.0.0",
18 | "elm-community/string-extra": "4.0.1",
19 | "lucamug/elm-ui-with-context": "1.0.0",
20 | "mdgriffith/elm-ui": "1.1.8",
21 | "noahzgordon/elm-color-extra": "1.0.2",
22 | "zwilias/json-decode-exploration": "6.0.0"
23 | },
24 | "indirect": {
25 | "elm/random": "1.0.0",
26 | "elm/time": "1.0.0",
27 | "elm/virtual-dom": "1.0.2",
28 | "fredcy/elm-parseint": "2.0.1",
29 | "mgold/elm-nonempty-list": "4.1.0"
30 | }
31 | },
32 | "test-dependencies": {
33 | "direct": {},
34 | "indirect": {}
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/R10/Form/README.md:
--------------------------------------------------------------------------------
1 | TODO
2 |
3 | * FIX the problem of the duplcate helperSignin_M03_Submit
4 | * Use border color as primary color for the form library(?), also for links
5 | * FIx the view, so that the button is active at start R06
6 | * Check search input field in dropdowns
7 | * Fix fields in http://localhost:8002/#/r99
8 | * Green errors in password fields (wrong translations)
9 |
10 |
11 |
12 | ## Validations
13 |
14 | Validations are done
15 |
16 | * R10.Form.Internal.Update.onChangeValue (only for few fields, calling "runOnlyExistingValidations")
17 | * "validateEntireForm" instead run "runAllValidations", used when the submit buttons is pressed.
18 |
19 |
20 | ## Logic of fromFieldStateValidationToComponentValidation
21 |
22 | * R10.Form.Internal.Converter.fromFieldStateValidationToComponentValidation
23 |
24 | type alias ValidationSpecs =
25 | { showAlsoPassedValidation : Bool
26 | , pretendIsNotValidatedIfValid : Bool
27 | , validation : List Validation
28 | , validationIcon : R10.FormTypes.ValidationIcon
29 | }
30 |
31 |
32 | The main function for validations is R10.Form.Internal.Validation.validate
33 |
34 |
35 | shouldValidationBeVisible
--------------------------------------------------------------------------------
/src/R10/Form/Internal/TempSubmitButton.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.TempSubmitButton exposing (button)
2 |
3 | import Element.WithContext exposing (..)
4 | import Element.WithContext.Background as Background
5 | import Element.WithContext.Border as Border
6 | import Element.WithContext.Font as Font
7 | import Element.WithContext.Input as Input
8 | import R10.Context exposing (..)
9 | import R10.Form
10 | import R10.Form.Internal.Msg
11 | import R10.Form.Internal.Update
12 |
13 |
14 | button : R10.Form.Form -> (R10.Form.Internal.Msg.Msg -> msg) -> Element (R10.Context.ContextInternal z) msg
15 | button form msgMapper =
16 | let
17 | submittable : Bool
18 | submittable =
19 | R10.Form.Internal.Update.isFormSubmittable form
20 | in
21 | map msgMapper <|
22 | Input.button
23 | [ padding 20
24 | , Border.rounded 6
25 | , Font.color <| rgb 1 1 1
26 | , Background.color <|
27 | if submittable then
28 | rgb 0 0.5 0
29 |
30 | else
31 | rgb 0.5 0 0
32 | ]
33 | { label = text "Submit"
34 | , onPress = Just <| R10.Form.Internal.Msg.Submit form.conf
35 | }
36 |
--------------------------------------------------------------------------------
/src/R10/FontSize.elm:
--------------------------------------------------------------------------------
1 | module R10.FontSize exposing
2 | ( large, normal, small, xlarge, xxlarge, xsmall, xxsmall
3 | , normalAsInt
4 | )
5 |
6 | {-| Font sizes
7 |
8 | @docs large, normal, small, xlarge, xxlarge, xsmall, xxsmall
9 |
10 | @docs normalAsInt
11 |
12 | -}
13 |
14 | import Element.WithContext exposing (..)
15 | import Element.WithContext.Font as Font
16 | import R10.Context exposing (..)
17 |
18 |
19 | {-| -}
20 | xlarge : Attr (R10.Context.ContextInternal z) decorative msg
21 | xlarge =
22 | Font.size 24
23 |
24 |
25 | {-| -}
26 | xxlarge : Attr (R10.Context.ContextInternal z) decorative msg
27 | xxlarge =
28 | Font.size 32
29 |
30 |
31 | {-| -}
32 | large : Attr (R10.Context.ContextInternal z) decorative msg
33 | large =
34 | Font.size 20
35 |
36 |
37 | {-| -}
38 | normalAsInt : Int
39 | normalAsInt =
40 | 16
41 |
42 |
43 | {-| -}
44 | normal : Attr (R10.Context.ContextInternal z) decorative msg
45 | normal =
46 | Font.size normalAsInt
47 |
48 |
49 | {-| -}
50 | small : Attr (R10.Context.ContextInternal z) decorative msg
51 | small =
52 | Font.size 14
53 |
54 |
55 | {-| -}
56 | xsmall : Attr (R10.Context.ContextInternal z) decorative msg
57 | xsmall =
58 | Font.size 13
59 |
60 |
61 | {-| -}
62 | xxsmall : Attr (R10.Context.ContextInternal z) decorative msg
63 | xxsmall =
64 | Font.size 12
65 |
--------------------------------------------------------------------------------
/examples/pwa/review/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": [
4 | "src"
5 | ],
6 | "elm-version": "0.19.1",
7 | "dependencies": {
8 | "direct": {
9 | "elm/core": "1.0.5",
10 | "elm/json": "1.1.3",
11 | "elm/project-metadata-utils": "1.0.1",
12 | "jfmengels/elm-review": "2.3.2",
13 | "jfmengels/elm-review-unused": "1.1.2",
14 | "jfmengels/review-common": "1.2.3",
15 | "leojpod/review-no-empty-html-text": "1.0.2",
16 | "stil4m/elm-syntax": "7.1.3"
17 | },
18 | "indirect": {
19 | "elm/html": "1.0.0",
20 | "elm/parser": "1.1.0",
21 | "elm/random": "1.0.0",
22 | "elm/time": "1.0.0",
23 | "elm/url": "1.0.0",
24 | "elm/virtual-dom": "1.0.2",
25 | "elm-community/json-extra": "4.3.0",
26 | "elm-community/list-extra": "8.2.4",
27 | "elm-explorations/test": "1.2.2",
28 | "rtfeldman/elm-hex": "1.0.0",
29 | "rtfeldman/elm-iso8601-date-strings": "1.1.3",
30 | "stil4m/structured-writer": "1.0.3"
31 | }
32 | },
33 | "test-dependencies": {
34 | "direct": {
35 | "elm-explorations/test": "1.2.2"
36 | },
37 | "indirect": {}
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/R10/CountryCode.elm:
--------------------------------------------------------------------------------
1 | -- Eventually we could make this the same as R10.Country, but for the moment
2 | -- this is a much simpler version
3 |
4 |
5 | module R10.CountryCode exposing
6 | ( CountryCode(..)
7 | , decoder
8 | , default
9 | , fromString
10 | , isJapan
11 | , toString
12 | )
13 |
14 | import Json.Decode.Exploration
15 |
16 |
17 | type CountryCode
18 | = JP
19 | | DE
20 | | Others String
21 |
22 |
23 | default : CountryCode
24 | default =
25 | Others "tw"
26 |
27 |
28 | decoder : Json.Decode.Exploration.Decoder CountryCode
29 | decoder =
30 | Json.Decode.Exploration.string
31 | |> Json.Decode.Exploration.andThen
32 | (\string -> Json.Decode.Exploration.succeed <| fromString string)
33 |
34 |
35 | fromString : String -> CountryCode
36 | fromString string =
37 | case String.toLower string of
38 | "de" ->
39 | DE
40 |
41 | "jp" ->
42 | JP
43 |
44 | _ ->
45 | Others string
46 |
47 |
48 | toString : CountryCode -> String
49 | toString countryCode =
50 | case countryCode of
51 | JP ->
52 | "jp"
53 |
54 | DE ->
55 | "de"
56 |
57 | Others string ->
58 | String.toLower string
59 |
60 |
61 | isJapan : CountryCode -> Bool
62 | isJapan countryCode =
63 | case countryCode of
64 | JP ->
65 | True
66 |
67 | _ ->
68 | False
69 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/ValidationCode.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.ValidationCode exposing (fromValidationCodeToMessageWithReplacedValues)
2 |
3 | import R10.Form.Internal.FieldConf
4 | import Regex
5 |
6 |
7 | fromValidationCodeToMessageWithReplacedValues :
8 | R10.Form.Internal.FieldConf.ValidationCode
9 | -> R10.Form.Internal.FieldConf.ValidationPayload
10 | -> (R10.Form.Internal.FieldConf.ValidationCode -> String)
11 | -> String
12 | fromValidationCodeToMessageWithReplacedValues validationCode bracketsArgs translator_ =
13 | let
14 | translated : String
15 | translated =
16 | translator_ validationCode
17 | in
18 | if List.isEmpty bracketsArgs then
19 | translated
20 |
21 | else
22 | replaceBrackets bracketsArgs translated
23 |
24 |
25 | replacer : ( Int, String ) -> String -> String
26 | replacer ( index, value ) acc =
27 | Regex.replace (regexBracket index) (\_ -> value) acc
28 |
29 |
30 | replaceBrackets : List String -> String -> String
31 | replaceBrackets values target =
32 | values
33 | |> List.indexedMap Tuple.pair
34 | |> List.foldl replacer target
35 |
36 |
37 | regexBracket : Int -> Regex.Regex
38 | regexBracket index =
39 | -- Removing all pairs of square brackets that just contain comments
40 | Regex.fromStringWith { caseInsensitive = True, multiline = True } ("\\{" ++ String.fromInt index ++ "\\}")
41 | |> Maybe.withDefault Regex.never
42 |
--------------------------------------------------------------------------------
/examples/simpleForm/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": [
4 | "src",
5 | "../../src"
6 | ],
7 | "elm-version": "0.19.1",
8 | "dependencies": {
9 | "direct": {
10 | "NoRedInk/elm-json-decode-pipeline": "1.0.0",
11 | "avh4/elm-color": "1.0.0",
12 | "elm/browser": "1.0.2",
13 | "elm/core": "1.0.5",
14 | "elm/html": "1.0.0",
15 | "elm/json": "1.1.3",
16 | "elm/parser": "1.1.0",
17 | "elm/regex": "1.0.0",
18 | "elm/svg": "1.0.1",
19 | "elm/time": "1.0.0",
20 | "elm/url": "1.0.0",
21 | "elm-community/json-extra": "4.3.0",
22 | "elm-community/list-extra": "8.5.2",
23 | "elm-community/string-extra": "4.0.1",
24 | "lucamug/elm-ui-with-context": "1.0.0",
25 | "mdgriffith/elm-ui": "1.1.8",
26 | "noahzgordon/elm-color-extra": "1.0.2",
27 | "rtfeldman/elm-iso8601-date-strings": "1.1.4",
28 | "tasuki/elm-punycode": "1.1.0",
29 | "zwilias/json-decode-exploration": "6.0.0"
30 | },
31 | "indirect": {
32 | "elm/random": "1.0.0",
33 | "elm/virtual-dom": "1.0.2",
34 | "fredcy/elm-parseint": "2.0.1",
35 | "mgold/elm-nonempty-list": "4.1.0"
36 | }
37 | },
38 | "test-dependencies": {
39 | "direct": {},
40 | "indirect": {}
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/creditCardForm/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": [
4 | "src",
5 | "../../src"
6 | ],
7 | "elm-version": "0.19.1",
8 | "dependencies": {
9 | "direct": {
10 | "NoRedInk/elm-json-decode-pipeline": "1.0.0",
11 | "avh4/elm-color": "1.0.0",
12 | "elm/browser": "1.0.2",
13 | "elm/core": "1.0.5",
14 | "elm/html": "1.0.0",
15 | "elm/json": "1.1.3",
16 | "elm/parser": "1.1.0",
17 | "elm/regex": "1.0.0",
18 | "elm/svg": "1.0.1",
19 | "elm/time": "1.0.0",
20 | "elm/url": "1.0.0",
21 | "elm-community/json-extra": "4.3.0",
22 | "elm-community/list-extra": "8.5.2",
23 | "elm-community/string-extra": "4.0.1",
24 | "lucamug/elm-ui-with-context": "1.0.0",
25 | "mdgriffith/elm-ui": "1.1.8",
26 | "noahzgordon/elm-color-extra": "1.0.2",
27 | "rtfeldman/elm-iso8601-date-strings": "1.1.4",
28 | "tasuki/elm-punycode": "1.1.0",
29 | "zwilias/json-decode-exploration": "6.0.0"
30 | },
31 | "indirect": {
32 | "elm/random": "1.0.0",
33 | "elm/virtual-dom": "1.0.2",
34 | "fredcy/elm-parseint": "2.0.1",
35 | "mgold/elm-nonempty-list": "4.1.0"
36 | }
37 | },
38 | "test-dependencies": {
39 | "direct": {},
40 | "indirect": {}
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Html/String/Keyed.elm:
--------------------------------------------------------------------------------
1 | module Html.String.Keyed exposing
2 | ( node
3 | , ol, ul
4 | )
5 |
6 | {-| A keyed node helps optimize cases where children are getting added, moved,
7 | removed, etc. Common examples include:
8 |
9 | - The user can delete items from a list.
10 | - The user can create new items in a list.
11 | - You can sort a list based on name or date or whatever.
12 |
13 | When you use a keyed node, every child is paired with a string identifier. This
14 | makes it possible for the underlying diffing algorithm to reuse nodes more
15 | efficiently.
16 |
17 |
18 | # Keyed Nodes
19 |
20 | @docs node
21 |
22 |
23 | # Commonly Keyed Nodes
24 |
25 | @docs ol, ul
26 |
27 | -}
28 |
29 | import Html.String exposing (Attribute, Html)
30 | import Html.Types
31 |
32 |
33 | {-| Works just like `Html.node`, but you add a unique identifier to each child
34 | node. You want this when you have a list of nodes that is changing: adding
35 | nodes, removing nodes, etc. In these cases, the unique identifiers help make
36 | the DOM modifications more efficient.
37 | -}
38 | node : String -> List (Attribute msg) -> List ( String, Html msg ) -> Html msg
39 | node tag attrs children =
40 | Html.Types.Node tag attrs (Html.Types.Keyed children)
41 |
42 |
43 | {-| -}
44 | ol : List (Attribute msg) -> List ( String, Html msg ) -> Html msg
45 | ol =
46 | node "ol"
47 |
48 |
49 | {-| -}
50 | ul : List (Attribute msg) -> List ( String, Html msg ) -> Html msg
51 | ul =
52 | node "ul"
53 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/ConfMeta.elm:
--------------------------------------------------------------------------------
1 | module Starter.ConfMeta exposing
2 | ( ConfMeta
3 | , confMeta
4 | )
5 |
6 | import Starter.Version
7 |
8 |
9 | type alias ConfMeta =
10 | -- ports
11 | { portBuild : Int
12 | , portStatic : Int
13 | , portDev : Int
14 |
15 | --
16 | , versionElmStarter : String
17 |
18 | --
19 | , indentation : Int
20 |
21 | -- notifications
22 | , messageDoNotEditDisclaimer : String
23 | , messageEnableJavascriptForBetterExperience : String
24 | , messageLoading : String
25 | , messageYouNeedToEnableJavascript : String
26 |
27 | -- tags
28 | , tagLoader : String
29 | , tagNotification : String
30 | }
31 |
32 |
33 | confMeta : ConfMeta
34 | confMeta =
35 | -- ports
36 | { portStatic = 7000
37 | , portDev = 8000
38 | , portBuild = 9000
39 |
40 | --
41 | , versionElmStarter = Starter.Version.version
42 |
43 | --
44 | , indentation = 0
45 |
46 | -- messages
47 | , messageYouNeedToEnableJavascript = "You need to enable JavaScript to run this app."
48 | , messageEnableJavascriptForBetterExperience = "Enable Javascript for a better experience."
49 | , messageLoading = "L O A D I N G . . ."
50 | , messageDoNotEditDisclaimer = "Generated file ** DO NOT EDIT DIRECTLY ** Edit Elm files instead"
51 |
52 | -- tags
53 | , tagLoader = prefix ++ "notification"
54 | , tagNotification = prefix ++ "loader"
55 | }
56 |
57 |
58 | prefix : String
59 | prefix =
60 | "elm-starter-"
61 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/State.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.State exposing
2 | ( FiltersState(..)
3 | , FiltersStateRecord
4 | , PaginationButtonState(..)
5 | , PaginationState(..)
6 | , PaginationStateRecord
7 | , State
8 | )
9 |
10 | import Dict
11 | import R10.Form
12 |
13 |
14 | type PaginationButtonState
15 | = PaginationButtonDisabled
16 | | PaginationButtonOtherLoading
17 | | PaginationButtonLoading
18 | | PaginationButtonEnabled
19 |
20 |
21 | type alias PaginationStateRecord =
22 | -- TODO there is too many combinations of nextButtonState + prevButtonState
23 | { length : Int
24 | , nextButtonState : PaginationButtonState
25 | , prevButtonState : PaginationButtonState
26 |
27 | -- todo replace button states with Edge+Loading states? Same number of combinations but likely clearer idea
28 | }
29 |
30 |
31 | type PaginationState
32 | = Pagination PaginationStateRecord
33 | | NoPagination
34 |
35 |
36 | type alias SortState =
37 | { name : String
38 | , isReversed : Bool
39 | }
40 |
41 |
42 | type alias FiltersStateRecord =
43 | { filterEditor : Maybe ( String, R10.Form.Form ) -- ( open on filter with key, popup inner form model)
44 | , filterValues : Dict.Dict String String
45 | }
46 |
47 |
48 | type FiltersState
49 | = Filters FiltersStateRecord
50 | | NoFilters
51 |
52 |
53 | type alias State =
54 | { sort : SortState
55 | , pagination : PaginationState
56 | , filters : FiltersState
57 | , loading : Bool
58 | }
59 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/Types.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.Types exposing (Filter(..), Sorter(..), Status(..))
2 |
3 | {-| Specifies a particular way of sorting data.
4 | -}
5 |
6 |
7 | type Sorter data
8 | = None
9 | | Increasing (List data -> List data)
10 | | Decreasing (List data -> List data)
11 | | IncOrDec (List data -> List data)
12 | | DecOrInc (List data -> List data)
13 |
14 |
15 | {-| The status of a particular column, for use in the `thead` field of your
16 | `Customizations`.
17 |
18 | - If the column is unsortable, the status will always be `Unsortable`.
19 | - If the column can be sorted in one direction, the status will be `Sortable`.
20 | The associated boolean represents whether this column is selected. So it is
21 | `True` if the table is currently sorted by this column, and `False` otherwise.
22 | - If the column can be sorted in either direction, the status will be `Reversible`.
23 | The associated maybe tells you whether this column is selected. It is
24 | `Just isReversed` if the table is currently sorted by this column, and
25 | `Nothing` otherwise. The `isReversed` boolean lets you know which way it
26 | is sorted.
27 |
28 | This information lets you do custom header decorations for each scenario.
29 |
30 | -}
31 | type Status
32 | = Unsortable
33 | | Sortable Bool
34 | | Reversible (Maybe Bool)
35 |
36 |
37 | type Filter
38 | = FilterText { label : String, key : String }
39 | | FilterSelect { label : String, key : String, options : List { value : String, label : String } }
40 |
--------------------------------------------------------------------------------
/examples/pwa/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": [
4 | "src",
5 | "src-elm-starter",
6 | "../../src"
7 | ],
8 | "elm-version": "0.19.1",
9 | "dependencies": {
10 | "direct": {
11 | "NoRedInk/elm-json-decode-pipeline": "1.0.0",
12 | "avh4/elm-color": "1.0.0",
13 | "elm/browser": "1.0.2",
14 | "elm/core": "1.0.5",
15 | "elm/html": "1.0.0",
16 | "elm/http": "2.0.0",
17 | "elm/json": "1.1.3",
18 | "elm/regex": "1.0.0",
19 | "elm/svg": "1.0.1",
20 | "elm/time": "1.0.0",
21 | "elm/url": "1.0.0",
22 | "elm-community/json-extra": "4.3.0",
23 | "elm-community/list-extra": "8.2.4",
24 | "elm-community/string-extra": "4.0.1",
25 | "elm-explorations/markdown": "1.0.0",
26 | "mdgriffith/elm-ui": "1.1.8",
27 | "noahzgordon/elm-color-extra": "1.0.2",
28 | "zwilias/json-decode-exploration": "6.0.0"
29 | },
30 | "indirect": {
31 | "elm/bytes": "1.0.8",
32 | "elm/file": "1.0.5",
33 | "elm/parser": "1.1.0",
34 | "elm/random": "1.0.0",
35 | "elm/virtual-dom": "1.0.2",
36 | "fredcy/elm-parseint": "2.0.1",
37 | "mgold/elm-nonempty-list": "4.1.0",
38 | "rtfeldman/elm-iso8601-date-strings": "1.1.3"
39 | }
40 | },
41 | "test-dependencies": {
42 | "direct": {},
43 | "indirect": {}
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/Manifest.elm:
--------------------------------------------------------------------------------
1 | module Starter.Manifest exposing
2 | ( Manifest
3 | , manifest
4 | )
5 |
6 | import Json.Encode
7 | import Starter.Icon
8 |
9 |
10 | manifestIcon : String -> Int -> Json.Encode.Value
11 | manifestIcon relative size =
12 | let
13 | sizeString =
14 | String.fromInt size
15 | in
16 | Json.Encode.object
17 | [ ( "src", Json.Encode.string (Starter.Icon.iconFileName relative size) )
18 | , ( "sizes", Json.Encode.string (sizeString ++ "x" ++ sizeString) )
19 | , ( "type", Json.Encode.string "image/png" )
20 | , ( "purpose", Json.Encode.string "any maskable" )
21 | ]
22 |
23 |
24 | type alias Manifest =
25 | { iconSizes : List Int
26 | , themeColor : String
27 | , name : String
28 | , nameLong : String
29 | }
30 |
31 |
32 | manifest : String -> Manifest -> Json.Encode.Value
33 | manifest relative args =
34 | -- https://developer.mozilla.org/en-US/docs/Web/Manifest
35 | Json.Encode.object
36 | [ ( "short_name", Json.Encode.string args.name )
37 | , ( "name", Json.Encode.string args.nameLong )
38 | , ( "start_url", Json.Encode.string (relative ++ "/") )
39 | , ( "display", Json.Encode.string "standalone" )
40 | , ( "background_color", Json.Encode.string args.themeColor )
41 | , ( "theme_color", Json.Encode.string args.themeColor )
42 | , ( "icons", Json.Encode.list (manifestIcon relative) args.iconSizes )
43 |
44 | -- TODO - add https://developer.mozilla.org/en-US/docs/Web/Manifest/screenshots
45 | ]
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020-present, Rakuten Inc.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above
11 | copyright notice, this list of conditions and the following
12 | disclaimer in the documentation and/or other materials provided
13 | with the distribution.
14 |
15 | * Neither the name of Rakuten Inc., nor the names of other
16 | contributors may be used to endorse or promote products derived
17 | from this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/Utils/FocusOut.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.Utils.FocusOut exposing (onFocusOut)
2 |
3 | import Json.Decode as D
4 |
5 |
6 | outsideTarget : String -> String -> msg -> D.Decoder msg
7 | outsideTarget targetName dropdownId closeMsg =
8 | D.field targetName (isOutsideDropdown dropdownId)
9 | |> D.andThen
10 | (\isOutside ->
11 | if isOutside then
12 | D.succeed closeMsg
13 |
14 | else
15 | D.fail "inside dropdown"
16 | )
17 |
18 |
19 | isOutsideDropdown : String -> D.Decoder Bool
20 | isOutsideDropdown dropdownId =
21 | D.oneOf
22 | [ D.field "id" D.string
23 | |> D.andThen
24 | (\id ->
25 | if dropdownId == id then
26 | -- found match by id
27 | D.succeed False
28 |
29 | else
30 | -- try next decoder
31 | D.fail "check parent node"
32 | )
33 | , D.lazy
34 | (\_ ->
35 | isOutsideDropdown dropdownId |> D.field "parentNode"
36 | )
37 |
38 | -- fallback if all previous decoders failed
39 | , D.succeed True
40 | ]
41 |
42 |
43 | onFocusOut : String -> msg -> D.Decoder msg
44 | onFocusOut containerId closeMsg =
45 | -- Every target that should be allowed (element contained in `containerId`),
46 | -- should be focusable. Otherwise relatedTarget would be null and it would be
47 | -- impossible to check if relatedTarget is a child of a target
48 | outsideTarget "relatedTarget" containerId closeMsg
49 |
--------------------------------------------------------------------------------
/src/R10/Mode.elm:
--------------------------------------------------------------------------------
1 | module R10.Mode exposing (Mode(..), decodeJsonString, decoderExploration, default, fromString, isLight, toString, toggle)
2 |
3 | {-| Use `Mode` to determine if the application should be rendered with a `Light` or a `Dark` palette of colors.
4 |
5 | @docs Mode, decodeJsonString, decoderExploration, default, fromString, isLight, toString, toggle
6 |
7 | -}
8 |
9 | import Json.Decode
10 | import Json.Decode.Exploration
11 |
12 |
13 | {-| -}
14 | type Mode
15 | = Dark
16 | | Light
17 |
18 |
19 | {-| -}
20 | default : Mode
21 | default =
22 | Light
23 |
24 |
25 | {-| -}
26 | isLight : Mode -> Bool
27 | isLight mode =
28 | mode == Light
29 |
30 |
31 | {-| -}
32 | toggle : Mode -> Mode
33 | toggle mode =
34 | case mode of
35 | Dark ->
36 | Light
37 |
38 | Light ->
39 | Dark
40 |
41 |
42 | {-| -}
43 | fromString : String -> Mode
44 | fromString string =
45 | case String.toLower string of
46 | "dark" ->
47 | Dark
48 |
49 | _ ->
50 | default
51 |
52 |
53 | {-| -}
54 | toString : Mode -> String
55 | toString theme =
56 | case theme of
57 | Dark ->
58 | "Dark"
59 |
60 | Light ->
61 | "Light"
62 |
63 |
64 | {-| -}
65 | decoderExploration : Json.Decode.Exploration.Decoder Mode
66 | decoderExploration =
67 | Json.Decode.Exploration.string |> Json.Decode.Exploration.andThen (fromString >> Json.Decode.Exploration.succeed)
68 |
69 |
70 | decoder : Json.Decode.Decoder Mode
71 | decoder =
72 | Json.Decode.string |> Json.Decode.andThen (fromString >> Json.Decode.succeed)
73 |
74 |
75 | {-| -}
76 | decodeJsonString : Json.Decode.Value -> Result Json.Decode.Error Mode
77 | decodeJsonString value =
78 | Json.Decode.decodeValue decoder value
79 |
--------------------------------------------------------------------------------
/examples/pwa/review/src/ReviewConfig.elm:
--------------------------------------------------------------------------------
1 | module ReviewConfig exposing (config)
2 |
3 | {-| Do not rename the ReviewConfig module or the config function, because
4 | `elm-review` will look for these.
5 |
6 | To add packages that contain rules, add them to this review project using
7 |
8 | `elm install author/packagename`
9 |
10 | when inside the directory containing this file.
11 |
12 | -}
13 |
14 | import NoEmptyText
15 | import NoExposingEverything
16 | import NoImportingEverything
17 | import NoMissingTypeAnnotation
18 | import NoMissingTypeAnnotationInLetIn
19 | import NoMissingTypeExpose
20 | import NoUnused.CustomTypeConstructorArgs
21 | import NoUnused.CustomTypeConstructors
22 | import NoUnused.Dependencies
23 | import NoUnused.Exports
24 | import NoUnused.Modules
25 | import NoUnused.Parameters
26 | import NoUnused.Patterns
27 | import NoUnused.Variables
28 | import Review.Rule exposing (Rule)
29 |
30 |
31 | config : List Rule
32 | config =
33 | [ NoEmptyText.rule
34 | , NoExposingEverything.rule
35 | , NoImportingEverything.rule [ "Element", "Test" ]
36 | , NoMissingTypeAnnotation.rule
37 | , NoMissingTypeAnnotationInLetIn.rule
38 | , NoMissingTypeExpose.rule
39 | , NoUnused.CustomTypeConstructors.rule []
40 | , NoUnused.CustomTypeConstructorArgs.rule
41 | , NoUnused.Dependencies.rule
42 | , NoUnused.Exports.rule
43 | , NoUnused.Modules.rule
44 | , NoUnused.Parameters.rule
45 | , NoUnused.Patterns.rule
46 | , NoUnused.Variables.rule
47 | ]
48 | |> List.map
49 | (\rule ->
50 | rule
51 | |> Review.Rule.ignoreErrorsForDirectories
52 | [ "src-elm-starter"
53 | , "../../src"
54 | ]
55 | |> Review.Rule.ignoreErrorsForFiles
56 | []
57 | )
58 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/Key.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.Key exposing
2 | ( Key
3 | , KeyAsString
4 | , composeKey
5 | , composeMultiKeys
6 | , empty
7 | , fromList
8 | , fromString
9 | , headId
10 | , replaceLeaf
11 | , separator
12 | , toQuantity
13 | , toString
14 | )
15 |
16 |
17 | type Key
18 | = Key (List String)
19 |
20 |
21 | type alias KeyAsString =
22 | String
23 |
24 |
25 | fromList : List String -> Key
26 | fromList list =
27 | Key (list |> List.filter (not << String.isEmpty))
28 |
29 |
30 | empty : Key
31 | empty =
32 | fromList []
33 |
34 |
35 | composeKey : Key -> String -> Key
36 | composeKey (Key keys) extraKey =
37 | if String.isEmpty extraKey then
38 | Key keys
39 |
40 | else
41 | Key (extraKey :: keys)
42 |
43 |
44 | composeMultiKeys : Key -> Int -> List Key
45 | composeMultiKeys key quantity =
46 | List.indexedMap
47 | (\index _ ->
48 | composeKey key (String.fromInt index)
49 | )
50 | (List.repeat quantity ())
51 |
52 |
53 | headId : Key -> String
54 | headId (Key list) =
55 | list
56 | |> List.head
57 | |> Maybe.withDefault "CANNOT_FIND_THE_HEAD_ID_IN_AN_EMPTY_KEY"
58 |
59 |
60 | separator : String
61 | separator =
62 | "/"
63 |
64 |
65 | toString : Key -> KeyAsString
66 | toString (Key keys) =
67 | String.join separator (List.reverse keys)
68 |
69 |
70 | fromString : KeyAsString -> Key
71 | fromString keyAsString =
72 | Key <| List.reverse <| String.split separator keyAsString
73 |
74 |
75 | toQuantity : Key -> Int
76 | toQuantity (Key keys) =
77 | List.length keys
78 |
79 |
80 | replaceLeaf : String -> Key -> Key
81 | replaceLeaf newLeaf (Key keyList) =
82 | if List.isEmpty keyList then
83 | fromList keyList
84 |
85 | else
86 | newLeaf :: List.drop 1 keyList |> fromList
87 |
--------------------------------------------------------------------------------
/examples/pwa/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.1",
3 | "name": "R10",
4 | "nameLong": "R10",
5 | "description": "Rakuten Elm front-end bootstrapper and components Library",
6 | "author": "Rakuten",
7 | "homepage": "https://r10.netlify.app/",
8 | "license": "© Rakuten, Inc. 2020 - present",
9 | "snapshotWidth": 700,
10 | "snapshotHeight": 350,
11 | "themeColor": {
12 | "red": 17,
13 | "green": 123,
14 | "blue": 180
15 | },
16 | "devDependencies": {
17 | "chokidar-cli": "^2.1.0",
18 | "cloc": "^2.6.0",
19 | "concurrently": "^5.3.0",
20 | "elm": "^0.19.1-3",
21 | "elm-analyse": "^0.16.5",
22 | "elm-go": "^5.0.8",
23 | "html-minifier": "^4.0.0",
24 | "puppeteer": "^5.2.1",
25 | "terser": "^4.8.0"
26 | },
27 | "scripts": {
28 | "start": "node ./src-elm-starter/elm-starter start",
29 | "build": "node ./src-elm-starter/elm-starter build",
30 | "serverBuild": "node ./src-elm-starter/elm-starter serverBuild",
31 | "publishRpaas": "cf push -f rpaas-manifest.yml -p ./elm-stuff/elm-starter-files/build/",
32 | "elm-starter:boot": "node ./src-elm-starter/elm-starter boot",
33 | "elm-starter:generateDevFiles": "node ./src-elm-starter/elm-starter generateDevFiles",
34 | "elm-starter:buildExpectingTheServerRunning": "node ./src-elm-starter/elm-starter buildExpectingTheServerRunning",
35 | "elm-starter:serverDev": "node ./src-elm-starter/elm-starter serverDev",
36 | "elm-starter:serverStatic": "node ./src-elm-starter/elm-starter serverStatic",
37 | "elm-starter:watchStartElm": "node ./src-elm-starter/elm-starter watchStartElm",
38 | "elm-starter:debug": "node ./src-elm-starter/elm-starter debug",
39 | "elm-starter:help": "node ./src-elm-starter/elm-starter --help",
40 | "elm-starter:version": "node ./src-elm-starter/elm-starter --version"
41 | },
42 | "repository": {
43 | "type": "git",
44 | "url": "https://github.com/rakutentech/r10"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/R10/Transition.elm:
--------------------------------------------------------------------------------
1 | module R10.Transition exposing
2 | ( parseCharacteristics
3 | , transition
4 | )
5 |
6 | import Element.WithContext exposing (..)
7 | import Html.Attributes
8 | import R10.Context
9 | import String.Extra
10 |
11 |
12 |
13 | -- Examples
14 | --
15 | -- "color .2s ease-out, background-color .2s ease-out"
16 | -- "background-color 0.8s"
17 | -- "all 0.15s ease-out"
18 | -- "all 0.2s "
19 | -- "all 0.13s"
20 | -- "all 0.15s ease-in, opacity 0.15s 0.2s ease-in"
21 | -- "opacity 0.2s, visibility 0.2s"
22 | -- "color .2s ease-out, background-color .2s ease-out"
23 | -- "font-size 300ms 0ms ease-in, opacity 300ms 300ms ease-in"
24 | -- "0.2s"
25 | --
26 | --
27 |
28 |
29 | transition : String -> Attribute (R10.Context.ContextInternal z) msg
30 | transition characteristics =
31 | withContextAttribute <| \c -> htmlAttribute <| Html.Attributes.style "transition" (parseCharacteristics c.contextR10.debugger_transitionSpeed characteristics)
32 |
33 |
34 | parseCharacteristics : Float -> String -> String
35 | parseCharacteristics ratio characteristics =
36 | characteristics
37 | |> String.Extra.clean
38 | |> String.split ","
39 | |> List.map (parseUnit ratio)
40 | |> String.join ","
41 |
42 |
43 | parseUnit : Float -> String -> String
44 | parseUnit ratio unit =
45 | unit
46 | |> String.split " "
47 | |> List.map (parseSubUnit ratio)
48 | |> String.join " "
49 |
50 |
51 | parseSubUnit : Float -> String -> String
52 | parseSubUnit ratio subUnit =
53 | if String.endsWith "ms" subUnit then
54 | case String.toFloat ("0" ++ String.dropRight 2 subUnit) of
55 | Just value ->
56 | String.fromFloat (value * ratio) ++ "ms"
57 |
58 | Nothing ->
59 | subUnit
60 |
61 | else if String.endsWith "s" subUnit then
62 | case String.toFloat ("0" ++ String.dropRight 1 subUnit) of
63 | Just value ->
64 | String.fromFloat (value * ratio) ++ "s"
65 |
66 | Nothing ->
67 | subUnit
68 |
69 | else
70 | subUnit
71 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/Style.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.Style exposing
2 | ( defaultCellAttrs
3 | , defaultHeaderAttrs
4 | , defaultRowAttrs
5 | )
6 |
7 | import Element.WithContext exposing (..)
8 | import Element.WithContext.Border as Border
9 | import Element.WithContext.Font as Font
10 | import Html.Attributes
11 | import R10.Context exposing (..)
12 | import R10.Transition
13 |
14 |
15 |
16 | -- Application specific
17 |
18 |
19 | borderColor : Color
20 | borderColor =
21 | Element.WithContext.rgba 0 0 0 0.2
22 |
23 |
24 |
25 | {-
26 | Following styles are from
27 | https://material.io/components/data-tables/#specs
28 | -}
29 | -- Table cell padding
30 | -- Corner radius
31 | -- Container outline
32 | -- Height and padding
33 |
34 |
35 | headerRowHeight : number
36 | headerRowHeight =
37 | 56
38 |
39 |
40 | columnPadding : number
41 | columnPadding =
42 | 16
43 |
44 |
45 | defaultHeaderAttrs : List (Attribute (R10.Context.ContextInternal z) msg)
46 | defaultHeaderAttrs =
47 | [ paddingXY columnPadding 0
48 | , spacing columnPadding
49 | , width (fill |> minimum 120) -- minimum 120: weird behaviour on shrink otherwise
50 | , height <| px headerRowHeight
51 | , htmlAttribute <| Html.Attributes.style "word-break" "break-all"
52 | , htmlAttribute (Html.Attributes.style "user-select" "none")
53 | , Font.extraBold
54 | , Border.color borderColor
55 | , Border.widthEach { bottom = 1, top = 0, left = 0, right = 0 }
56 | ]
57 |
58 |
59 | defaultRowAttrs : List (Attribute (R10.Context.ContextInternal z) msg)
60 | defaultRowAttrs =
61 | [ width fill
62 | , height fill
63 | , Border.color borderColor
64 | , Border.widthEach { bottom = 1, top = 0, left = 0, right = 0 }
65 | ]
66 |
67 |
68 | defaultCellAttrs : List (Attribute (R10.Context.ContextInternal z) msg)
69 | defaultCellAttrs =
70 | [ width (fill |> minimum 120)
71 | , R10.Transition.transition "all 0.25s ease-out"
72 | , height (fill |> minimum 54)
73 | , paddingXY 16 6
74 | , htmlAttribute <| Html.Attributes.style "word-break" "break-word"
75 | ]
76 |
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/TextColors.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.TextColors exposing
2 | ( getBorderColor
3 | , getLabelColor
4 | )
5 |
6 | import Element.WithContext exposing (..)
7 | import R10.FormComponents.Internal.UI.Color
8 | import R10.Palette
9 |
10 |
11 | getBorderColor :
12 | { a
13 | | focused : Bool
14 | , disabled : Bool
15 | , maybeValid : Maybe Bool
16 | , displayValidation : Bool
17 | , isMouseOver : Bool
18 | , palette : R10.Palette.Palette
19 | }
20 | -> Color
21 | getBorderColor { disabled, focused, maybeValid, displayValidation, isMouseOver, palette } =
22 | let
23 | validationActive : Bool
24 | validationActive =
25 | displayValidation && maybeValid == Just False
26 |
27 | alpha : Float
28 | alpha =
29 | if not disabled && (focused || isMouseOver || validationActive) then
30 | 1
31 |
32 | else
33 | 0.7
34 | in
35 | case ( displayValidation, maybeValid, focused ) of
36 | ( True, Just True, _ ) ->
37 | -- VALID
38 | R10.FormComponents.Internal.UI.Color.successA alpha palette
39 |
40 | ( True, Just False, _ ) ->
41 | -- NOT VALID
42 | R10.FormComponents.Internal.UI.Color.errorA alpha palette
43 |
44 | ( _, _, _ ) ->
45 | -- NORMAL
46 | R10.FormComponents.Internal.UI.Color.borderA alpha palette
47 |
48 |
49 | getLabelColor :
50 | { a
51 | | maybeValid : Maybe Bool
52 | , displayValidation : Bool
53 | , palette : R10.Palette.Palette
54 | }
55 | -> Color
56 | getLabelColor { maybeValid, displayValidation, palette } =
57 | case ( displayValidation, maybeValid ) of
58 | ( True, Just True ) ->
59 | -- VALID
60 | R10.FormComponents.Internal.UI.Color.success palette
61 |
62 | ( True, Just False ) ->
63 | -- NOT VALID
64 | R10.FormComponents.Internal.UI.Color.error palette
65 |
66 | ( _, _ ) ->
67 | -- NORMAL
68 | R10.FormComponents.Internal.UI.Color.label palette
69 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Html/String/Extra.elm:
--------------------------------------------------------------------------------
1 | module Html.String.Extra exposing
2 | ( body
3 | , charset
4 | , content
5 | , crossorigin
6 | , doctype
7 | , head
8 | , html
9 | , httpEquiv
10 | , link
11 | , meta
12 | , noscript
13 | , property_
14 | , script
15 | , style_
16 | , title_
17 | )
18 |
19 | import Html.String exposing (..)
20 | import Html.String.Attributes exposing (..)
21 |
22 |
23 |
24 | -- HTML EXTENSIONS
25 | --
26 | -- Adding nodes and attributes useful to generate an entire HTML page
27 |
28 |
29 | doctype : String
30 | doctype =
31 | ""
32 |
33 |
34 | html : List (Attribute msg) -> List (Html msg) -> Html msg
35 | html =
36 | node "html"
37 |
38 |
39 | head : List (Attribute msg) -> List (Html msg) -> Html msg
40 | head =
41 | node "head"
42 |
43 |
44 | body : List (Attribute msg) -> List (Html msg) -> Html msg
45 | body =
46 | node "body"
47 |
48 |
49 | script : List (Attribute msg) -> List (Html msg) -> Html msg
50 | script =
51 | node "script"
52 |
53 |
54 | noscript : List (Attribute msg) -> List (Html msg) -> Html msg
55 | noscript =
56 | node "noscript"
57 |
58 |
59 | meta : List (Attribute msg) -> List (Html msg) -> Html msg
60 | meta =
61 | node "meta"
62 |
63 |
64 | link : List (Attribute msg) -> List (Html msg) -> Html msg
65 | link =
66 | node "link"
67 |
68 |
69 | style_ : List (Attribute msg) -> List (Html msg) -> Html msg
70 | style_ =
71 | node "style"
72 |
73 |
74 | title_ : List (Attribute msg) -> List (Html msg) -> Html msg
75 | title_ =
76 | node "title"
77 |
78 |
79 | charset : String -> Attribute msg
80 | charset =
81 | attribute "charset"
82 |
83 |
84 | crossorigin : String -> Attribute msg
85 | crossorigin =
86 | attribute "crossorigin"
87 |
88 |
89 | property_ : String -> Attribute msg
90 | property_ =
91 | attribute "property"
92 |
93 |
94 | content : String -> Attribute msg
95 | content =
96 | attribute "content"
97 |
98 |
99 | httpEquiv : String -> Attribute msg
100 | httpEquiv =
101 | attribute "http-equiv"
102 |
--------------------------------------------------------------------------------
/src/R10/Card.elm:
--------------------------------------------------------------------------------
1 | module R10.Card exposing (high, low, normal, noShadow)
2 |
3 | {-| Cards are area of the page surranded by a rounded border.
4 |
5 | @docs high, low, normal, noShadow
6 |
7 | -}
8 |
9 | import Element.WithContext exposing (..)
10 | import Element.WithContext.Border as Border
11 | import R10.Color.AttrsBackground
12 | import R10.Color.AttrsBorder
13 | import R10.Color.AttrsFont
14 | import R10.Context exposing (..)
15 | import R10.Mode
16 | import R10.Transition
17 |
18 |
19 | shadow : Float -> Attr (R10.Context.ContextInternal z) decorative msg
20 | shadow level =
21 | Border.shadow
22 | { offset = ( 0, level )
23 | , blur = level + 2
24 | , size = level - 2
25 | , color = rgba255 0 0 0 0.07
26 | }
27 |
28 |
29 | base : List (Attribute (R10.Context.ContextInternal context) msg)
30 | base =
31 | [ R10.Color.AttrsBackground.surface
32 | , R10.Color.AttrsBorder.normal
33 | , R10.Color.AttrsFont.normal
34 | , Border.rounded 10
35 | , Border.width 1
36 | , withContextAttribute <|
37 | \c ->
38 | Border.color <|
39 | case c.contextR10.theme.mode of
40 | R10.Mode.Light ->
41 | rgba 0 0 0 0.1
42 |
43 | R10.Mode.Dark ->
44 | rgba 1 1 1 0.08
45 | , padding 30
46 | , width fill
47 | , height fill
48 | , R10.Transition.transition "background-color 0.8s"
49 | ]
50 |
51 |
52 | {-| Card with an high shadow
53 | -}
54 | high : List (Attribute (R10.Context.ContextInternal context) msg)
55 | high =
56 | -- https://material.io/design/environment/elevation.html#elevation-in-material-design
57 | base ++ [ shadow 8 ]
58 |
59 |
60 | {-| Card with a normal shadow
61 | -}
62 | normal : List (Attribute (R10.Context.ContextInternal context) msg)
63 | normal =
64 | -- base ++ [ shadow 2, mouseOver [ shadow 8 ] ]
65 | base ++ [ shadow 4 ]
66 |
67 |
68 | {-| Card with a low shadow
69 | -}
70 | low : List (Attribute (R10.Context.ContextInternal context) msg)
71 | low =
72 | base ++ [ shadow 2 ]
73 |
74 |
75 | {-| Card without a shadow
76 | -}
77 | noShadow : List (Attribute (R10.Context.ContextInternal context) msg)
78 | noShadow =
79 | base
80 |
--------------------------------------------------------------------------------
/src/R10/Footer.elm:
--------------------------------------------------------------------------------
1 | module R10.Footer exposing (view)
2 |
3 | {-| Generic footer.
4 |
5 | Be aware that this component depends on the `Header` component for historical and logical reasons.
6 |
7 | @docs view
8 |
9 | -}
10 |
11 | import Element.WithContext exposing (..)
12 | import R10.Context exposing (..)
13 | import Element.WithContext.Background as Background
14 | import Element.WithContext.Font as Font
15 | import R10.FontSize
16 | import R10.Header
17 |
18 |
19 | {-| -}
20 | view : R10.Header.Header -> R10.Header.ViewArgs z msg route -> Element (R10.Context.ContextInternal z) msg
21 | view model args =
22 | column
23 | [ width fill
24 | , Background.color <| rgb 0.3 0.3 0.3
25 | , Font.color <| rgb 0.8 0.8 0.8
26 | , paddingXY 0 60
27 | , R10.FontSize.normal
28 | , spacing 50
29 | ]
30 | <|
31 | [ el
32 | [ moveRight 14
33 | , width (fill |> maximum model.maxWidth)
34 | , centerX
35 | ]
36 | <|
37 | args.logoOnDark
38 | , row
39 | [ width (fill |> maximum model.maxWidth)
40 | , centerX
41 | ]
42 | [ column [ width fill, alignTop ]
43 | args.extraContent
44 | , column [ width fill, alignTop ] <|
45 | []
46 | ++ R10.Header.languageMenu model args
47 | ++ R10.Header.menuSeparator
48 | ++ [ case model.session of
49 | R10.Header.SessionNotRequired ->
50 | none
51 |
52 | R10.Header.SessionNotRequested ->
53 | none
54 |
55 | R10.Header.SessionFetching ->
56 | none
57 |
58 | R10.Header.SessionSuccess _ ->
59 | map args.msgMapper <| R10.Header.logoutLink model args
60 |
61 | R10.Header.SessionError _ ->
62 | map args.msgMapper <| R10.Header.urlLogin model args
63 | ]
64 | ]
65 | , el [ alignBottom, centerX, Font.size 14 ] <| text "© Rakuten, Inc."
66 | ]
67 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Html/String/Lazy.elm:
--------------------------------------------------------------------------------
1 | module Html.String.Lazy exposing (lazy, lazy2, lazy3, lazy4, lazy5, lazy6, lazy7, lazy8)
2 |
3 | {-|
4 |
5 |
6 | # 🔥 This isn't actually lazy in this library..
7 |
8 | .. because we can't keep track of the model without existential types. It just
9 | eagerly evaluates. This set of function is here to serve as a drop-in
10 | replacement.
11 |
12 | @docs lazy, lazy2, lazy3, lazy4, lazy5, lazy6, lazy7, lazy8
13 |
14 | -}
15 |
16 | import Html.String exposing (Html)
17 |
18 |
19 | {-| A performance optimization that delays the building of virtual DOM nodes.
20 |
21 | Calling `(view model)` will definitely build some virtual DOM, perhaps a lot of
22 | it. Calling `(lazy view model)` delays the call until later. During diffing, we
23 | can check to see if `model` is referentially equal to the previous value used,
24 | and if so, we just stop. No need to build up the tree structure and diff it,
25 | we know if the input to `view` is the same, the output must be the same!
26 |
27 | -}
28 | lazy : (a -> Html msg) -> a -> Html msg
29 | lazy f x =
30 | f x
31 |
32 |
33 | {-| Same as `lazy` but checks on two arguments.
34 | -}
35 | lazy2 : (a -> b -> Html msg) -> a -> b -> Html msg
36 | lazy2 f x y =
37 | f x y
38 |
39 |
40 | {-| Same as `lazy` but checks on three arguments.
41 | -}
42 | lazy3 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg
43 | lazy3 f x y z =
44 | f x y z
45 |
46 |
47 | {-| Same as `lazy` but checks on four arguments.
48 | -}
49 | lazy4 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg
50 | lazy4 f x y z =
51 | f x y z
52 |
53 |
54 | {-| Same as `lazy` but checks on five arguments.
55 | -}
56 | lazy5 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg
57 | lazy5 f x y z =
58 | f x y z
59 |
60 |
61 | {-| Same as `lazy` but checks on six arguments.
62 | -}
63 | lazy6 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg
64 | lazy6 f x y z =
65 | f x y z
66 |
67 |
68 | {-| Same as `lazy` but checks on seven arguments.
69 | -}
70 | lazy7 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg
71 | lazy7 f x y z =
72 | f x y z
73 |
74 |
75 | {-| Same as `lazy` but checks on eight arguments.
76 | -}
77 | lazy8 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg
78 | lazy8 f x y z =
79 | f x y z
80 |
--------------------------------------------------------------------------------
/src/R10/Translations.elm:
--------------------------------------------------------------------------------
1 | module R10.Translations exposing (language, signIn, signInHeader, signOut)
2 |
3 | {-| Text translations.
4 |
5 | This is an examples of translation:
6 |
7 | signInHeader : R10.Language.Translations
8 | signInHeader =
9 | { key = "signInHeader"
10 | , en_us = "Sign in to your Rakuten account"
11 | , ja_jp = "楽天会員 ログイン"
12 | , zh_tw = "登錄您的Rakuten帳戶"
13 | , de_de = "Loggen Sie sich in Ihr Rakuten-Konto ein"
14 | , fr_fr = "Connectez-vous à votre compte Rakuten"
15 | }
16 |
17 | @docs language, signIn, signInHeader, signOut
18 |
19 | -}
20 |
21 | import R10.Language
22 |
23 |
24 | {-| -}
25 | signInHeader : R10.Language.Translations
26 | signInHeader =
27 | { key = "signInHeader"
28 | , en_us = "Sign in to your Rakuten account"
29 | , ja_jp = "楽天会員 ログイン"
30 | , zh_tw = "登錄您的Rakuten帳戶"
31 | , zh_cn = "登录您的Rakuten帐户"
32 | , de_de = "Loggen Sie sich in Ihr Rakuten-Konto ein[[R]]"
33 | , fr_fr = "Connectez-vous à votre compte Rakuten"
34 | , es_es = "Inicie sesión en su cuenta de Rakuten"
35 | , it_it = "Collegati col tuo account Rakuten"
36 | , uk_ua = ""
37 | , pt_pt = ""
38 | , nl_nl = ""
39 | }
40 |
41 |
42 | {-| -}
43 | language : R10.Language.Translations
44 | language =
45 | { key = "language"
46 | , en_us = "Language"
47 | , ja_jp = "言語"
48 | , zh_tw = "語言"
49 | , zh_cn = "语言"
50 | , de_de = "Sprache"
51 | , fr_fr = "Langue"
52 | , es_es = "Idioma"
53 | , it_it = "Lingua"
54 | , uk_ua = ""
55 | , pt_pt = ""
56 | , nl_nl = ""
57 | }
58 |
59 |
60 | {-| -}
61 | signOut : R10.Language.Translations
62 | signOut =
63 | { key = "signOut"
64 | , en_us = "Sign Out"
65 | , ja_jp = "ログアウト"
66 | , zh_tw = "登出"
67 | , zh_cn = "登出"
68 | , de_de = "Ausloggen"
69 | , fr_fr = "Déconnexion"
70 | , es_es = "Desconectar"
71 | , it_it = "Disconnetti"
72 | , uk_ua = ""
73 | , pt_pt = ""
74 | , nl_nl = ""
75 | }
76 |
77 |
78 | {-| -}
79 | signIn : R10.Language.Translations
80 | signIn =
81 | { key = "signIn"
82 | , en_us = "Sign in"
83 | , ja_jp = "ログイン"
84 | , zh_tw = "登入"
85 | , zh_cn = "登入"
86 | , de_de = "Anmelden"
87 | , fr_fr = "Se connecter"
88 | , es_es = "Registrarse"
89 | , it_it = ""
90 | , uk_ua = ""
91 | , pt_pt = ""
92 | , nl_nl = ""
93 | }
94 |
--------------------------------------------------------------------------------
/src/R10/Libu.elm:
--------------------------------------------------------------------------------
1 | module R10.Libu exposing (view, Type(..))
2 |
3 | {-|
4 |
5 | ██ ██ ██████ ██ ██
6 | ██ ██ ██ ██ ██ ██
7 | ██ ██ ██████ ██ ██
8 | ██ ██ ██ ██ ██ ██
9 | ███████ ██ ██████ ██████
10 |
11 | Hi! I'm Libu, your new friend, half Link and half Button
12 |
13 | I am a super-entity that will take care of all your hypertext necessity
14 | as I will let user to go wherever they want.
15 |
16 | @docs view, Type
17 |
18 | -}
19 |
20 | import Element.WithContext exposing (..)
21 | import Element.WithContext.Input as Input
22 | import Html
23 | import Html.Events
24 | import Json.Decode
25 | import R10.Context exposing (..)
26 |
27 |
28 | {-| `LiNewTab` => A link that open in a new tab.
29 |
30 | `LiInternal` => A link that prevent the default behavior of the browser, to be used in SPA so that the browser doesn't refresh.
31 |
32 | `Li` => Just a link.
33 |
34 | `Bu` => Just a button.
35 |
36 | -}
37 | type Type msg
38 | = LiNewTab String
39 | | LiInternal String (String -> msg)
40 | | Li String
41 | | Bu (Maybe msg)
42 |
43 |
44 | {-| -}
45 | view :
46 | List (Attribute (R10.Context.ContextInternal z) msg)
47 | -> { type_ : Type msg, label : Element (R10.Context.ContextInternal z) msg }
48 | -> Element (R10.Context.ContextInternal z) msg
49 | view attrs args =
50 | case args.type_ of
51 | Li url ->
52 | link
53 | attrs
54 | { label = args.label
55 | , url = url
56 | }
57 |
58 | LiNewTab url ->
59 | newTabLink
60 | attrs
61 | { label = args.label
62 | , url = url
63 | }
64 |
65 | LiInternal url onClick ->
66 | let
67 | -- From https://github.com/elm/browser/blob/1.0.2/notes/navigation-in-elements.md
68 | preventDefault : msg -> Html.Attribute msg
69 | preventDefault msg =
70 | Html.Events.preventDefaultOn "click" (Json.Decode.succeed ( msg, True ))
71 | in
72 | link
73 | ((htmlAttribute <| preventDefault (onClick url)) :: attrs)
74 | { label = args.label
75 | , url = url
76 | }
77 |
78 | Bu onPress ->
79 | Input.button
80 | attrs
81 | { label = args.label
82 | , onPress = onPress
83 | }
84 |
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/ExtraCss.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.ExtraCss exposing (extraCss)
2 |
3 | import Element.WithContext exposing (..)
4 | import R10.Context exposing (..)
5 | import R10.FormComponents.Internal.Single
6 | import R10.FormComponents.Internal.Text
7 | import R10.FormComponents.Internal.UI.Color
8 | import R10.FormComponents.Internal.Validations
9 | import R10.Palette
10 |
11 |
12 | extraCss : R10.Palette.Palette -> String
13 | extraCss palette =
14 | R10.FormComponents.Internal.Text.extraCss
15 | ++ R10.FormComponents.Internal.Single.extraCss
16 | ++ R10.FormComponents.Internal.Validations.extraCss
17 | ++ ripple
18 | (R10.FormComponents.Internal.UI.Color.onSurface palette)
19 | (R10.FormComponents.Internal.UI.Color.primary palette)
20 | (R10.FormComponents.Internal.UI.Color.onPrimary palette)
21 |
22 |
23 | ripple : Color -> Color -> Color -> String
24 | ripple onSurface primary onPrimary =
25 | let
26 | onSurfaceStr : String
27 | onSurfaceStr =
28 | onSurface |> R10.FormComponents.Internal.UI.Color.toCssString
29 |
30 | primaryStr : String
31 | primaryStr =
32 | primary |> R10.FormComponents.Internal.UI.Color.toCssString
33 |
34 | onPrimaryStr : String
35 | onPrimaryStr =
36 | onPrimary |> R10.FormComponents.Internal.UI.Color.toCssString
37 | in
38 | rippleStr_ "ripple" onSurfaceStr
39 | ++ rippleStr_ "ripple-primary" primaryStr
40 | ++ rippleStr_ "ripple-on-primary" onPrimaryStr
41 |
42 |
43 | rippleStr_ : String -> String -> String
44 | rippleStr_ className colorStr =
45 | """
46 | .""" ++ className ++ """ {
47 | position: relative;
48 | overflow: hidden;
49 | transform: translate3d(0, 0, 0);
50 | }
51 | .""" ++ className ++ """:after {
52 | content: "";
53 | display: block;
54 | position: absolute;
55 | width: 100%;
56 | height: 100%;
57 | top: 0;
58 | left: 0;
59 | pointer-events: none;
60 | background-image: radial-gradient(circle, """ ++ colorStr ++ """ 10%, transparent 10.01%);
61 | background-repeat: no-repeat;
62 | background-position: 50%;
63 | transform: scale(10, 10);
64 | opacity: 0;
65 | transition: transform .5s, opacity 1s;
66 | }
67 | .""" ++ className ++ """:active:after {
68 | transform: scale(0, 0);
69 | opacity: .2;
70 | transition: 0s;
71 | }
72 | """
73 |
--------------------------------------------------------------------------------
/examples/simpleView/src/Main.elm:
--------------------------------------------------------------------------------
1 | module Main exposing (main)
2 |
3 | import Element.WithContext exposing (..)
4 | import Element.WithContext.Background as Background
5 | import Element.WithContext.Border as Border
6 | import Element.WithContext.Font as Font
7 | import Html
8 | import R10.Button
9 | import R10.Card
10 | import R10.Color
11 | import R10.Color.AttrsBackground
12 | import R10.Color.Svg
13 | import R10.Context
14 | import R10.Device
15 | import R10.FontSize
16 | import R10.Language
17 | import R10.Libu
18 | import R10.Mode
19 | import R10.Paragraph
20 | import R10.Svg.Icons
21 | import R10.Svg.Logos
22 | import R10.Svg.LogosExtra
23 | import R10.Theme
24 |
25 |
26 | main : Html.Html msg
27 | main =
28 | layout R10.Context.default [ R10.Color.AttrsBackground.background, padding 20, R10.FontSize.normal ] <|
29 | column
30 | (R10.Card.high
31 | ++ [ centerX
32 | , centerY
33 | , width (fill |> maximum 360)
34 | , height shrink
35 | , spacing 30
36 | ]
37 | )
38 | [ withContext <| \c -> R10.Svg.LogosExtra.r10 [ centerX ] (R10.Color.Svg.logo c.contextR10.theme) 32
39 | , R10.Paragraph.normalMarkdown [ Font.center ] "This is an example of a view made with [Elm](https://elm-lang.org/), [elm-ui](https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/) and [R10](https://package.elm-lang.org/packages/rakutentech/r10/latest/) ([Source code](https://github.com/rakutentech/r10/blob/master/examples/simpleView/src/Main.elm))."
40 | , el [ Font.size 60, centerX, padding 10 ] <| text "🎉"
41 | , R10.Button.primary []
42 | { label =
43 | withContext <|
44 | \c ->
45 | row [ spacing 15, centerX ]
46 | [ R10.Paragraph.normal [] [ text "Primary Buttons" ]
47 | , R10.Svg.Icons.cart_f [] (R10.Color.Svg.fontHighEmphasisWithMaximumContrast c.contextR10.theme) 18
48 | ]
49 | , libu = R10.Libu.Li "https://r10.netlify.app"
50 | , translation = { key = "primary-example" }
51 | }
52 | , R10.Button.secondary []
53 | { label = R10.Paragraph.normal [] [ text "Secondary Buttons" ]
54 | , libu = R10.Libu.Li "https://r10.netlify.app"
55 | , translation = { key = "secodnary-example" }
56 | }
57 | ]
58 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/Svg.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.Svg exposing
2 | ( arrowDown
3 | , arrowNext
4 | , arrowPrev
5 | , filterList
6 | , removeCircle
7 | )
8 |
9 | import Svg
10 | import Svg.Attributes as SA
11 |
12 |
13 | wrapperWithViewbox : Int -> String -> List (Svg.Svg msg) -> Svg.Svg msg
14 | wrapperWithViewbox size viewbox listSvg =
15 | Svg.svg
16 | [ SA.xmlSpace "http://www.w3.org/2000/svg"
17 | , SA.viewBox viewbox
18 | , SA.height <| String.fromInt size
19 | , SA.preserveAspectRatio "xMinYMin slice"
20 | ]
21 | listSvg
22 |
23 |
24 | arrowPrev : String -> Int -> Svg.Svg msg
25 | arrowPrev color size =
26 | wrapperWithViewbox
27 | size
28 | "0 0 24 24"
29 | [ Svg.path [ SA.fill color, SA.d "M16.62 2.99c-.49-.49-1.28-.49-1.77 0L6.54 11.3c-.39.39-.39 1.02 0 1.41l8.31 8.31c.49.49 1.28.49 1.77 0s.49-1.28 0-1.77L9.38 12l7.25-7.25c.48-.48.48-1.28-.01-1.76z" ] []
30 | ]
31 |
32 |
33 | arrowNext : String -> Int -> Svg.Svg msg
34 | arrowNext color size =
35 | wrapperWithViewbox
36 | size
37 | "0 0 24 24"
38 | [ Svg.path [ SA.fill color, SA.d "M7.38 21.01c.49.49 1.28.49 1.77 0l8.31-8.31c.39-.39.39-1.02 0-1.41L9.15 2.98c-.49-.49-1.28-.49-1.77 0s-.49 1.28 0 1.77L14.62 12l-7.25 7.25c-.48.48-.48 1.28.01 1.76z" ] []
39 | ]
40 |
41 |
42 | arrowDown : String -> Int -> Svg.Svg msg
43 | arrowDown color size =
44 | wrapperWithViewbox
45 | size
46 | "0 0 24 24"
47 | [ Svg.path [ SA.fill color, SA.d "M11 5v11.17l-4.88-4.88c-.39-.39-1.03-.39-1.42 0-.39.39-.39 1.02 0 1.41l6.59 6.59c.39.39 1.02.39 1.41 0l6.59-6.59c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L13 16.17V5c0-.55-.45-1-1-1s-1 .45-1 1z" ] []
48 | ]
49 |
50 |
51 | removeCircle : String -> Int -> Svg.Svg msg
52 | removeCircle color size =
53 | wrapperWithViewbox
54 | size
55 | "0 0 24 24"
56 | [ Svg.path [ SA.fill color, SA.d "M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" ] []
57 | ]
58 |
59 |
60 | filterList : String -> Int -> Svg.Svg msg
61 | filterList color size =
62 | wrapperWithViewbox
63 | size
64 | "0 0 24 24"
65 | [ Svg.path [ SA.fill color, SA.d "M11 18h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM3 7c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1zm4 6h10c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1z" ] []
66 | ]
67 |
--------------------------------------------------------------------------------
/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "package",
3 | "name": "rakutentech/r10",
4 | "summary": "Bootstrapper and UI Components we use at Rakuten",
5 | "license": "BSD-3-Clause",
6 | "version": "7.0.0",
7 | "exposed-modules": [
8 | "R10.Button",
9 | "R10.Card",
10 | "R10.Color",
11 | "R10.Context",
12 | "R10.Counter",
13 | "R10.Country",
14 | "R10.Device",
15 | "R10.DropDown",
16 | "R10.FontSize",
17 | "R10.Footer",
18 | "R10.Form",
19 | "R10.FormDebug",
20 | "R10.FormTypes",
21 | "R10.Header",
22 | "R10.I18n",
23 | "R10.Language",
24 | "R10.LanguageSelector",
25 | "R10.Libu",
26 | "R10.Link",
27 | "R10.Mode",
28 | "R10.Okaimonopanda",
29 | "R10.Paragraph",
30 | "R10.SimpleMarkdown",
31 | "R10.Table",
32 | "R10.Theme",
33 | "R10.Translations",
34 | "R10.Color.AttrsBackground",
35 | "R10.Color.AttrsBorder",
36 | "R10.Color.AttrsFont",
37 | "R10.Color.Svg",
38 | "R10.Color.Utils",
39 | "R10.Svg.Icons",
40 | "R10.Svg.IconsExtra",
41 | "R10.Svg.Lists",
42 | "R10.Svg.Logos",
43 | "R10.Svg.LogosExtra",
44 | "R10.Svg.Others",
45 | "R10.Svg.Utils"
46 | ],
47 | "elm-version": "0.19.0 <= v < 0.20.0",
48 | "dependencies": {
49 | "NoRedInk/elm-json-decode-pipeline": "1.0.0 <= v < 2.0.0",
50 | "avh4/elm-color": "1.0.0 <= v < 2.0.0",
51 | "elm/browser": "1.0.2 <= v < 2.0.0",
52 | "elm/core": "1.0.2 <= v < 2.0.0",
53 | "elm/html": "1.0.0 <= v < 2.0.0",
54 | "elm/http": "2.0.0 <= v < 3.0.0",
55 | "elm/json": "1.1.3 <= v < 2.0.0",
56 | "elm/parser": "1.1.0 <= v < 2.0.0",
57 | "elm/regex": "1.0.0 <= v < 2.0.0",
58 | "elm/svg": "1.0.1 <= v < 2.0.0",
59 | "elm/time": "1.0.0 <= v < 2.0.0",
60 | "elm/url": "1.0.0 <= v < 2.0.0",
61 | "elm-community/json-extra": "4.3.0 <= v < 5.0.0",
62 | "elm-community/list-extra": "8.2.4 <= v < 9.0.0",
63 | "elm-community/string-extra": "4.0.1 <= v < 5.0.0",
64 | "lucamug/elm-ui-with-context": "1.0.0 <= v < 2.0.0",
65 | "mdgriffith/elm-ui": "1.1.7 <= v < 2.0.0",
66 | "noahzgordon/elm-color-extra": "1.0.2 <= v < 2.0.0",
67 | "rtfeldman/elm-iso8601-date-strings": "1.1.4 <= v < 2.0.0",
68 | "tasuki/elm-punycode": "1.1.0 <= v < 2.0.0",
69 | "zwilias/json-decode-exploration": "6.0.0 <= v < 7.0.0"
70 | },
71 | "test-dependencies": {}
72 | }
--------------------------------------------------------------------------------
/examples/pwa/src/Pages/Counter.elm:
--------------------------------------------------------------------------------
1 | module Pages.Counter exposing
2 | ( Model
3 | , Msg
4 | , init
5 | , subscriptions
6 | , update
7 | , view
8 | )
9 |
10 | import Browser.Events
11 | import Element exposing (..)
12 | import Element.Font as Font
13 | import R10.Button
14 | import R10.Counter
15 | import R10.Libu
16 | import R10.Theme
17 |
18 |
19 | type alias Model =
20 | { counter : R10.Counter.Counter }
21 |
22 |
23 | init : Model
24 | init =
25 | { counter =
26 | R10.Counter.init
27 | |> R10.Counter.start
28 | }
29 |
30 |
31 | type Msg
32 | = OnAnimationFrame
33 | | GoTo Int
34 | | Add Int
35 |
36 |
37 | update : Msg -> Model -> Model
38 | update msg model =
39 | case msg of
40 | OnAnimationFrame ->
41 | { model | counter = R10.Counter.update model.counter }
42 |
43 | GoTo value ->
44 | { model | counter = R10.Counter.moveTo value model.counter }
45 |
46 | Add value ->
47 | { model | counter = R10.Counter.add value model.counter }
48 |
49 |
50 | view : Model -> R10.Theme.Theme -> List (Element Msg)
51 | view model theme =
52 | [ el [ Font.family [ Font.monospace ] ] <| R10.Counter.view model.counter 100
53 | , row [ spacing 20 ]
54 | [ R10.Button.secondary [ width shrink ]
55 | { label = text "Jump To 10"
56 | , libu = R10.Libu.Bu <| Just <| GoTo 10
57 | , theme = theme
58 | }
59 | , R10.Button.secondary [ width shrink ]
60 | { label = text "Jump To 0"
61 | , libu = R10.Libu.Bu <| Just <| GoTo 0
62 | , theme = theme
63 | }
64 | , R10.Button.secondary [ width shrink ]
65 | { label = text "Add 10"
66 | , libu = R10.Libu.Bu <| Just <| Add 10
67 | , theme = theme
68 | }
69 | , R10.Button.secondary [ width shrink ]
70 | { label = text "Add 94,851"
71 | , libu = R10.Libu.Bu <| Just <| Add 94857
72 | , theme = theme
73 | }
74 | , R10.Button.secondary [ width shrink ]
75 | { label = text "Subtract 10"
76 | , libu = R10.Libu.Bu <| Just <| Add -10
77 | , theme = theme
78 | }
79 | ]
80 | ]
81 |
82 |
83 |
84 | -- COUNTER
85 |
86 |
87 | subscriptions : Model -> Sub Msg
88 | subscriptions model =
89 | Sub.batch <|
90 | if R10.Counter.areMoving [ model.counter ] then
91 | [ Browser.Events.onAnimationFrame (\_ -> OnAnimationFrame) ]
92 |
93 | else
94 | []
95 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/StateForValues.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.StateForValues exposing
2 | ( Entity(..)
3 | , EntityId
4 | , FieldId
5 | , Index
6 | , Value
7 | , encoderEntity
8 | , toString
9 | )
10 |
11 | import Json.Encode as E
12 |
13 |
14 | type alias FieldId =
15 | String
16 |
17 |
18 | type alias EntityId =
19 | String
20 |
21 |
22 | type alias Value =
23 | String
24 |
25 |
26 | type alias Index =
27 | Int
28 |
29 |
30 | type Entity
31 | = EntityField FieldId Value
32 | | EntityMulti EntityId (List Entity)
33 | | EntityIndex Index (List Entity)
34 |
35 |
36 | encoderEntity : Entity -> E.Value
37 | encoderEntity entity =
38 | case entity of
39 | EntityField fieldId value ->
40 | -- E.string <| fieldId ++ ":: " ++ value
41 | E.object
42 | [ ( "id", E.string fieldId )
43 | , ( "string", E.string value )
44 | ]
45 |
46 | EntityMulti entityId listEntity ->
47 | E.object
48 | [ ( "id", E.string entityId )
49 | , ( "list", E.list encoderEntity listEntity )
50 | ]
51 |
52 | EntityIndex _ listEntity ->
53 | -- E.object
54 | -- [ ( "index", E.int index )
55 | -- , ( "list", E.list encoderEntity listEntity )
56 | -- ]
57 | E.list encoderEntity listEntity
58 |
59 |
60 | toString : List Entity -> String
61 | toString entities =
62 | E.encode 4 <| E.list encoderEntity entities
63 |
64 |
65 |
66 | --
67 | -- Study on Firebase data structure
68 | --
69 | -- https://firebase.google.com/docs/firestore/data-model#hierarchical-data
70 | --
71 | -- type alias DocId =
72 | -- String
73 | --
74 | --
75 | -- type alias CollectionId =
76 | -- String
77 | --
78 | --
79 | -- type alias DocValue =
80 | -- String
81 | --
82 | --
83 | -- type Doc
84 | -- = Doc DocId DocValue (List Collection)
85 | --
86 | --
87 | -- type Collection
88 | -- = Collection CollectionId (List Doc)
89 | --
90 | --
91 | -- example : Collection
92 | -- example =
93 | -- Collection "rooms"
94 | -- [ Doc "roomA"
95 | -- "name: my chat room"
96 | -- [ Collection "messages"
97 | -- [ Doc "message1" "from: alex, msg: Hello world!" []
98 | -- , Doc "message2" "..." []
99 | -- ]
100 | -- ]
101 | -- , Doc "roomB" "..." []
102 | -- ]
103 | --
104 |
--------------------------------------------------------------------------------
/examples/pwa/src/Pages/Form_Example_PhoneSelector.elm:
--------------------------------------------------------------------------------
1 | module Pages.Form_Example_PhoneSelector exposing
2 | ( Model
3 | , Msg
4 | , init
5 | , update
6 | , view
7 | )
8 |
9 | import Element exposing (..)
10 | import R10.Form
11 | import R10.FormTypes
12 | import R10.Theme
13 |
14 |
15 | type alias Model =
16 | { phone1 : R10.Form.PhoneModel
17 | , phone2 : R10.Form.PhoneModel
18 | , disabled : Bool
19 | , messages : List String
20 | , valid : Maybe Bool
21 | }
22 |
23 |
24 | init : Model
25 | init =
26 | { phone1 = R10.Form.phoneInit
27 | , phone2 = R10.Form.phoneInit
28 | , disabled = False
29 | , messages = []
30 | , valid = Nothing
31 | }
32 |
33 |
34 | type Msg
35 | = OnPhoneMsg1 R10.Form.PhoneMsg
36 | | OnPhoneMsg2 R10.Form.PhoneMsg
37 |
38 |
39 | update : Msg -> Model -> ( Model, Cmd Msg )
40 | update msg model =
41 | case msg of
42 | OnPhoneMsg1 singleMsg ->
43 | let
44 | ( selectState, selectCmd ) =
45 | R10.Form.phoneUpdate singleMsg model.phone1
46 | in
47 | ( { model | phone1 = selectState }, Cmd.map OnPhoneMsg1 selectCmd )
48 |
49 | OnPhoneMsg2 singleMsg ->
50 | let
51 | ( selectState, selectCmd ) =
52 | R10.Form.phoneUpdate singleMsg model.phone2
53 | in
54 | ( { model | phone2 = selectState }, Cmd.map OnPhoneMsg2 selectCmd )
55 |
56 |
57 | view : Model -> R10.Theme.Theme -> List (Element Msg)
58 | view model theme =
59 | let
60 | palette : R10.FormTypes.Palette
61 | palette =
62 | R10.Form.themeToPalette theme
63 | in
64 | [ row
65 | [ spacing 40, width fill, padding 40 ]
66 | [ R10.Form.phoneView
67 | []
68 | model.phone1
69 | { valid = model.valid
70 | , toMsg = OnPhoneMsg1
71 | , label = "Phone number"
72 | , helperText = Nothing
73 | , disabled = model.disabled
74 | , requiredLabel = Nothing
75 | , style = R10.Form.style.outlined
76 | , key = "field1"
77 | , palette = palette
78 | , countryOptions = Nothing
79 | }
80 | , R10.Form.phoneView
81 | []
82 | model.phone2
83 | { valid = model.valid
84 | , toMsg = OnPhoneMsg2
85 | , label = "Phone number"
86 | , helperText = Nothing
87 | , disabled = model.disabled
88 | , requiredLabel = Nothing
89 | , style = R10.Form.style.filled
90 | , key = "field2"
91 | , palette = palette
92 | , countryOptions = Nothing
93 | }
94 | ]
95 | ]
96 |
--------------------------------------------------------------------------------
/src/R10/Svg/Utils.elm:
--------------------------------------------------------------------------------
1 | module R10.Svg.Utils exposing (wrapperWithViewbox, wrapper32)
2 |
3 | {-| Utilities to render SVG elements.
4 |
5 | @docs wrapperWithViewbox, wrapper32
6 |
7 | -}
8 |
9 | import Element.WithContext exposing (..)
10 | import Html.Attributes
11 | import R10.Context exposing (..)
12 | import Svg
13 | import Svg.Attributes as SA
14 |
15 |
16 |
17 | -- WRAPPERS
18 |
19 |
20 | svgSize_ : String -> Int -> List (Svg.Attribute msg)
21 | svgSize_ viewbox ySize =
22 | --
23 | -- IE11 is very picky about knowing all sizes of a SVG so
24 | -- here we calculate the width starting from the height
25 | -- using the viewbox.
26 | --
27 | case String.split " " viewbox of
28 | [ x, y, dx, dy ] ->
29 | Maybe.withDefault [ SA.height <| String.fromInt ySize ] <|
30 | Maybe.map4
31 | (\_ _ dx_ dy_ ->
32 | let
33 | xSize : Float
34 | xSize =
35 | (dx_ * toFloat ySize) / dy_
36 | in
37 | [ SA.height <| String.fromInt ySize
38 | , SA.width <| String.fromFloat xSize
39 | ]
40 | )
41 | (String.toFloat x)
42 | (String.toFloat y)
43 | (String.toFloat dx)
44 | (String.toFloat dy)
45 |
46 | _ ->
47 | [ SA.height <| String.fromInt ySize ]
48 |
49 |
50 | {-| -}
51 | wrapperWithViewbox_ : String -> Int -> List (Svg.Svg msg) -> Svg.Svg msg
52 | wrapperWithViewbox_ viewbox ySize listSvg =
53 | Svg.svg
54 | ([ Html.Attributes.attribute "xmlns" "http://www.w3.org/2000/svg"
55 | , Html.Attributes.attribute "xmlns:xlink" "http://www.w3.org/1999/xlink"
56 | , SA.version "1.1"
57 | , SA.preserveAspectRatio "xMinYMin slice"
58 | , SA.viewBox viewbox
59 |
60 | -- This fix a bug in IE11:
61 | -- https://stackoverflow.com/questions/29393144/how-to-prevent-svg-elements-from-gaining-focus-with-tabs-in-ie11
62 | --
63 | , Html.Attributes.attribute "focusable" "false"
64 | ]
65 | ++ svgSize_ viewbox ySize
66 | )
67 | listSvg
68 |
69 |
70 | {-| -}
71 | wrapperWithViewbox : List (Attribute (R10.Context.ContextInternal z) msg) -> String -> Int -> List (Svg.Svg msg) -> Element (R10.Context.ContextInternal z) msg
72 | wrapperWithViewbox attrs viewbox size listSvg =
73 | el attrs <| html <| wrapperWithViewbox_ viewbox size listSvg
74 |
75 |
76 | {-| -}
77 | wrapper32 : List (Attribute (R10.Context.ContextInternal z) msg) -> Int -> List (Svg.Svg msg) -> Element (R10.Context.ContextInternal z) msg
78 | wrapper32 attrs size listSvg =
79 | wrapperWithViewbox attrs "0 0 32 32" size listSvg
80 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Application.elm:
--------------------------------------------------------------------------------
1 | module Application exposing (main)
2 |
3 | import Browser
4 | import Html
5 | import Html.Attributes
6 | import Json.Encode
7 | import Starter.Conf
8 |
9 |
10 | type Msg
11 | = OnUrlRequest
12 | | OnUrlChange
13 |
14 |
15 | type alias Flags =
16 | ()
17 |
18 |
19 | type alias Model =
20 | ()
21 |
22 |
23 | view : Model -> { body : List (Html.Html msg), title : String }
24 | view _ =
25 | { title = "title"
26 | , body =
27 | [ Html.div [ Html.Attributes.style "margin" "40px" ]
28 | [ Html.h1 [] [ Html.text "elm-starter configuration" ]
29 | , Html.pre
30 | []
31 | [ Html.text <|
32 | Json.Encode.encode 4 <|
33 | Starter.Conf.conf
34 | -- From package.jspn
35 | { name = "NOT-AVAILABLE [name]"
36 | , nameLong = "NOT-AVAILABLE [nameLong]"
37 | , description = "NOT-AVAILABLE [description]"
38 | , author = "NOT-AVAILABLE [author]"
39 | , version = "NOT-AVAILABLE [version]"
40 | , homepage = "http://example.com/xxx/yyy"
41 | , license = "NOT-AVAILABLE [license]"
42 | , twitterSite = Just "NOT-AVAILABLE [twitterSite]"
43 | , twitterAuthor = Just "NOT-AVAILABLE [twitterAuthor]"
44 | , snapshotWidth = Just "NOT-AVAILABLE [snapshotWidth]"
45 | , snapshotHeight = Just "NOT-AVAILABLE [snapshotHeight]"
46 | , themeColor = Nothing
47 |
48 | -- From Git
49 | , commit = "NOT-AVAILABLE [commit]"
50 | , branch = "NOT-AVAILABLE [branch]"
51 |
52 | -- From starter.js
53 | , env = "NOT-AVAILABLE [env]"
54 | , dirPw = "NOT-AVAILABLE [dirPw]"
55 | , dirBin = "NOT-AVAILABLE [dirBin]"
56 | , dirIgnoredByGit = "NOT-AVAILABLE [dirIgnoredByGit]"
57 | , dirTemp = "NOT-AVAILABLE [dirTemp]"
58 | , fileElmWorker = "NOT-AVAILABLE [fileElmWorker]"
59 | }
60 | ]
61 | ]
62 | ]
63 | }
64 |
65 |
66 | main : Program Flags Model Msg
67 | main =
68 | Browser.application
69 | { init = \_ _ _ -> ( (), Cmd.none )
70 | , view = view
71 | , update = \_ model -> ( model, Cmd.none )
72 | , subscriptions = \_ -> Sub.none
73 | , onUrlRequest = \_ -> OnUrlRequest
74 | , onUrlChange = \_ -> OnUrlChange
75 | }
76 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/Config.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.Config exposing
2 | ( ColumnAttrs
3 | , ColumnConf
4 | , Config
5 | , FiltersConfig
6 | , HeaderInfo
7 | , PaginationConfig
8 | )
9 |
10 | import Element.WithContext exposing (..)
11 | import R10.Context exposing (..)
12 | import R10.Palette
13 | import R10.Table.Internal.Msg
14 | import R10.Table.Internal.Types
15 |
16 |
17 | {-| There are quite a lot of ways to customize the `
` tag. You can add
18 | a `` which can be styled via CSS. You can do crazy stuff with
19 | `` to group columns in weird ways. You can have a `` tag for
20 | summaries of various columns. And maybe you want to put attributes on ``
21 | or on particular rows in the body. All these customizations are available to you.
22 | -}
23 |
24 |
25 |
26 | --type alias Customizations data msg =
27 | -- { --columnHeaderView : List (HeaderData data msg) -> Element (R10.Context.ContextInternal z) msg
28 | -- --,
29 | -- bodyAttrs : List (Attribute (R10.Context.ContextInternal z) msg)
30 | -- , rowAttrsBuilder : Maybe data -> List (Attribute (R10.Context.ContextInternal z) msg)
31 | -- }
32 |
33 |
34 | type alias PaginationConfig =
35 | { lengthOptions : List Int }
36 |
37 |
38 | type alias FiltersConfig =
39 | { filterFields : List R10.Table.Internal.Types.Filter
40 | }
41 |
42 |
43 |
44 | -- CONFIG
45 |
46 |
47 | {-| Configuration for your table, describing your columns.
48 |
49 | **Note:** Your `Config` should _never_ be held in your model.
50 | It should only appear in `view` code.
51 |
52 | -- todo exposing `Config(..)` would be the same as using `type alias`?
53 |
54 | -}
55 | type alias Config data msg context =
56 | { toId : data -> String
57 | , toMsg : R10.Table.Internal.Msg.Msg -> msg
58 | , columns : List (ColumnConf data msg context)
59 | , bodyAttrs : List (Attribute (R10.Context.ContextInternal context) msg)
60 | , rowAttrsBuilder : Maybe data -> List (Attribute (R10.Context.ContextInternal context) msg)
61 | , maybePaginationConfig : Maybe PaginationConfig
62 | , maybeFiltersConfig : Maybe FiltersConfig
63 | }
64 |
65 |
66 | type alias ColumnConf data msg context =
67 | { name : String
68 | , viewCell : R10.Palette.Palette -> Maybe data -> Element (R10.Context.ContextInternal context) msg
69 | , viewHeader : R10.Palette.Palette -> HeaderInfo msg -> Element (R10.Context.ContextInternal context) msg
70 | , sorter : R10.Table.Internal.Types.Sorter data
71 | }
72 |
73 |
74 | type alias HeaderInfo msg =
75 | { name : String
76 | , sortStatus : R10.Table.Internal.Types.Status
77 | , onSortMsg : msg
78 | }
79 |
80 |
81 | type alias ColumnAttrs msg context =
82 | { header : List (Attribute (R10.Context.ContextInternal context) msg)
83 | , cell : List (Attribute (R10.Context.ContextInternal context) msg)
84 | }
85 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/Sorter.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.Sorter exposing
2 | ( increasingOrDecreasingBy
3 | , sort
4 | , unsortable
5 | )
6 |
7 | import R10.Table.Internal.Config
8 | import R10.Table.Internal.State
9 | import R10.Table.Internal.Types
10 |
11 |
12 |
13 | -- SORTING
14 |
15 |
16 | sort :
17 | R10.Table.Internal.State.State
18 | -> List (R10.Table.Internal.Config.ColumnConf data msg context)
19 | -> List data
20 | -> List data
21 | sort state columnData data =
22 | case findSorter state.sort.name columnData of
23 | Nothing ->
24 | data
25 |
26 | Just sorter ->
27 | applySorter state.sort.isReversed sorter data
28 |
29 |
30 | applySorter : Bool -> R10.Table.Internal.Types.Sorter data -> List data -> List data
31 | applySorter isReversed sorter data =
32 | case sorter of
33 | R10.Table.Internal.Types.None ->
34 | data
35 |
36 | R10.Table.Internal.Types.Increasing sort_ ->
37 | sort_ data
38 |
39 | R10.Table.Internal.Types.Decreasing sort_ ->
40 | List.reverse (sort_ data)
41 |
42 | R10.Table.Internal.Types.IncOrDec sort_ ->
43 | if isReversed then
44 | List.reverse (sort_ data)
45 |
46 | else
47 | sort_ data
48 |
49 | R10.Table.Internal.Types.DecOrInc sort_ ->
50 | if isReversed then
51 | sort_ data
52 |
53 | else
54 | List.reverse (sort_ data)
55 |
56 |
57 | findSorter :
58 | String
59 | -> List (R10.Table.Internal.Config.ColumnConf data msg context)
60 | -> Maybe (R10.Table.Internal.Types.Sorter data)
61 | findSorter selectedColumn columnData =
62 | case columnData of
63 | [] ->
64 | Nothing
65 |
66 | { name, sorter } :: remainingColumnData ->
67 | if name == selectedColumn then
68 | Just sorter
69 |
70 | else
71 | findSorter selectedColumn remainingColumnData
72 |
73 |
74 |
75 | -- SORTERS
76 |
77 |
78 | {-| A sorter for columns that are unsortable. Maybe you have a column in your
79 | table for delete buttons that delete the row. It would not make any sense to
80 | sort based on that column.
81 | -}
82 | unsortable : R10.Table.Internal.Types.Sorter data
83 | unsortable =
84 | R10.Table.Internal.Types.None
85 |
86 |
87 | {-| Sometimes you want to be able to sort data in increasing _or_ decreasing
88 | order. Maybe you have race times for the 100 meter sprint. This function lets
89 | sort by best time by default, but also see the other order.
90 |
91 | sorter : R10.Table.Internal.State.Sorter { a | time : comparable }
92 | sorter =
93 | increasingOrDecreasingBy .time
94 |
95 | -}
96 | increasingOrDecreasingBy : (data -> comparable) -> R10.Table.Internal.Types.Sorter data
97 | increasingOrDecreasingBy toComparable =
98 | R10.Table.Internal.Types.IncOrDec (List.sortBy toComparable)
99 |
--------------------------------------------------------------------------------
/src/R10/Paragraph.elm:
--------------------------------------------------------------------------------
1 | module R10.Paragraph exposing
2 | ( large, normal, small, xlarge, xxlarge, xsmall, xxsmall
3 | , normalMarkdown
4 | )
5 |
6 | {-| Paraggraphs.
7 |
8 | @docs large, normal, small, xlarge, xxlarge, xsmall, xxsmall
9 |
10 | @docs normalMarkdown
11 |
12 | -}
13 |
14 | import Element.WithContext exposing (..)
15 | import R10.Context exposing (..)
16 | import R10.FontSize
17 | import R10.Link
18 | import R10.SimpleMarkdown
19 |
20 |
21 | spacingNormal : Int
22 | spacingNormal =
23 | 10
24 |
25 |
26 | {-| -}
27 | xxlarge : List (Attribute (R10.Context.ContextInternal z) msg) -> List (Element (R10.Context.ContextInternal z) msg) -> Element (R10.Context.ContextInternal z) msg
28 | xxlarge attrs children =
29 | paragraph ([ R10.FontSize.xxlarge, spacing <| spacingNormal ] ++ attrs) children
30 |
31 |
32 | {-| -}
33 | xlarge : List (Attribute (R10.Context.ContextInternal z) msg) -> List (Element (R10.Context.ContextInternal z) msg) -> Element (R10.Context.ContextInternal z) msg
34 | xlarge attrs children =
35 | paragraph ([ R10.FontSize.xlarge, spacing <| spacingNormal ] ++ attrs) children
36 |
37 |
38 | {-| -}
39 | large : List (Attribute (R10.Context.ContextInternal z) msg) -> List (Element (R10.Context.ContextInternal z) msg) -> Element (R10.Context.ContextInternal z) msg
40 | large attrs children =
41 | paragraph ([ R10.FontSize.large, spacing <| spacingNormal ] ++ attrs) children
42 |
43 |
44 | {-| -}
45 | normalMarkdown : List (Attribute (R10.Context.ContextInternal z) msg) -> String -> Element (R10.Context.ContextInternal z) msg
46 | normalMarkdown attrs string =
47 | normal attrs
48 | (R10.SimpleMarkdown.elementMarkdownAdvanced
49 | { link = R10.Link.attrsUnderline }
50 | string
51 | )
52 |
53 |
54 | {-| -}
55 | normal : List (Attribute (R10.Context.ContextInternal z) msg) -> List (Element (R10.Context.ContextInternal z) msg) -> Element (R10.Context.ContextInternal z) msg
56 | normal attrs children =
57 | paragraph ([ R10.FontSize.normal, spacing <| spacingNormal ] ++ attrs) children
58 |
59 |
60 | {-| -}
61 | small : List (Attribute (R10.Context.ContextInternal z) msg) -> List (Element (R10.Context.ContextInternal z) msg) -> Element (R10.Context.ContextInternal z) msg
62 | small attrs children =
63 | paragraph ([ R10.FontSize.small, spacing <| spacingNormal - 3 ] ++ attrs) children
64 |
65 |
66 | {-| -}
67 | xsmall : List (Attribute (R10.Context.ContextInternal z) msg) -> List (Element (R10.Context.ContextInternal z) msg) -> Element (R10.Context.ContextInternal z) msg
68 | xsmall attrs children =
69 | paragraph ([ R10.FontSize.xsmall, spacing <| spacingNormal - 6 ] ++ attrs) children
70 |
71 |
72 | {-| -}
73 | xxsmall : List (Attribute (R10.Context.ContextInternal z) msg) -> List (Element (R10.Context.ContextInternal z) msg) -> Element (R10.Context.ContextInternal z) msg
74 | xxsmall attrs children =
75 | paragraph ([ R10.FontSize.xsmall, spacing <| spacingNormal - 9 ] ++ attrs) children
76 |
--------------------------------------------------------------------------------
/src/R10/ValidationDate.elm:
--------------------------------------------------------------------------------
1 | module R10.ValidationDate exposing
2 | ( Range
3 | , RangeResult(..)
4 | , dateToMillis
5 | , range
6 | )
7 |
8 | import Iso8601
9 | import Parser
10 | import R10.Utils
11 | import Time
12 |
13 |
14 | prepareDate : String -> Result RangeResult String
15 | prepareDate value =
16 | -- Remove non-digits and extract year/month/day.
17 | -- Format the output as YYYY-MM-DD unless there
18 | -- errors. In which case it returns "" that will
19 | -- then fail later, during the conversion to date.
20 | let
21 | newValue : String
22 | newValue =
23 | value
24 | -- Remove all non-digits
25 | |> R10.Utils.userReplace "[^\\d]" (\_ -> "")
26 | -- Add an extra zero if needed, for example
27 | -- "2000/01/2" -> "2000/01/02"
28 | |> (\v ->
29 | if String.length v == 7 then
30 | String.left 6 v ++ "0" ++ String.right 1 v
31 |
32 | else
33 | v
34 | )
35 | in
36 | if String.length newValue /= 8 then
37 | Err Need8Digits
38 |
39 | else
40 | let
41 | year : String
42 | year =
43 | String.slice 0 4 newValue
44 |
45 | month : String
46 | month =
47 | String.slice 4 6 newValue
48 |
49 | day : String
50 | day =
51 | String.slice 6 8 newValue
52 | in
53 | Ok <| year ++ "-" ++ month ++ "-" ++ day
54 |
55 |
56 | dateToMillis : String -> Result RangeResult Int
57 | dateToMillis date =
58 | case prepareDate date of
59 | Err rangeResult ->
60 | Err rangeResult
61 |
62 | Ok preparedDate ->
63 | case Iso8601.toTime preparedDate of
64 | Err iso8601Error ->
65 | Err <| ParsingError iso8601Error
66 |
67 | Ok posix ->
68 | Ok <| Time.posixToMillis posix
69 |
70 |
71 | type RangeResult
72 | = TooOld
73 | | TooNew
74 | | MinRangeNotValid
75 | | MaxRangeNotValid
76 | | InvertedMinMax
77 | | Need8Digits
78 | | ParsingError (List Parser.DeadEnd)
79 |
80 |
81 | type alias Range =
82 | { min : Int, max : Int }
83 |
84 |
85 | range : Range -> String -> Result RangeResult Int
86 | range { min, max } date =
87 | let
88 | maybePosixDate =
89 | dateToMillis date
90 | in
91 | case maybePosixDate of
92 | Err err ->
93 | Err err
94 |
95 | Ok posixDate ->
96 | if min > max then
97 | Err InvertedMinMax
98 |
99 | else if posixDate < min then
100 | Err TooOld
101 |
102 | else if posixDate > max then
103 | Err TooNew
104 |
105 | else
106 | Ok posixDate
107 |
--------------------------------------------------------------------------------
/src/R10/Color/Utils.elm:
--------------------------------------------------------------------------------
1 | module R10.Color.Utils exposing (fromColorColor, toColorColor, fromHex, fromLightToDark, setAlpha, toCssRgba, fromHexToColorColor)
2 |
3 | {-| Utilities for colors.
4 |
5 | There are two competing color types in this library:
6 |
7 | - `Color.Color` (from `avh4/elm-color`)
8 | - `Color` (from `mdgriffith/elm-ui`)
9 |
10 | The default color type is `Color`.
11 |
12 | @docs fromColorColor, toColorColor, fromHex, fromLightToDark, setAlpha, toCssRgba, fromHexToColorColor
13 |
14 | -}
15 |
16 | import Color
17 | import Color.Convert
18 | import Color.Manipulate
19 | import Element.WithContext exposing (..)
20 |
21 |
22 |
23 | -- import R10.Context exposing (..)
24 |
25 |
26 | {-| Transform a `Color.Color` into an `Color`.
27 | -}
28 | fromColorColor : Color.Color -> Color
29 | fromColorColor color =
30 | let
31 | { red, green, blue, alpha } =
32 | Color.toRgba color
33 | in
34 | rgba red green blue alpha
35 |
36 |
37 | {-| Transform an `Color` into a `Color.Color`.
38 | -}
39 | toColorColor : Color -> Color.Color
40 | toColorColor elementColor =
41 | let
42 | { red, green, blue, alpha } =
43 | toRgb elementColor
44 | in
45 | Color.fromRgba { red = red, green = green, blue = blue, alpha = alpha }
46 |
47 |
48 | {-| Convert a string containing an hexadecimal number into a `Color.Color`.
49 | -}
50 | fromHexToColorColor : String -> Color.Color
51 | fromHexToColorColor hex =
52 | let
53 | resultColor : Result String Color.Color
54 | resultColor =
55 | Color.Convert.hexToColor hex
56 |
57 | color : Color.Color
58 | color =
59 | Result.withDefault (Color.fromRgba { red = 0, green = 0, blue = 0, alpha = 0 }) resultColor
60 | in
61 | color
62 |
63 |
64 | {-| Convert a string containing an hexadecimal number into an `Color`.
65 | -}
66 | fromHex : String -> Color
67 | fromHex hex =
68 | hex
69 | |> fromHexToColorColor
70 | |> fromColorColor
71 |
72 |
73 | {-| Convert an `Color` to a RGBA string, for example: rgba(100, 200, 0, 1)
74 | -}
75 | toCssRgba : Color -> String
76 | toCssRgba elementColor =
77 | elementColor
78 | |> toColorColor
79 | |> Color.Convert.colorToCssRgba
80 |
81 |
82 | {-| Convert a color from Light Mode to Dark Mode. This function works for `Color.Color` type.
83 | -}
84 | fromLightToDark : Color.Color -> Color.Color
85 | fromLightToDark color =
86 | color
87 | |> Color.Manipulate.scaleHsl
88 | { saturationScale = -0.17
89 | , lightnessScale = -0.04
90 | , alphaScale = 0
91 | }
92 |
93 |
94 | {-| Change the alpha channel in a color. This function works for `Color.Color` type.
95 | -}
96 | setAlpha : Float -> Color.Color -> Color.Color
97 | setAlpha newAlpha color =
98 | let
99 | c : { alpha : Float, blue : Float, green : Float, red : Float }
100 | c =
101 | Color.toRgba color
102 | in
103 | Color.fromRgba { red = c.red, green = c.green, blue = c.blue, alpha = newAlpha }
104 |
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/IconButton.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.IconButton exposing (view)
2 |
3 | import Element.WithContext exposing (..)
4 | import Element.WithContext.Background as Background
5 | import Element.WithContext.Border as Border
6 | import Html.Attributes
7 | import Html.Events
8 | import Json.Decode
9 | import R10.Context exposing (..)
10 | import R10.FormComponents.Internal.UI
11 | import R10.FormComponents.Internal.UI.Color
12 | import R10.Palette
13 | import R10.Transition
14 |
15 |
16 | view :
17 | List (Attribute (R10.Context.ContextInternal z) msg)
18 | ->
19 | { msgOnClick : Maybe msg
20 | , icon : Element (R10.Context.ContextInternal z) msg
21 | , palette : R10.Palette.Palette
22 | , size : Int
23 | }
24 | -> Element (R10.Context.ContextInternal z) msg
25 | view args { msgOnClick, icon, palette, size } =
26 | let
27 | padding_ : Int
28 | padding_ =
29 | 8
30 |
31 | containerSize : Int
32 | containerSize =
33 | 24
34 |
35 | iconHitboxSize : Int
36 | iconHitboxSize =
37 | size + (padding_ * 2)
38 |
39 | moveUp_ : Float
40 | moveUp_ =
41 | toFloat (iconHitboxSize - containerSize) / 2
42 |
43 | attrsCommon : List (Attr (R10.Context.ContextInternal z) () msg)
44 | attrsCommon =
45 | [ Background.color <| R10.FormComponents.Internal.UI.Color.onSurfaceA 0 palette
46 | , padding padding_
47 | , centerX
48 |
49 | -- achieving `centerY` here. Note: we cannot use `moveUp` because `Html.Attributes.class <| "ripple"` brakes it
50 | , htmlAttribute <| Html.Attributes.style "margin-top" ("-" ++ String.fromFloat moveUp_ ++ "px")
51 | ]
52 |
53 | attrsClickable : List (Attr (R10.Context.ContextInternal z) () msg)
54 | attrsClickable =
55 | case msgOnClick of
56 | Just msgOnClick_ ->
57 | [ htmlAttribute <| Html.Attributes.tabindex 0
58 | , htmlAttribute <| R10.FormComponents.Internal.UI.onSelectKey msgOnClick_
59 | , htmlAttribute <| Html.Events.stopPropagationOn "mouseup" (Json.Decode.succeed ( msgOnClick_, False ))
60 | , htmlAttribute <| Html.Attributes.class <| "ripple"
61 | , R10.Transition.transition "all 0.13s; margin-top 0s "
62 | , pointer
63 | , Border.rounded 40
64 | , mouseOver [ Border.innerShadow { offset = ( 0, 0 ), size = 40, blur = 0, color = R10.FormComponents.Internal.UI.Color.onSurfaceA 0.07 palette } ]
65 | , focused [ Background.color <| R10.FormComponents.Internal.UI.Color.onSurfaceA 0.14 palette ]
66 | ]
67 |
68 | Nothing ->
69 | [ alpha 0.5 ]
70 | in
71 | el
72 | ([ width <| px containerSize
73 | , height <| px containerSize
74 | ]
75 | ++ args
76 | )
77 | <|
78 | el
79 | (attrsCommon ++ attrsClickable)
80 | <|
81 | el [ centerX, centerY, width <| px size, height <| px size ] <|
82 | icon
83 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/ServiceWorker.elm:
--------------------------------------------------------------------------------
1 | module Starter.ServiceWorker exposing
2 | ( encoderCacheableUrls
3 | , precacheFiles
4 | , serviceWorker
5 | )
6 |
7 | import Json.Encode
8 | import Starter.Cache
9 | import Starter.ConfMeta
10 |
11 |
12 | encoderCacheableUrls : { a | revision : String, url : String } -> Json.Encode.Value
13 | encoderCacheableUrls obj =
14 | Json.Encode.object
15 | [ ( "url", Json.Encode.string obj.url )
16 | , ( "revision", Json.Encode.string obj.revision )
17 | ]
18 |
19 |
20 | precacheFiles :
21 | { assets : List ( String, String )
22 | , commit : String
23 | , relative : String
24 | , version : String
25 | }
26 | -> String
27 | precacheFiles { relative, version, commit, assets } =
28 | Starter.Cache.stuffToCache relative version commit assets
29 | |> List.map (\( url, revision ) -> { url = url, revision = revision ++ "." ++ commit })
30 | |> Json.Encode.list encoderCacheableUrls
31 | |> Json.Encode.encode 4
32 |
33 |
34 | serviceWorker :
35 | { assets : List ( String, String )
36 | , commit : String
37 | , relative : String
38 | , version : String
39 | }
40 | -> String
41 | serviceWorker { relative, version, commit, assets } =
42 | "// "
43 | ++ Starter.ConfMeta.confMeta.messageDoNotEditDisclaimer
44 | ++ """
45 | //
46 | // This is implemented using Workbox
47 | // https://developers.google.com/web/tools/workbox
48 | //
49 |
50 | importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');
51 |
52 | const registerRoute = workbox.routing.registerRoute;
53 | const NetworkFirst = workbox.strategies.NetworkFirst;
54 | const CacheFirst = workbox.strategies.CacheFirst;
55 | const StaleWhileRevalidate = workbox.strategies.StaleWhileRevalidate;
56 | const ExpirationPlugin = workbox.expiration.ExpirationPlugin;
57 | const precacheAndRoute = workbox.precaching.precacheAndRoute;
58 |
59 | // https://developers.google.com/web/tools/workbox/guides/precache-files
60 | precacheAndRoute(
61 | """
62 | ++ precacheFiles
63 | { assets = assets
64 | , commit = commit
65 | , relative = relative
66 | , version = version
67 | }
68 | ++ """
69 | );
70 |
71 |
72 | registerRoute(
73 | ({url}) => url.pathname === ('/'),
74 | new NetworkFirst()
75 | );
76 |
77 | registerRoute(
78 | ({request}) => request.destination === 'script',
79 | new NetworkFirst()
80 | );
81 |
82 | registerRoute(
83 | // Cache style assets, i.e. CSS files.
84 | ({request}) => request.destination === 'style',
85 | // Use cache but update in the background.
86 | new StaleWhileRevalidate({
87 | // Use a custom cache name.
88 | cacheName: 'css-cache',
89 | })
90 | );
91 |
92 | // From https://developers.google.com/web/tools/workbox/guides/common-recipes
93 | registerRoute(
94 | ({request}) => request.destination === 'image',
95 | new CacheFirst({
96 | cacheName: 'images',
97 | plugins: [
98 | new ExpirationPlugin({
99 | maxEntries: 60,
100 | maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
101 | }),
102 | ],
103 | })
104 | );
105 | """
106 |
--------------------------------------------------------------------------------
/src/R10/LanguageSelector.elm:
--------------------------------------------------------------------------------
1 | module R10.LanguageSelector exposing (view)
2 |
3 | {-| Dropdown for the language selector
4 |
5 | @docs view
6 |
7 | -}
8 |
9 | import Element.WithContext exposing (..)
10 | import Element.WithContext.Font as Font
11 | import Html.Attributes
12 | import R10.Color.Utils
13 | import R10.Context exposing (..)
14 | import R10.DropDown
15 | import R10.Language
16 | import R10.Svg.Icons
17 |
18 |
19 | {-| -}
20 | view :
21 | List (Attribute (R10.Context.ContextInternal z) msg)
22 | ->
23 | { changeMsg : Result String R10.Language.Language -> msg
24 | , colorBackground : Color
25 | , colorFont : Color
26 | , currentLanguage : R10.Language.Language
27 | , supportedLanguages : List R10.Language.Language
28 | , fontSize : Int
29 | }
30 | -> Element (R10.Context.ContextInternal z) msg
31 | view attrs args =
32 | let
33 | handleInputChange : String -> msg
34 | handleInputChange string =
35 | string
36 | |> R10.Language.decoder args.supportedLanguages
37 | |> args.changeMsg
38 |
39 | optionList : List R10.DropDown.Option
40 | optionList =
41 | args.supportedLanguages
42 | |> List.map
43 | (\locale ->
44 | R10.DropDown.Option
45 | (R10.Language.toString locale)
46 | (R10.Language.toStringLong R10.Language.Localization locale)
47 | )
48 | in
49 | el
50 | (attrs
51 | ++ [ inFront <|
52 | row
53 | [ spacing 7
54 | , htmlAttribute <| Html.Attributes.style "pointer-events" "none"
55 | , htmlAttribute <| Html.Attributes.style "letter-spacing" "0px"
56 | , centerY
57 | , moveRight 2
58 | , Font.size args.fontSize
59 | , Font.color args.colorFont
60 | ]
61 | [ R10.Svg.Icons.world_l [] args.colorFont args.fontSize
62 | , el [ Font.color <| rgba 0 0 0 0 ] <| text <| R10.Language.toStringLong R10.Language.Localization args.currentLanguage
63 | , triangle args.colorFont
64 | ]
65 | ]
66 | )
67 | (R10.DropDown.viewBorderLess []
68 | { colorBackground = args.colorBackground
69 | , colorFont = args.colorFont
70 | , currentValue = R10.Language.toString args.currentLanguage
71 | , inputHandler = handleInputChange
72 | , optionList = optionList
73 | , fontSize = args.fontSize
74 | }
75 | )
76 |
77 |
78 | getBorderAttr : Int -> String -> String
79 | getBorderAttr width colorHex =
80 | String.join " " [ String.fromInt width ++ "px", "solid", colorHex ]
81 |
82 |
83 | triangle : Color -> Element (R10.Context.ContextInternal z) msg
84 | triangle colorFont =
85 | el
86 | (List.map htmlAttribute <|
87 | [ Html.Attributes.style "width" "0"
88 | , Html.Attributes.style "height" "0"
89 | , Html.Attributes.style "border-left" <| getBorderAttr 4 "transparent"
90 | , Html.Attributes.style "border-right" <| getBorderAttr 4 "transparent"
91 | , Html.Attributes.style "border-top" <| getBorderAttr 6 (R10.Color.Utils.toCssRgba colorFont)
92 |
93 | -- , Html.Attributes.style "position" "absolute"
94 | -- , Html.Attributes.style "right" "12px"
95 | , Html.Attributes.style "pointer-events" "none"
96 | ]
97 | )
98 | none
99 |
--------------------------------------------------------------------------------
/PUBLISHING.md:
--------------------------------------------------------------------------------
1 | # PUBLISHING
2 |
3 | ## Documentation
4 |
5 | You can verify the documentation of the project running
6 |
7 | ```
8 | elm-doc-preview
9 | ```
10 |
11 | installable with
12 | ```
13 | npm install -g elm-doc-preview
14 | ```
15 |
16 | These are good guidelines to follow while coding and writing documentation:
17 |
18 | * https://package.elm-lang.org/help/design-guidelines
19 | * https://elm-lang.org/docs/style-guide
20 |
21 | ## Dependencies
22 |
23 | You can add or remove dependencies with `elm-json`
24 |
25 | ## Publishing
26 |
27 | **Notes about elm-bump: Read below about the error "I got the data back, but it was not what I was expecting"**
28 |
29 | Run the following to bump && publish the version in elm.json:
30 |
31 | ```
32 | npx -p elm@0.19.0-no-deps elm bump
33 | ```
34 |
35 | or
36 |
37 | ```
38 | elm bump
39 | ```
40 |
41 | ---
42 |
43 | If you get something like this:
44 |
45 | ```
46 | -- PROBLEM LOADING DOCS --------------------------------------------------------
47 |
48 | I need the docs for 12.17.0 to compute the next version number, so I fetched:
49 |
50 | https://package.elm-lang.org/packages/NoRedInk/noredink-ui/12.17.0/docs.json
51 |
52 | I got the data back, but it was not what I was expecting. The response body
53 | contains 195076 bytes. Here is the beginning:
54 |
55 | [{"name":"Nri.Ui","comment":" A collection of helpers for working with No...
56 |
57 | Does this error keep showing up? Maybe there is something weird with your
58 | internet connection. We have gotten reports that schools, businesses, airports,
59 | etc. sometimes intercept requests and add things to the body or change its
60 | contents entirely. Could that be the problem?
61 | ```
62 |
63 | Then run it with 0.19.0 explicitly (0.19.1 has some problems with big docs):
64 |
65 | ```
66 | npx -p elm@0.19.0-no-deps elm bump
67 | ```
68 |
69 | ---
70 |
71 | Commit and push your changes in a PR. Once it's approved and merged, then:
72 |
73 | ```
74 | git tag -a 7.0.0 -m "release version 7.0.0"
75 | git push origin 7.0.0
76 | npx -p elm@0.19.0-no-deps elm publish
77 | ```
78 |
79 | You can also add a tag in https://github.com/rakutentech/r10/releases/new if you want to add more detail.
80 |
81 | Once you've published, you should see the latest version at https://package.elm-lang.org/packages/rakutentech/r10/ or https://elm.dmy.fr/packages/rakutentech/r10/.
82 |
83 | ## Best practices
84 |
85 | Imports should be plain, without aliases and without exposing particular functions. This make the code more clear as it immediately understanding if a resource is defined in the present module or somewhere else. It also makes code block more portable.
86 |
87 | These are the exceptions to this rule:
88 |
89 | import Element exposing (..)
90 | import Element.Background as Background
91 | import Element.Border as Border
92 | import Element.Events as Events
93 | import Element.Font as Font
94 | import Element.Input as Input
95 | import Element.Keyed as Keyed
96 | import Json.Decode as D
97 | import Json.Encode as E
98 | import Svg.Attributes as SA
99 | import Html exposing (..)
100 | import Html.Attributes exposing (..)
101 |
102 | `Html` and `Html.Attributes` can be esposed only if `Element` is not used, otherwise there are conflicts.
103 |
104 | ----
105 |
106 | Modules that are not exposed should have `Internal` somewhere in their path.
107 |
108 | ## How to develop
109 |
110 | For testing or modification to R10 on a local environment, clone R10 (https://github.com/rakutentech/r10) in a sibling folder of projects that use R10, then, in the elm.json file of such project:
111 |
112 | * Remove the dependency from r10 (or run `elm-json uninstall rakutenteck/r10`)
113 | * Add in the list of `"source-directories"` folders: `"../r10/src"`
--------------------------------------------------------------------------------
/src/R10/Alert.elm:
--------------------------------------------------------------------------------
1 | module R10.Alert exposing (Alert(..), view)
2 |
3 | import Element.WithContext exposing (..)
4 | import Element.WithContext.Border as Border
5 | import R10.Color.AttrsBackground
6 | import R10.Color.AttrsFont
7 | import R10.Color.Svg
8 | import R10.Context
9 | import R10.FontSize
10 | import R10.Svg.Icons
11 |
12 |
13 | type Alert
14 | = Danger
15 | | Info
16 | | Warning
17 | | Success
18 |
19 |
20 | view :
21 | Alert
22 | -> List (Attribute (R10.Context.ContextInternal z) msg)
23 | -> List (Element (R10.Context.ContextInternal z) msg)
24 | -> Element (R10.Context.ContextInternal z) msg
25 | view alert attrs listOfElement =
26 | if List.isEmpty listOfElement then
27 | text ""
28 |
29 | else
30 | withContext <|
31 | \c ->
32 | let
33 | ( colorFont, colorBackground, colorIcon ) =
34 | case alert of
35 | Danger ->
36 | ( R10.Color.AttrsFont.fontAlertDanger
37 | , R10.Color.AttrsBackground.backgroundAlertDanger
38 | , R10.Color.Svg.fontAlertDanger c.contextR10.theme
39 | )
40 |
41 | Info ->
42 | ( R10.Color.AttrsFont.fontAlertInfo
43 | , R10.Color.AttrsBackground.backgroundAlertInfo
44 | , R10.Color.Svg.fontAlertInfo c.contextR10.theme
45 | )
46 |
47 | Warning ->
48 | ( R10.Color.AttrsFont.fontAlertWarning
49 | , R10.Color.AttrsBackground.backgroundAlertWarning
50 | , R10.Color.Svg.fontAlertWarning c.contextR10.theme
51 | )
52 |
53 | Success ->
54 | ( R10.Color.AttrsFont.fontAlertSuccess
55 | , R10.Color.AttrsBackground.backgroundAlertSuccess
56 | , R10.Color.Svg.fontAlertSuccess c.contextR10.theme
57 | )
58 | in
59 | column [ spacing 20, width fill ]
60 | (List.map
61 | (\section ->
62 | row
63 | [ colorFont
64 | , colorBackground
65 | , R10.FontSize.small
66 | , Border.rounded 5
67 | , padding 16
68 | , spacing 16
69 | , width fill
70 | ]
71 | [ (case alert of
72 | -- https://dev-cdn.rex.contents.rakuten.co.jp/rex-form/v1.7.0/components/alert.html
73 | Danger ->
74 | R10.Svg.Icons.sign_warning_l
75 |
76 | Info ->
77 | R10.Svg.Icons.sign_info_l
78 |
79 | Warning ->
80 | R10.Svg.Icons.sign_info_l
81 |
82 | Success ->
83 | R10.Svg.Icons.check
84 | )
85 | [ alignTop ]
86 | colorIcon
87 | 16
88 | , paragraph attrs [ section ]
89 | ]
90 | )
91 | listOfElement
92 | )
93 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/ElmGo.elm:
--------------------------------------------------------------------------------
1 | module Starter.ElmGo exposing
2 | ( Compilation(..)
3 | , ElmLiveArgs
4 | , HotReload(..)
5 | , Pushstate(..)
6 | , Reload(..)
7 | , Ssl(..)
8 | , Verbose(..)
9 | , elmGo
10 | , encoder
11 | )
12 |
13 | import Json.Encode
14 |
15 |
16 | type alias ElmLiveArgs =
17 | { dir : String
18 | , outputCompiledJs : String
19 | , indexHtml : String
20 | , port_ : Int
21 | , compilation : Compilation
22 | , verbose : Verbose
23 | , pushstate : Pushstate
24 | , reload : Reload
25 | , hotReload : HotReload
26 | , ssl : Ssl
27 | , elmFileToCompile : String
28 | , dirBin : String
29 | , relative : String
30 | , certificatesFolder : String
31 | }
32 |
33 |
34 | type Compilation
35 | = Optimize
36 | | Normal
37 | | Debug
38 |
39 |
40 | type Reload
41 | = ReloadYes
42 | | ReloadNo
43 |
44 |
45 | type HotReload
46 | = HotReloadYes
47 | | HotReloadNo
48 |
49 |
50 | type Verbose
51 | = VerboseYes
52 | | VerboseNo
53 |
54 |
55 | type Pushstate
56 | = PushstateYes
57 | | PushstateNo
58 |
59 |
60 | type Ssl
61 | = SslYes
62 | | SslNo
63 |
64 |
65 | elmGo : ElmLiveArgs -> { command : String, parameters : List String }
66 | elmGo args =
67 | -- { command = args.dirBin ++ "/elm-go"
68 | { command = "node"
69 | , parameters =
70 | [ "node_modules/.bin/elm-go"
71 |
72 | -- [ "elm-go/bin/elm-go.js"
73 | , args.elmFileToCompile
74 | , "--path-to-elm=" ++ args.dirBin ++ "/elm"
75 | , "--dir=" ++ args.dir
76 | , "--start-page=" ++ args.indexHtml
77 | , "--port=" ++ String.fromInt args.port_
78 | ]
79 | ++ (case args.ssl of
80 | SslYes ->
81 | [ "--ssl"
82 |
83 | -- , "--ssl-cert=" ++ args.certificatesFolder ++ "/localhost.crt"
84 | -- , "--ssl-key=" ++ args.certificatesFolder ++ "/localhost.key"
85 | ]
86 |
87 | SslNo ->
88 | []
89 | )
90 | ++ (case args.pushstate of
91 | PushstateYes ->
92 | [ "--pushstate" ]
93 |
94 | PushstateNo ->
95 | []
96 | )
97 | ++ (case args.verbose of
98 | VerboseYes ->
99 | [ "--verbose" ]
100 |
101 | VerboseNo ->
102 | []
103 | )
104 | ++ (case args.hotReload of
105 | HotReloadYes ->
106 | [ "--hot" ]
107 |
108 | HotReloadNo ->
109 | []
110 | )
111 | ++ (case args.reload of
112 | ReloadYes ->
113 | []
114 |
115 | ReloadNo ->
116 | [ "--no-reload" ]
117 | )
118 | ++ [ "--"
119 | , "--output=" ++ args.outputCompiledJs
120 | ]
121 | ++ (case args.compilation of
122 | Optimize ->
123 | [ "--optimize" ]
124 |
125 | Normal ->
126 | []
127 |
128 | Debug ->
129 | [ "--debug" ]
130 | )
131 | }
132 |
133 |
134 | encoder : { command : String, parameters : List String } -> Json.Encode.Value
135 | encoder args =
136 | Json.Encode.object
137 | [ ( "command", Json.Encode.string args.command )
138 | , ( "parameters", Json.Encode.list Json.Encode.string args.parameters )
139 | ]
140 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 3.0.0 (2021-02-19)
2 |
3 | ## Release Highlights
4 |
5 | * Updates color system, making Element.Color the default color.
6 | * Add single radio row.
7 |
8 | ## Differences
9 |
10 | This is a MAJOR change.
11 |
12 | ---- R10.Color.Svg - MAJOR ----
13 |
14 | Added:
15 | fontHighEmphasis : R10.Theme.Theme -> Element.Color
16 | fontMediumEmphasis : R10.Theme.Theme -> Element.Color
17 |
18 | Removed:
19 | fontNormal : Theme -> Color
20 | logoHex : Theme -> Color
21 | mediumEmphasis : Theme -> Color
22 |
23 |
24 | ---- R10.Color.Utils - MAJOR ----
25 |
26 | Added:
27 | fromColorColor : Color.Color -> Element.Color
28 | fromHexToColorColor : String.String -> Color.Color
29 | toColorColor : Element.Color -> Color.Color
30 | toCssRgba : Element.Color -> String.String
31 |
32 | Removed:
33 | colorToElementColor : Color -> Color
34 | elementColorToColor : Color -> Color
35 | toHex : Color -> String
36 |
37 |
38 | ---- R10.Form - MINOR ----
39 |
40 | Added:
41 | type alias TextArgs msg = R10.FormComponents.Internal.Text.Args msg
42 | textView :
43 | List.List (Element.Attribute msg)
44 | -> List.List (Element.Attribute msg)
45 | -> R10.FormComponents.Internal.Text.Args msg
46 | -> Element.Element msg
47 |
48 |
49 | ---- R10.FormTypes - MAJOR ----
50 |
51 | Changed:
52 | - type TypeSingle = SingleRadio | SingleCombobox | SingleSelect
53 | + type TypeSingle
54 | = SingleRadio
55 | | SingleRadioRow
56 | | SingleCombobox
57 | | SingleSelect
58 |
59 | - inputField :
60 | { binaryCheckbox : FieldType
61 | , binarySwitch : FieldType
62 | , multiCombobox : List FieldOption -> FieldType
63 | , singleCombobox : List FieldOption -> FieldType
64 | , singleSelect : List FieldOption -> FieldType
65 | , singleRadio : List FieldOption -> FieldType
66 | , textEmail : FieldType
67 | , textMultiline : FieldType
68 | , textPasswordCurrent : FieldType
69 | , textPasswordNew : FieldType
70 | , textPlain : FieldType
71 | , textUsername : FieldType
72 | , textWithPattern : String -> FieldType
73 | }
74 | + inputField :
75 | { binaryCheckbox : R10.FormTypes.FieldType
76 | , binarySwitch : R10.FormTypes.FieldType
77 | , multiCombobox :
78 | List.List R10.FormTypes.FieldOption -> R10.FormTypes.FieldType
79 | , singleCombobox :
80 | List.List R10.FormTypes.FieldOption -> R10.FormTypes.FieldType
81 | , singleSelect :
82 | List.List R10.FormTypes.FieldOption -> R10.FormTypes.FieldType
83 | , singleRadio :
84 | List.List R10.FormTypes.FieldOption -> R10.FormTypes.FieldType
85 | , singleRadioRow :
86 | List.List R10.FormTypes.FieldOption -> R10.FormTypes.FieldType
87 | , textEmail : R10.FormTypes.FieldType
88 | , textMultiline : R10.FormTypes.FieldType
89 | , textPasswordCurrent : R10.FormTypes.FieldType
90 | , textPasswordNew : R10.FormTypes.FieldType
91 | , textPlain : R10.FormTypes.FieldType
92 | , textUsername : R10.FormTypes.FieldType
93 | , textWithPattern : String.String -> R10.FormTypes.FieldType
94 | }
95 |
96 |
97 |
98 | ---- R10.Svg.IconsExtra - MINOR ----
99 |
100 | Added:
101 | copy :
102 | List.List (Element.Attribute msg)
103 | -> Element.Color
104 | -> Basics.Int
105 | -> Element.Element msg
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/Phone/Common.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.Phone.Common exposing
2 | ( Args
3 | , FieldOption
4 | , Model
5 | , Msg(..)
6 | , dropdownContainerId
7 | , dropdownContentId
8 | , dropdownSearchBoxId
9 | , filterBySearch
10 | , init
11 | , inputPhoneElementId
12 | , normalizeString
13 | )
14 |
15 | import Element.WithContext exposing (..)
16 | import R10.Context exposing (..)
17 | import R10.Country
18 | import R10.FormComponents.Internal.Single.Common
19 | import R10.FormComponents.Internal.Style
20 | import R10.Palette
21 |
22 |
23 |
24 | -- types
25 |
26 |
27 | type Msg
28 | = NoOp
29 | | OnFocus String
30 | | OnLoseFocus String
31 | | OnScroll Float
32 | | OnEsc String Bool
33 | --
34 | | OnInputClick { key : String, selectedY : Float }
35 | | OnOptionSelect String R10.Country.Country
36 | | OnSearch { key : String, selectOptionHeight : Int, maxDisplayCount : Int, filteredFieldOption : List R10.Country.Country } String
37 | | OnArrowUp { key : String, selectOptionHeight : Int, maxDisplayCount : Int, filteredFieldOption : List R10.Country.Country }
38 | | OnArrowDown { key : String, selectOptionHeight : Int, maxDisplayCount : Int, filteredFieldOption : List R10.Country.Country }
39 | --
40 | | OnValueChange String { selectOptionHeight : Int, maxDisplayCount : Int, filteredFieldOption : List R10.Country.Country } String
41 | | OnSimpleValueChange Bool String
42 |
43 |
44 | init : Model
45 | init =
46 | R10.FormComponents.Internal.Single.Common.init
47 |
48 |
49 | type alias Model =
50 | R10.FormComponents.Internal.Single.Common.Model
51 |
52 |
53 | type alias FieldOption =
54 | R10.FormComponents.Internal.Single.Common.FieldOption
55 |
56 |
57 | type alias Args z msg =
58 | -- Stuff that change
59 | { maybeValid : Maybe Bool
60 |
61 | ---- Messages
62 | , toMsg : Msg -> msg
63 |
64 | -- Stuff that doesn't change
65 | , label : String
66 | , helperText : Maybe String
67 | , disabled : Bool
68 | , requiredLabel : Maybe String
69 | , style : R10.FormComponents.Internal.Style.Style
70 | , key : String
71 | , palette : R10.Palette.Palette
72 | , disabledCountryChange : Bool
73 |
74 | -- Specific
75 | , countryOptions : List R10.Country.Country
76 | , toOptionEl : R10.Country.Country -> Element (R10.Context.ContextInternal z) msg
77 | , selectOptionHeight : Int
78 | , maxDisplayCount : Int
79 | , leadingIcon : List (Element (R10.Context.ContextInternal z) msg)
80 | , trailingIcon : List (Element (R10.Context.ContextInternal z) msg)
81 | }
82 |
83 |
84 | normalizeString : String -> String
85 | normalizeString =
86 | -- use for filtering, search <-> label comparison
87 | String.toLower >> String.trim
88 |
89 |
90 | searchFn : String -> R10.Country.Country -> Bool
91 | searchFn search country =
92 | String.contains
93 | (search |> normalizeString)
94 | (country |> R10.Country.toCountryNameWithAlias |> normalizeString)
95 |
96 |
97 | filterBySearch : String -> List R10.Country.Country -> List R10.Country.Country
98 | filterBySearch search fieldOptions =
99 | if String.isEmpty search then
100 | fieldOptions
101 |
102 | else
103 | fieldOptions
104 | |> List.filter (searchFn search)
105 |
106 |
107 | dropdownContainerId : String -> String
108 | dropdownContainerId key =
109 | "dropdown-container-" ++ key
110 |
111 |
112 | dropdownContentId : String -> String
113 | dropdownContentId key =
114 | "dropdown-content-" ++ key
115 |
116 |
117 | dropdownSearchBoxId : String -> String
118 | dropdownSearchBoxId key =
119 | "dropdown-search-" ++ key
120 |
121 |
122 | inputPhoneElementId : String -> String
123 | inputPhoneElementId key =
124 | "input-phone-" ++ key
125 |
--------------------------------------------------------------------------------
/src/R10/Color.elm:
--------------------------------------------------------------------------------
1 | module R10.Color exposing
2 | ( Base
3 | , Primary, primary, primaryDefault, primaryToString, primaryDecoder, primaryDecoderExploration
4 | , Derived
5 | , listPrimary, listBase, listDerived
6 | , maximumContrast
7 | )
8 |
9 | {-| These lists are just to be used to create documentations, not to actually use colors in the layout.
10 |
11 |
12 | # Base
13 |
14 | Base colors are the only color, together with one primary color, that are used to derive all other colors for the interface.
15 |
16 | They are different depending on the mode:
17 |
18 | 
19 |
20 | @docs Base
21 |
22 |
23 | # Primary
24 |
25 | These represent the brands color of Rakuten.
26 |
27 | Rakuten Brand guideline:
28 |
29 | 
30 |
31 | @docs Primary, primary, primaryDefault, primaryToString, primaryDecoder, primaryDecoderExploration
32 |
33 |
34 | # Derived
35 |
36 | @docs Derived
37 |
38 |
39 | # Lists
40 |
41 | These lists should only be used to generate documentation.
42 |
43 | @docs listPrimary, listBase, listDerived
44 |
45 |
46 | # Utils
47 |
48 | @docs maximumContrast
49 |
50 | -}
51 |
52 | import Color
53 | import Json.Decode
54 | import Json.Decode.Exploration
55 | import R10.Color.Internal.Base
56 | import R10.Color.Internal.Derived
57 | import R10.Color.Internal.Primary
58 | import R10.Theme
59 |
60 |
61 |
62 | -- EXPOSING PRIMARY COLOR STUFF
63 |
64 |
65 | {-| -}
66 | type alias Primary =
67 | R10.Color.Internal.Primary.Color
68 |
69 |
70 | {-| -}
71 | primary :
72 | { crimsonRed : Primary
73 | , red : Primary
74 | , orange : Primary
75 | , yellow : Primary
76 | , green : Primary
77 | , lightBlue : Primary
78 | , blue : Primary
79 | , blueSky : Primary
80 | , purple : Primary
81 | , pink : Primary
82 | }
83 | primary =
84 | { yellow = R10.Color.Internal.Primary.Yellow
85 | , purple = R10.Color.Internal.Primary.Purple
86 | , pink = R10.Color.Internal.Primary.Pink
87 | , orange = R10.Color.Internal.Primary.Orange
88 | , lightBlue = R10.Color.Internal.Primary.LightBlue
89 | , green = R10.Color.Internal.Primary.Green
90 | , crimsonRed = R10.Color.Internal.Primary.CrimsonRed
91 | , red = R10.Color.Internal.Primary.CrimsonRed
92 | , blue = R10.Color.Internal.Primary.Blue
93 | , blueSky = R10.Color.Internal.Primary.BlueSky
94 | }
95 |
96 |
97 | {-| -}
98 | primaryDecoder : Json.Decode.Decoder Primary
99 | primaryDecoder =
100 | R10.Color.Internal.Primary.decoder
101 |
102 |
103 | {-| -}
104 | primaryDecoderExploration : Json.Decode.Exploration.Decoder Primary
105 | primaryDecoderExploration =
106 | R10.Color.Internal.Primary.decoderExploration
107 |
108 |
109 | {-| -}
110 | primaryToString : Primary -> String
111 | primaryToString =
112 | R10.Color.Internal.Primary.toString
113 |
114 |
115 | {-| -}
116 | primaryDefault : Primary
117 | primaryDefault =
118 | R10.Color.Internal.Primary.default
119 |
120 |
121 |
122 | -- EXPOSING BASE COLOR STUFF
123 |
124 |
125 | {-| -}
126 | type alias Base =
127 | R10.Color.Internal.Base.Color
128 |
129 |
130 |
131 | -- EXPOSING DERIVED COLOR STUFF
132 |
133 |
134 | {-| -}
135 | type alias Derived =
136 | R10.Color.Internal.Derived.Color
137 |
138 |
139 |
140 | -- LISTS
141 |
142 |
143 | {-| -}
144 | listPrimary : R10.Theme.Theme -> List { color : Color.Color, name : String, description : String, type_ : Primary }
145 | listPrimary =
146 | R10.Color.Internal.Primary.list
147 |
148 |
149 | {-| -}
150 | listBase : R10.Theme.Theme -> List { color : Color.Color, name : String }
151 | listBase theme =
152 | R10.Color.Internal.Base.list theme
153 |
154 |
155 | {-| -}
156 | listDerived : R10.Theme.Theme -> List { color : Color.Color, name : String, description : String }
157 | listDerived theme =
158 | R10.Color.Internal.Derived.list theme
159 |
160 |
161 | {-| A sligtly modified version of `Color.Accessibility.maximumContrast`
162 | -}
163 | maximumContrast : Color.Color -> List Color.Color -> Maybe Color.Color
164 | maximumContrast =
165 | R10.Color.Internal.Derived.maximumContrast
166 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/Msg.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.Msg exposing
2 | ( Msg(..)
3 | , handleChangesSinceLastSubmissions
4 | , isChangingValues
5 | , isSubmitted
6 | , onLoseFocus
7 | , onOptionSelect
8 | , onValueChange
9 | , toValue
10 | )
11 |
12 | import R10.Context
13 | import R10.Form.Internal.Conf
14 | import R10.Form.Internal.FieldConf
15 | import R10.Form.Internal.Key
16 | import R10.FormComponents.Internal.Phone.Common
17 | import R10.FormComponents.Internal.Single.Common
18 |
19 |
20 | toValue : Msg -> Maybe String
21 | toValue msg =
22 | case msg of
23 | ChangeValue _ _ _ _ string ->
24 | Just string
25 |
26 | _ ->
27 | Nothing
28 |
29 |
30 | {-| -}
31 | type Msg
32 | = NoOp
33 | | GetFocus R10.Form.Internal.Key.Key R10.Form.Internal.FieldConf.FieldConf
34 | | LoseFocus R10.Form.Internal.Key.Key R10.Form.Internal.FieldConf.FieldConf
35 | | Hover R10.Form.Internal.Key.Key (Maybe String)
36 | | TogglePasswordShow R10.Form.Internal.Key.Key
37 | | KeyDown Int
38 | | ChangeValue R10.Form.Internal.Key.Key R10.Form.Internal.FieldConf.FieldConf R10.Form.Internal.Conf.Conf R10.Context.ContextR10 String
39 | | ChangeTab R10.Form.Internal.Key.Key String
40 | | AddEntity R10.Form.Internal.Key.Key
41 | | RemoveEntity R10.Form.Internal.Key.Key
42 | | Submit R10.Form.Internal.Conf.Conf
43 | -- SUB COMPONENTS
44 | | OnSingleMsg R10.Form.Internal.Key.Key R10.Form.Internal.FieldConf.FieldConf R10.Form.Internal.Conf.Conf R10.FormComponents.Internal.Single.Common.Msg
45 | | OnPhoneMsg R10.Form.Internal.Key.Key R10.Form.Internal.FieldConf.FieldConf R10.Form.Internal.Conf.Conf R10.FormComponents.Internal.Phone.Common.Msg
46 |
47 |
48 | {-| -}
49 | isSubmitted : Msg -> Bool
50 | isSubmitted msgState =
51 | case msgState of
52 | Submit _ ->
53 | True
54 |
55 | _ ->
56 | False
57 |
58 |
59 | {-| -}
60 | handleChangesSinceLastSubmissions : Bool -> Msg -> Bool
61 | handleChangesSinceLastSubmissions changesSinceLastSubmissions msg =
62 | case msg of
63 | Submit _ ->
64 | -- We reset the value
65 | False
66 |
67 | _ ->
68 | if isChangingValues msg then
69 | True
70 |
71 | else
72 | changesSinceLastSubmissions
73 |
74 |
75 | {-| Return true if the message can potentially change some value
76 | -}
77 | isChangingValues : Msg -> Bool
78 | isChangingValues msg =
79 | case msg of
80 | ChangeValue _ _ _ _ _ ->
81 | True
82 |
83 | AddEntity _ ->
84 | True
85 |
86 | RemoveEntity _ ->
87 | True
88 |
89 | _ ->
90 | False
91 |
92 |
93 | onLoseFocus :
94 | (R10.Form.Internal.Key.Key
95 | -> R10.Form.Internal.FieldConf.FieldConf
96 | -> any
97 | )
98 | -> Msg
99 | -> Maybe any
100 | onLoseFocus func msg_ =
101 | case msg_ of
102 | LoseFocus key conf ->
103 | Just (func key conf)
104 |
105 | _ ->
106 | Nothing
107 |
108 |
109 | onValueChange :
110 | (R10.Form.Internal.Key.Key
111 | -> R10.Form.Internal.FieldConf.FieldConf
112 | -> R10.Form.Internal.Conf.Conf
113 | -> String
114 | -> any
115 | )
116 | -> Msg
117 | -> Maybe any
118 | onValueChange func msg_ =
119 | case msg_ of
120 | ChangeValue key fieldConf formConf _ value ->
121 | Just (func key fieldConf formConf value)
122 |
123 | _ ->
124 | Nothing
125 |
126 |
127 | onOptionSelect :
128 | (R10.Form.Internal.Key.Key
129 | -> R10.Form.Internal.FieldConf.FieldConf
130 | -> R10.Form.Internal.Conf.Conf
131 | -> String
132 | -> any
133 | )
134 | -> Msg
135 | -> Maybe any
136 | onOptionSelect func msg_ =
137 | case msg_ of
138 | OnSingleMsg key fieldConf formConf singleMsg ->
139 | case singleMsg of
140 | R10.FormComponents.Internal.Single.Common.OnOptionSelect option ->
141 | Just (func key fieldConf formConf option)
142 |
143 | _ ->
144 | Nothing
145 |
146 | _ ->
147 | Nothing
148 |
--------------------------------------------------------------------------------
/src/R10/Table/Internal/Placeholder.elm:
--------------------------------------------------------------------------------
1 | module R10.Table.Internal.Placeholder exposing (placeholderSvg, view)
2 |
3 | import Element.WithContext exposing (..)
4 | import Element.WithContext.Border as Border
5 | import R10.Context exposing (..)
6 | import Svg
7 | import Svg.Attributes as SA
8 |
9 |
10 | toRadix : Int -> String
11 | toRadix n =
12 | -- Internal Utils for getting radix number
13 | let
14 | getChr c =
15 | if c < 10 then
16 | String.fromInt c
17 |
18 | else
19 | String.fromChar <| Char.fromCode (87 + c)
20 |
21 | result =
22 | if n < 16 then
23 | getChr n
24 |
25 | else
26 | toRadix (n // 16) ++ getChr (remainderBy 16 n)
27 | in
28 | result
29 |
30 |
31 | toHex : Color -> String
32 | toHex color =
33 | let
34 | { red, green, blue } =
35 | toRgb color
36 | in
37 | [ red * 255, green * 255, blue * 255 ]
38 | |> List.map ceiling
39 | |> List.map (toRadix >> String.padLeft 2 '0')
40 | |> (::) "#"
41 | |> String.join ""
42 |
43 |
44 | placeholderSvg : Color -> Element (R10.Context.ContextInternal z) msg
45 | placeholderSvg color =
46 | let
47 | stringColor =
48 | toHex color
49 |
50 | fillId =
51 | "fill" ++ stringColor
52 |
53 | speed =
54 | "2s"
55 | in
56 | Element.WithContext.html <|
57 | Svg.svg
58 | [ SA.xmlSpace "http://www.w3.org/2000/svg"
59 | , SA.width "auto"
60 | , SA.height "auto"
61 | ]
62 | [ Svg.rect
63 | [ SA.fill "none"
64 | , SA.x "0"
65 | , SA.y "0"
66 | , SA.width "100%"
67 | , SA.height "100%"
68 | , SA.style <| "fill: url(#" ++ fillId ++ ");"
69 | ]
70 | []
71 | , Svg.defs []
72 | [ Svg.linearGradient
73 | [ SA.id fillId ]
74 | [ Svg.stop
75 | [ SA.offset "0.599964"
76 | , SA.stopColor stringColor
77 | , SA.stopOpacity "0.7"
78 | ]
79 | [ Svg.animate
80 | [ SA.attributeName "offset"
81 | , SA.values "-2; -2; 1"
82 | , SA.keyTimes "0; 0.25; 1"
83 | , SA.dur speed
84 | , SA.repeatCount "indefinite"
85 | ]
86 | []
87 | ]
88 | , Svg.stop
89 | [ SA.offset "1.59996"
90 | , SA.stopColor stringColor
91 | , SA.stopOpacity "1"
92 | ]
93 | [ Svg.animate
94 | [ SA.attributeName "offset"
95 | , SA.values "-1; -1; 2"
96 | , SA.keyTimes "0; 0.25; 1"
97 | , SA.dur speed
98 | , SA.repeatCount "indefinite"
99 | ]
100 | []
101 | ]
102 | , Svg.stop
103 | [ SA.offset "2.59996"
104 | , SA.stopColor stringColor
105 | , SA.stopOpacity "0.7"
106 | ]
107 | [ Svg.animate
108 | [ SA.attributeName "offset"
109 | , SA.values "0; 0; 3"
110 | , SA.keyTimes "0; 0.25; 1"
111 | , SA.dur speed
112 | , SA.repeatCount "indefinite"
113 | ]
114 | []
115 | ]
116 | ]
117 | ]
118 | ]
119 |
120 |
121 | view : Color -> List (Attribute (R10.Context.ContextInternal z) msg) -> Element (R10.Context.ContextInternal z) msg
122 | view color attrs =
123 | el ([ width fill, height <| px 16, Border.rounded 4, clip, alpha 0.6 ] ++ attrs) <|
124 | (placeholderSvg <| color)
125 |
--------------------------------------------------------------------------------
/examples/pwa/src/Pages/Form_Entities.elm:
--------------------------------------------------------------------------------
1 | module Pages.Form_Entities exposing
2 | ( Model
3 | , Msg
4 | , init
5 | , update
6 | , view
7 | )
8 |
9 | import Element exposing (..)
10 | import Element.Background as Background
11 | import Element.Border as Border
12 | import Html.Attributes
13 | import Markdown
14 | import R10.Form
15 | import R10.FormTypes
16 | import R10.Paragraph
17 | import R10.Theme
18 |
19 |
20 | type alias Model =
21 | { formState : R10.Form.State }
22 |
23 |
24 | init : Model
25 | init =
26 | { formState = R10.Form.initState }
27 |
28 |
29 | type Msg
30 | = FormMsg R10.Form.Msg
31 |
32 |
33 | update : Msg -> Model -> Model
34 | update msg model =
35 | case msg of
36 | FormMsg formMsg ->
37 | let
38 | ( newFormState, _ ) =
39 | R10.Form.update formMsg model.formState
40 | in
41 | { model | formState = newFormState }
42 |
43 |
44 |
45 | --
46 |
47 |
48 | inputFieldConf : Int -> R10.Form.Entity
49 | inputFieldConf id =
50 | R10.Form.entity.field
51 | { id = "text" ++ String.fromInt id
52 | , idDom = Nothing
53 | , type_ = R10.FormTypes.inputField.textPlain
54 | , label = "Text " ++ String.fromInt id
55 | , helperText = Nothing
56 | , requiredLabel = Nothing
57 | , validationSpecs = Nothing
58 | }
59 |
60 |
61 | entities : List R10.Form.Entity
62 | entities =
63 | [ inputFieldConf 1, inputFieldConf 2, inputFieldConf 3 ]
64 |
65 |
66 | entitiesForTabs : List ( String, R10.Form.Entity )
67 | entitiesForTabs =
68 | [ ( "Tab 1", inputFieldConf 1 ), ( "Tab 2", inputFieldConf 2 ), ( "Tab 3", inputFieldConf 3 ) ]
69 |
70 |
71 | helperForTitles : { helperText : Maybe a1, title : String, validationSpecs : Maybe a }
72 | helperForTitles =
73 | { title = "Title", helperText = Nothing, validationSpecs = Nothing }
74 |
75 |
76 | section : String -> R10.Form.Form -> R10.Theme.Theme -> List (Element Msg)
77 | section entityAsString form theme =
78 | [ R10.Paragraph.xlarge [ Background.color <| rgba 1 1 0 0.5, padding 5 ] [ text entityAsString ]
79 | , row [ Border.width 5, Border.color <| rgba 0.95 0.95 0 1 ] <| R10.Form.viewWithTheme form FormMsg theme
80 | , row [ Border.width 5, Border.color <| rgba 0.95 0.95 0 1, width fill ] <| R10.Form.viewWithTheme form FormMsg theme
81 | ]
82 |
83 |
84 | view : Model -> R10.Theme.Theme -> List (Element Msg)
85 | view model theme =
86 | let
87 | state : R10.Form.State
88 | state =
89 | model.formState
90 | in
91 | --
92 | -- Look at R10.FormComponents.Text.view line 385
93 | --
94 | []
95 | ++ [ paragraph [] [ html <| Markdown.toHtml [ Html.Attributes.class "markdown" ] """**Entities** are the constituent of the form configuration.
96 |
97 | Each **entity** can represent an input field, a title, a sub-title or a list of other entities.
98 |
99 | As list of other entities is used to represent some grouping. For example to add a border around certain number of input field that are somehow related.
100 |
101 | There are 8 types of entity:
102 |
103 | 1. R10.Form.entity.field
104 | 2. R10.Form.entity.normal
105 | 3. R10.Form.entity.wrappable
106 | 4. R10.Form.entity.withBorder
107 | 5. R10.Form.entity.withTabs
108 | 6. R10.Form.entity.multi
109 | 7. R10.Form.entity.title
110 | 8. R10.Form.entity.subTitle""" ] ]
111 | ++ section "R10.Form.entity.field" { conf = entities, state = state } theme
112 | ++ section "R10.Form.entity.normal" { conf = [ R10.Form.entity.normal "normal" entities ], state = state } theme
113 | ++ section "R10.Form.entity.wrappable" { conf = [ R10.Form.entity.wrappable "wrappable" entities ], state = state } theme
114 | ++ section "R10.Form.entity.withBorder" { conf = [ R10.Form.entity.withBorder "withBorder" entities ], state = state } theme
115 | ++ section "R10.Form.entity.withTabs" { conf = [ R10.Form.entity.withTabs "withTabs" entitiesForTabs ], state = state } theme
116 | ++ section "R10.Form.entity.multi" { conf = [ R10.Form.entity.multi "multi" entities ], state = state } theme
117 | ++ section "R10.Form.entity.title" { conf = [ R10.Form.entity.title "title" helperForTitles ], state = state } theme
118 | ++ section "R10.Form.entity.subTitle" { conf = [ R10.Form.entity.subTitle "subTitle" helperForTitles ], state = state } theme
119 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thank you for considering contributing to R10!
4 |
5 | When contributing to this repository, please first discuss the change you wish to make via issue,
6 | email, or any other method with the owners of this repository before making a change.
7 |
8 | Please note we have a code of conduct, please follow it in all your interactions with the project.
9 |
10 | ## Pull Request Process
11 |
12 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a
13 | build.
14 | 2. Update the README.md with details of changes to the interface, this includes new environment
15 | variables, exposed ports, useful file locations and container parameters.
16 | 3. Increase the version numbers in any examples files and the README.md to the new version that this
17 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/) and
18 | it is enforced by the Elm Semantic Versioning system.
19 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
20 | do not have permission to do that, you may request the second reviewer to merge it for you.
21 |
22 | ## Code of Conduct
23 |
24 | ### Our Pledge
25 |
26 | In the interest of fostering an open and welcoming environment, we as
27 | contributors and maintainers pledge to making participation in our project and
28 | our community a harassment-free experience for everyone, regardless of age, body
29 | size, disability, ethnicity, gender identity and expression, level of experience,
30 | nationality, personal appearance, race, religion, or sexual identity and
31 | orientation.
32 |
33 | ### Our Standards
34 |
35 | Examples of behavior that contributes to creating a positive environment
36 | include:
37 |
38 | * Using welcoming and inclusive language
39 | * Being respectful of differing viewpoints and experiences
40 | * Gracefully accepting constructive criticism
41 | * Focusing on what is best for the community
42 | * Showing empathy towards other community members
43 |
44 | Examples of unacceptable behavior by participants include:
45 |
46 | * The use of sexualized language or imagery and unwelcome sexual attention or
47 | advances
48 | * Trolling, insulting/derogatory comments, and personal or political attacks
49 | * Public or private harassment
50 | * Publishing others' private information, such as a physical or electronic
51 | address, without explicit permission
52 | * Other conduct which could reasonably be considered inappropriate in a
53 | professional setting
54 |
55 | ### Our Responsibilities
56 |
57 | Project maintainers are responsible for clarifying the standards of acceptable
58 | behavior and are expected to take appropriate and fair corrective action in
59 | response to any instances of unacceptable behavior.
60 |
61 | Project maintainers have the right and responsibility to remove, edit, or
62 | reject comments, commits, code, wiki edits, issues, and other contributions
63 | that are not aligned to this Code of Conduct, or to ban temporarily or
64 | permanently any contributor for other behaviors that they deem inappropriate,
65 | threatening, offensive, or harmful.
66 |
67 | ### Scope
68 |
69 | This Code of Conduct applies both within project spaces and in public spaces
70 | when an individual is representing the project or its community. Examples of
71 | representing a project or community include using an official project e-mail
72 | address, posting via an official social media account, or acting as an appointed
73 | representative at an online or offline event. Representation of a project may be
74 | further defined and clarified by project maintainers.
75 |
76 | ### Enforcement
77 |
78 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
79 | reported by contacting the project team. All
80 | complaints will be reviewed and investigated and will result in a response that
81 | is deemed necessary and appropriate to the circumstances. The project team is
82 | obligated to maintain confidentiality with regard to the reporter of an incident.
83 | Further details of specific enforcement policies may be posted separately.
84 |
85 | Project maintainers who do not follow or enforce the Code of Conduct in good
86 | faith may face temporary or permanent repercussions as determined by other
87 | members of the project's leadership.
88 |
89 | ### Attribution
90 |
91 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
92 | available at [http://contributor-covenant.org/version/1/4][version]
93 |
94 | [homepage]: http://contributor-covenant.org
95 | [version]: http://contributor-covenant.org/version/1/4/
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/Single/Common.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.Single.Common exposing
2 | ( Args
3 | , FieldOption
4 | , Model
5 | , Msg(..)
6 | , dropdownContainerId
7 | , dropdownContentId
8 | , filterBySearch
9 | , getSelectedOrFirst
10 | , init
11 | , singleSearchBoxId
12 | )
13 |
14 | import Element.WithContext exposing (..)
15 | import R10.Context exposing (..)
16 | import R10.FormComponents.Internal.Style
17 | import R10.FormTypes
18 | import R10.Palette
19 |
20 |
21 |
22 | -- types
23 |
24 |
25 | type Msg
26 | = NoOp
27 | | Hover (Maybe String)
28 | | OnFocus
29 | | OnLoseFocus String
30 | | OnScroll Float
31 | | OnEsc
32 | --
33 | | OnInputClick { key : String, selectedY : Float }
34 | | OnOptionSelect String
35 | | OnSearch { key : String, selectOptionHeight : Int, maxDisplayCount : Int, filteredFieldOption : List FieldOption } String
36 | | OnArrowUp { key : String, selectOptionHeight : Int, maxDisplayCount : Int, filteredFieldOption : List FieldOption }
37 | | OnArrowDown { key : String, selectOptionHeight : Int, maxDisplayCount : Int, filteredFieldOption : List FieldOption }
38 | --
39 | | OnDelBackspace
40 |
41 |
42 | init : Model
43 | init =
44 | { value = ""
45 | , search = ""
46 | , focused = False
47 | , scroll = 0
48 | , opened = False
49 | , select = ""
50 | , over = Nothing
51 | }
52 |
53 |
54 | type alias Model =
55 | { value : String
56 | , search : String
57 | , focused : Bool
58 | , scroll : Float
59 | , opened : Bool
60 | , select : String
61 | , over : Maybe String
62 | }
63 |
64 |
65 | type alias FieldOption =
66 | { value : String
67 | , label : String
68 | }
69 |
70 |
71 | type alias Args z msg =
72 | { ---- Messages
73 | toMsg : Msg -> msg
74 |
75 | -- Stuff that doesn't change
76 | , label : String
77 | , helperText : Maybe String
78 | , disabled : Bool
79 | , maybeValid : Maybe Bool
80 | , requiredLabel : Maybe String
81 | , style : R10.FormComponents.Internal.Style.Style
82 | , key : String
83 | , palette : R10.Palette.Palette
84 | , searchable : Bool
85 | , autocomplete : Maybe String
86 |
87 | -- Specific
88 | , singleType : R10.FormTypes.TypeSingle
89 | , fieldOptions : List FieldOption
90 | , viewOptionEl : FieldOption -> Element (R10.Context.ContextInternal z) msg
91 | , searchFn : String -> FieldOption -> Bool
92 | , selectOptionHeight : Int
93 | , maxDisplayCount : Int
94 | , leadingIcon : List (Element (R10.Context.ContextInternal z) msg)
95 | , trailingIcon : List (Element (R10.Context.ContextInternal z) msg)
96 | }
97 |
98 |
99 | isAnyOptionValueMatched : { a | value : String, fieldOptions : List FieldOption } -> Bool
100 | isAnyOptionValueMatched { value, fieldOptions } =
101 | List.any (\option -> option.value == value) fieldOptions
102 |
103 |
104 | isAnyOptionLabelMatched : { a | value : String, fieldOptions : List FieldOption } -> Bool
105 | isAnyOptionLabelMatched { value, fieldOptions } =
106 | List.any (\option -> option.label == value) fieldOptions
107 |
108 |
109 | getSelectedOrFirst : List FieldOption -> String -> String -> String
110 | getSelectedOrFirst fieldOptions value select =
111 | if not <| String.isEmpty select then
112 | select
113 |
114 | else if isAnyOptionValueMatched { value = value, fieldOptions = fieldOptions } then
115 | value
116 |
117 | else
118 | List.head fieldOptions
119 | |> Maybe.map .value
120 | |> Maybe.withDefault ""
121 |
122 |
123 | filterBySearch :
124 | String
125 | ->
126 | { a
127 | | searchFn : String -> FieldOption -> Bool
128 | , fieldOptions : List FieldOption
129 | }
130 | -> List FieldOption
131 | filterBySearch search { searchFn, fieldOptions } =
132 | if
133 | String.isEmpty search
134 | || isAnyOptionLabelMatched { value = search, fieldOptions = fieldOptions }
135 | then
136 | fieldOptions
137 |
138 | else
139 | fieldOptions
140 | |> List.filter (searchFn search)
141 |
142 |
143 | dropdownContainerId : String -> String
144 | dropdownContainerId key =
145 | "single-dropdown-container-" ++ key
146 |
147 |
148 | dropdownContentId : String -> String
149 | dropdownContentId key =
150 | "single-dropdown-content-" ++ key
151 |
152 |
153 | singleSearchBoxId : String -> String
154 | singleSearchBoxId key =
155 | "single-dropdown-search-" ++ key
156 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/MakerForValidationKeys.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.MakerForValidationKeys exposing (Outcome, maker)
2 |
3 | import R10.Form.Internal.Conf
4 | import R10.Form.Internal.Dict
5 | import R10.Form.Internal.FieldConf
6 | import R10.Form.Internal.Key
7 | import R10.Form.Internal.Shared
8 | import R10.FormTypes
9 | import Set
10 |
11 |
12 |
13 | -- ██████ ██ ██ ████████ ██████ ██████ ███ ███ ███████
14 | -- ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██
15 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ █████
16 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
17 | -- ██████ ██████ ██ ██████ ██████ ██ ██ ███████
18 |
19 |
20 | type alias Outcome =
21 | ( R10.Form.Internal.Key.Key, R10.FormTypes.FieldType, Maybe R10.Form.Internal.FieldConf.ValidationSpecs )
22 |
23 |
24 |
25 | -- ██ ██ ███████ ██ ██████ ███████ ██████ ███████
26 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
27 | -- ███████ █████ ██ ██████ █████ ██████ ███████
28 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██
29 | -- ██ ██ ███████ ███████ ██ ███████ ██ ██ ███████
30 |
31 |
32 | viewEntityMulti :
33 | R10.Form.Internal.Key.Key
34 | -> R10.Form.Internal.Shared.Form
35 | -> List Outcome
36 | viewEntityMulti key form =
37 | let
38 | quantity : Int
39 | quantity =
40 | Maybe.withDefault 1 <| R10.Form.Internal.Dict.get key form.state.multiplicableQuantities
41 | in
42 | List.concat <|
43 | List.indexedMap
44 | (\index _ ->
45 | let
46 | newKey : R10.Form.Internal.Key.Key
47 | newKey =
48 | R10.Form.Internal.Key.composeKey key (String.fromInt index)
49 |
50 | removed : Bool
51 | removed =
52 | Set.member (R10.Form.Internal.Key.toString newKey) form.state.removed
53 | in
54 | if removed then
55 | []
56 |
57 | else
58 | maker newKey form
59 | )
60 | (List.repeat quantity ())
61 |
62 |
63 |
64 | -- ███ ███ █████ ██ ██ ███████ ██████
65 | -- ████ ████ ██ ██ ██ ██ ██ ██ ██
66 | -- ██ ████ ██ ███████ █████ █████ ██████
67 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
68 | -- ██ ██ ██ ██ ██ ██ ███████ ██ ██
69 |
70 |
71 | maker :
72 | R10.Form.Internal.Key.Key
73 | -> R10.Form.Internal.Shared.Form
74 | -> List Outcome
75 | maker key form =
76 | --
77 | -- This is recursive
78 | --
79 | -- ┌─────> maker >─────┐
80 | -- │ │
81 | -- └───────────────────┘
82 | --
83 | List.concat <|
84 | List.map
85 | (\entity ->
86 | case entity of
87 | R10.Form.Internal.Conf.EntityWrappable id entities ->
88 | maker (R10.Form.Internal.Key.composeKey key id) { conf = entities, state = form.state }
89 |
90 | R10.Form.Internal.Conf.EntityWithBorder id entities ->
91 | maker (R10.Form.Internal.Key.composeKey key id) { conf = entities, state = form.state }
92 |
93 | R10.Form.Internal.Conf.EntityNormal id entities ->
94 | maker (R10.Form.Internal.Key.composeKey key id) { conf = entities, state = form.state }
95 |
96 | R10.Form.Internal.Conf.EntityWithTabs id titleEntityList ->
97 | maker (R10.Form.Internal.Key.composeKey key id) { conf = titleEntityList |> List.map Tuple.second, state = form.state }
98 |
99 | R10.Form.Internal.Conf.EntityMulti entityId entities ->
100 | viewEntityMulti (R10.Form.Internal.Key.composeKey key entityId) { conf = entities, state = form.state }
101 |
102 | R10.Form.Internal.Conf.EntityField fieldConf ->
103 | [ ( R10.Form.Internal.Key.composeKey key fieldConf.id, fieldConf.type_, fieldConf.validationSpecs ) ]
104 |
105 | R10.Form.Internal.Conf.EntityTitle entityId textConf ->
106 | [ ( R10.Form.Internal.Key.composeKey key entityId, R10.FormTypes.TypeText R10.FormTypes.TextPlain, textConf.validationSpecs ) ]
107 |
108 | R10.Form.Internal.Conf.EntitySubTitle entityId textConf ->
109 | [ ( R10.Form.Internal.Key.composeKey key entityId, R10.FormTypes.TypeText R10.FormTypes.TextPlain, textConf.validationSpecs ) ]
110 | )
111 | form.conf
112 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/State.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.State exposing
2 | ( State
3 | , encoder
4 | , fromString
5 | , init
6 | , toString
7 | )
8 |
9 | import Dict
10 | import Json.Decode as D
11 | import Json.Decode.Extra
12 | import Json.Decode.Pipeline
13 | import Json.Encode as E
14 | import Json.Encode.Extra
15 | import R10.Form.Internal.FieldState
16 | import R10.Form.Internal.Key
17 | import R10.Form.Internal.QtySubmitAttempted
18 | import Set
19 |
20 |
21 |
22 | -- ████████ ██ ██ ██████ ███████ ███████
23 | -- ██ ██ ██ ██ ██ ██ ██
24 | -- ██ ████ ██████ █████ ███████
25 | -- ██ ██ ██ ██ ██
26 | -- ██ ██ ██ ███████ ███████
27 | --
28 |
29 |
30 | type alias State =
31 | { fieldsState : Dict.Dict R10.Form.Internal.Key.KeyAsString R10.Form.Internal.FieldState.FieldState
32 | , multiplicableQuantities : Dict.Dict R10.Form.Internal.Key.KeyAsString Int
33 | , activeTabs : Dict.Dict R10.Form.Internal.Key.KeyAsString String
34 | , focused : Maybe R10.Form.Internal.Key.KeyAsString
35 | , active : Maybe R10.Form.Internal.Key.KeyAsString
36 | , removed : Set.Set R10.Form.Internal.Key.KeyAsString
37 | , qtySubmitAttempted : R10.Form.Internal.QtySubmitAttempted.QtySubmitAttempted
38 | , changesSinceLastSubmissions : Bool
39 | , lastKeyDownIsProcess : Bool
40 | }
41 |
42 |
43 |
44 | -- ██ ███ ██ ██ ████████
45 | -- ██ ████ ██ ██ ██
46 | -- ██ ██ ██ ██ ██ ██
47 | -- ██ ██ ██ ██ ██ ██
48 | -- ██ ██ ████ ██ ██
49 |
50 |
51 | init : State
52 | init =
53 | { fieldsState = Dict.empty
54 | , multiplicableQuantities = Dict.empty
55 | , activeTabs = Dict.empty
56 | , focused = Nothing
57 | , active = Nothing
58 | , removed = Set.empty
59 | , qtySubmitAttempted = R10.Form.Internal.QtySubmitAttempted.fromInt 0
60 | , changesSinceLastSubmissions = False
61 | , lastKeyDownIsProcess = False
62 | }
63 |
64 |
65 |
66 | --
67 | -- ███████ ███ ██ ██████ ██████ ██████ ███████ ██████
68 | -- ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██
69 | -- █████ ██ ██ ██ ██ ██ ██ ██ ██ █████ ██████
70 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
71 | -- ███████ ██ ████ ██████ ██████ ██████ ███████ ██ ██
72 | --
73 | -- ██████ ███████ ██████ ██████ ██████ ███████ ██████
74 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
75 | -- ██ ██ █████ ██ ██ ██ ██ ██ █████ ██████
76 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
77 | -- ██████ ███████ ██████ ██████ ██████ ███████ ██ ██
78 |
79 |
80 | encoder : State -> E.Value
81 | encoder v =
82 | E.object
83 | [ ( "fieldsState", R10.Form.Internal.FieldState.encoderFieldState v.fieldsState )
84 | , ( "multiplicableQuantities", E.dict identity E.int v.multiplicableQuantities )
85 | , ( "activeTabs", E.dict identity E.string v.activeTabs )
86 | , ( "focused", Json.Encode.Extra.maybe E.string v.focused )
87 |
88 | -- We don't want to save active state since it can cause incorrect render on load
89 | , ( "active", Json.Encode.Extra.maybe E.string Nothing )
90 | , ( "removed", E.list E.string (Set.toList v.removed) )
91 | , ( "qtySubmitAttempted", E.int (R10.Form.Internal.QtySubmitAttempted.toInt v.qtySubmitAttempted) )
92 | , ( "changesSinceLastSubmissions", E.bool v.changesSinceLastSubmissions )
93 | , ( "lastKeyDownIsProcess", E.bool v.lastKeyDownIsProcess )
94 | ]
95 |
96 |
97 | decoder : D.Decoder State
98 | decoder =
99 | D.succeed State
100 | |> Json.Decode.Pipeline.required "fieldsState" R10.Form.Internal.FieldState.decoderFieldState
101 | |> Json.Decode.Pipeline.required "multiplicableQuantities" (D.dict D.int)
102 | |> Json.Decode.Pipeline.required "activeTabs" (D.dict D.string)
103 | |> Json.Decode.Pipeline.required "focused" (D.nullable D.string)
104 | |> Json.Decode.Pipeline.required "active" (D.nullable D.string)
105 | |> Json.Decode.Pipeline.required "removed" (Json.Decode.Extra.set D.string)
106 | |> Json.Decode.Pipeline.required "qtySubmitAttempted" (D.map R10.Form.Internal.QtySubmitAttempted.fromInt D.int)
107 | |> Json.Decode.Pipeline.required "changesSinceLastSubmissions" D.bool
108 | |> Json.Decode.Pipeline.required "lastKeyDownIsProcess" D.bool
109 |
110 |
111 | toString : State -> String
112 | toString v =
113 | E.encode 4 <| encoder v
114 |
115 |
116 | fromString : String -> Result D.Error State
117 | fromString string =
118 | D.decodeString decoder string
119 |
--------------------------------------------------------------------------------
/src/R10/FormDebug.elm:
--------------------------------------------------------------------------------
1 | module R10.FormDebug exposing (textTypeMetaData, binaryTypeMetaData, singleTypeMetaData)
2 |
3 | {-| Only used for form debugging
4 |
5 | @docs textTypeMetaData, binaryTypeMetaData, singleTypeMetaData
6 |
7 | -}
8 |
9 | import R10.FormTypes
10 |
11 |
12 | {-| -}
13 | textTypeMetaData :
14 | R10.FormTypes.TypeText
15 | -> { next : R10.FormTypes.TypeText, string : String }
16 | textTypeMetaData textType =
17 | case textType of
18 | R10.FormTypes.TextPasswordNew _ ->
19 | { string = "R10.FormTypes.TextPasswordNew"
20 | , next = R10.FormTypes.TextPasswordCurrent ""
21 | }
22 |
23 | R10.FormTypes.TextPasswordCurrent _ ->
24 | { string = "R10.FormTypes.TextPasswordCurrent"
25 | , next = R10.FormTypes.TextPlain
26 | }
27 |
28 | R10.FormTypes.TextPlain ->
29 | { string = "R10.FormTypes.TextPlain"
30 | , next = R10.FormTypes.TextEmail
31 | }
32 |
33 | R10.FormTypes.TextEmail ->
34 | { string = "R10.FormTypes.TextEmail"
35 | , next = R10.FormTypes.TextUsername
36 | }
37 |
38 | R10.FormTypes.TextUsername ->
39 | { string = "R10.FormTypes.TextUsername"
40 | , next = R10.FormTypes.TextMultiline
41 | }
42 |
43 | R10.FormTypes.TextMultiline ->
44 | { string = "R10.FormTypes.TextMultiline"
45 | , next = R10.FormTypes.TextWithPattern "YY/MMMM"
46 | }
47 |
48 | R10.FormTypes.TextWithPattern pattern ->
49 | { string = "R10.FormTypes.TextWithPattern " ++ pattern
50 | , next = R10.FormTypes.TextEmailWithSuggestions [ "google.com", "hotmail.com", "yahoo.com" ]
51 | }
52 |
53 | R10.FormTypes.TextEmailWithSuggestions suggestions ->
54 | { string = "R10.FormTypes.TextEmailWithSuggestions [ " ++ String.join ", " suggestions ++ " ]"
55 | , next = R10.FormTypes.TextMobileEmail
56 | }
57 |
58 | R10.FormTypes.TextMobileEmail ->
59 | { string = "R10.FormTypes.TextMobileEmail"
60 | , next = R10.FormTypes.TextUsernameWithUseEmailCheckbox ""
61 | }
62 |
63 | R10.FormTypes.TextUsernameWithUseEmailCheckbox data ->
64 | { string = "R10.FormTypes.TextUsernameWithUseEmailCheckbox " ++ data
65 | , next = R10.FormTypes.TextWithPatternLarge ""
66 | }
67 |
68 | R10.FormTypes.TextWithPatternLarge data ->
69 | { string = "R10.FormTypes.TextWithPatternLarge " ++ data
70 | , next = R10.FormTypes.TextWithPatternLargeWithoutLabel ""
71 | }
72 |
73 | R10.FormTypes.TextWithPatternLargeWithoutLabel data ->
74 | { string = "R10.FormTypes.TextWithPatternLargeWithoutLabel " ++ data
75 | , next = R10.FormTypes.TextOnlyDigitsOrDash
76 | }
77 |
78 | R10.FormTypes.TextOnlyDigitsOrDash ->
79 | { string = "R10.FormTypes.TextOnlyDigitsOrDash"
80 | , next = R10.FormTypes.TextPasswordNew ""
81 | }
82 |
83 |
84 | {-| -}
85 | binaryTypeMetaData :
86 | R10.FormTypes.TypeBinary
87 | -> { next : R10.FormTypes.TypeBinary, string : String }
88 | binaryTypeMetaData textType =
89 | case textType of
90 | R10.FormTypes.BinaryCheckbox ->
91 | { string = "R10.FormTypes.BinaryCheckbox"
92 | , next = R10.FormTypes.BinarySwitch
93 | }
94 |
95 | R10.FormTypes.BinarySwitch ->
96 | { string = "R10.FormTypes.BinarySwitch"
97 | , next = R10.FormTypes.BinaryCheckbox
98 | }
99 |
100 |
101 | {-| -}
102 | singleTypeMetaData :
103 | R10.FormTypes.TypeSingle
104 | -> { next : R10.FormTypes.TypeSingle, string : String }
105 | singleTypeMetaData singleType =
106 | case singleType of
107 | R10.FormTypes.SingleRadio ->
108 | { string = "R10.FormTypes.SingleRadio"
109 | , next = R10.FormTypes.SingleRadioRow
110 | }
111 |
112 | R10.FormTypes.SingleRadioRow ->
113 | { string = "R10.FormTypes.SingleRadio"
114 | , next = R10.FormTypes.SingleCombobox
115 | }
116 |
117 | R10.FormTypes.SingleCombobox ->
118 | { string = "R10.FormTypes.SingleCombobox"
119 | , next = R10.FormTypes.SingleSelect
120 | }
121 |
122 | R10.FormTypes.SingleSelect ->
123 | { string = "R10.FormTypes.SingleSelect"
124 | , next = R10.FormTypes.SingleComboboxForCountry
125 | }
126 |
127 | R10.FormTypes.SingleComboboxForCountry ->
128 | { string = "R10.FormTypes.SingleComboboxForCountry"
129 | , next = R10.FormTypes.SingleRadio
130 | }
131 |
--------------------------------------------------------------------------------
/examples/pwa/src-elm-starter/Starter/SnippetJavascript.elm:
--------------------------------------------------------------------------------
1 | module Starter.SnippetJavascript exposing
2 | ( appWorkAlsoWithoutJS
3 | , metaInfo
4 | , metaInfoData
5 | , portChangeMeta
6 | , portOnUrlChange
7 | , portPushUrl
8 | , registerServiceWorker
9 | , selfInvoking
10 | , signature
11 | )
12 |
13 | import Json.Encode
14 | import Starter.Flags
15 |
16 |
17 | selfInvoking : String -> String
18 | selfInvoking code =
19 | "( function () {\"use strict\";\n" ++ code ++ "\n})();"
20 |
21 |
22 | metaInfo : Starter.Flags.Flags -> String
23 | metaInfo flags =
24 | "window.ElmStarter = " ++ metaInfoData flags ++ ";"
25 |
26 |
27 | metaInfoData : Starter.Flags.Flags -> String
28 | metaInfoData flags =
29 | Json.Encode.encode 4 <|
30 | Starter.Flags.encoder flags
31 |
32 |
33 | signature : String
34 | signature =
35 | selfInvoking <| """
36 | var color =
37 | { default: "background: #eee; color: gray; font-family: monospace"
38 | , love: "background: red; color: #eee"
39 | , elm: "background: #77d7ef; color: #00479a"
40 | };
41 | var emptyLine = " ".repeat(49);
42 | var message =
43 | [ ""
44 | , "%c"
45 | , emptyLine
46 | , " m a d e w i t h %c ❤ %c a n d %c e l m %c "
47 | , emptyLine
48 | , ""
49 | , ""
50 | ].join("\\n");
51 | console.info
52 | ( message
53 | , color.default
54 | , color.love
55 | , color.default
56 | , color.elm
57 | , color.default
58 | );"""
59 |
60 |
61 | registerServiceWorker : String -> String
62 | registerServiceWorker relative =
63 | selfInvoking <| """
64 | // From https://developers.google.com/web/tools/workbox/guides/get-started
65 | if (location.hostname === "localhost") {
66 | console.log("NOT loading the service worker in development");
67 | } else {
68 | if ('serviceWorker' in navigator) {
69 | // Use the window load event to keep the page load performant
70 | window.addEventListener('load', function() {
71 | navigator.serviceWorker.register('""" ++ relative ++ """/service-worker.js').then(function(registration) {
72 | // Registration was successful
73 | }, function(err) {
74 | // registration failed :(
75 | });
76 | });
77 | }
78 | }"""
79 |
80 |
81 | {-| Changing "You need js..." to "Better to use js..." because
82 | the app is working also wihtout js in production when
83 | these pages are generated with Puppeteer
84 | -}
85 | appWorkAlsoWithoutJS :
86 | { a
87 | | messageEnableJavascriptForBetterExperience : String
88 | , messageYouNeedToEnableJavascript : String
89 | }
90 | -> String
91 | appWorkAlsoWithoutJS args =
92 | """
93 | var noscriptElement = document.querySelector('noscript');
94 | if (noscriptElement) {
95 | noscriptElement.innerHTML = noscriptElement.innerHTML.replace
96 | ( \"""" ++ args.messageYouNeedToEnableJavascript ++ """"
97 | , \"""" ++ args.messageEnableJavascriptForBetterExperience ++ """"
98 | );
99 | } """
100 |
101 |
102 | portOnUrlChange : String
103 | portOnUrlChange =
104 | """
105 | // From https://github.com/elm/browser/blob/1.0.2/notes/navigation-in-elements.md
106 | // Inform app of browser navigation (the BACK and FORWARD buttons)
107 | if (ElmApp && ElmApp.ports && ElmApp.ports.onUrlChange) {
108 | window.addEventListener('popstate', function () {
109 | ElmApp.ports.onUrlChange.send(location.href);
110 | });
111 | } """
112 |
113 |
114 | portPushUrl : String
115 | portPushUrl =
116 | """
117 | // From https://github.com/elm/browser/blob/1.0.2/notes/navigation-in-elements.md
118 | // Change the URL upon request, inform app of the change.
119 | if (ElmApp && ElmApp.ports && ElmApp.ports.pushUrl) {
120 | ElmApp.ports.pushUrl.subscribe(function(url) {
121 | history.pushState({}, '', url);
122 | window.scrollTo(0, 0);
123 | if (ElmApp && ElmApp.ports && ElmApp.ports.onUrlChange) {
124 | ElmApp.ports.onUrlChange.send(location.href);
125 | }
126 | });
127 | } """
128 |
129 |
130 | portChangeMeta : String
131 | portChangeMeta =
132 | """
133 | if (ElmApp && ElmApp.ports && ElmApp.ports.changeMeta) {
134 | ElmApp.ports.changeMeta.subscribe(function(args) {
135 | if (args.querySelector !== "") {
136 | var element = document.querySelector(args.querySelector);
137 | if (element) {
138 | if (args.type_ == "attribute") {
139 | element.setAttribute(args.fieldName, args.content);
140 | } else if (args.type_ == "property" && element[args.fieldName]) {
141 | element[args.fieldName] = args.content;
142 | }
143 | }
144 | }
145 | });
146 | } """
147 |
--------------------------------------------------------------------------------
/src/R10/DropDown.elm:
--------------------------------------------------------------------------------
1 | module R10.DropDown exposing (Option, extraCss, view, viewBorderLess)
2 |
3 | {-| Craate a Dropdown using HTML `select`
4 |
5 | @docs Option, extraCss, view, viewBorderLess
6 |
7 | -}
8 |
9 | import Element.WithContext exposing (..)
10 | import Html
11 | import Html.Attributes
12 | import Html.Events
13 | import Json.Decode
14 | import R10.Color.Utils
15 | import R10.Context exposing (..)
16 | import R10.Transition
17 |
18 |
19 | {-| -}
20 | type alias Option =
21 | { value : String
22 | , text : String
23 | }
24 |
25 |
26 | type Type
27 | = BorderLess
28 |
29 |
30 | renderHtmlOption : String -> Option -> Html.Html msg
31 | renderHtmlOption selected { value, text } =
32 | Html.option
33 | [ Html.Attributes.value value
34 | , Html.Attributes.selected (value == selected)
35 | ]
36 | [ Html.text text ]
37 |
38 |
39 | commonStyle : Float -> Int -> Color -> Color -> List (Html.Attribute msg)
40 | commonStyle ratio fontSize colorFont colorBackground =
41 | [ Html.Attributes.style "font-size" (String.fromInt fontSize ++ "px")
42 | , Html.Attributes.style "padding" "8px 28px 8px 30px"
43 | , Html.Attributes.style "color" (R10.Color.Utils.toCssRgba colorFont)
44 | , Html.Attributes.style "background-color" (R10.Color.Utils.toCssRgba colorBackground)
45 | , Html.Attributes.style "-webkit-appearance" "none"
46 | , Html.Attributes.style "-moz-appearance" "none"
47 | , Html.Attributes.style "border-radius" "5px"
48 | , Html.Attributes.style "cursor" "pointer"
49 | , Html.Attributes.style "outline" "none"
50 | , Html.Attributes.class "drop-down"
51 | , Html.Attributes.style "transition" (R10.Transition.parseCharacteristics ratio "color .2s ease-out, background-color .2s ease-out")
52 | ]
53 |
54 |
55 | getDropDownStyle : Float -> Int -> Color -> Color -> Type -> List (Html.Attribute msg)
56 | getDropDownStyle ratio fontSize colorFont colorBackground dropDownType =
57 | case dropDownType of
58 | BorderLess ->
59 | -- Set margin left for alignment by compensating the spacing gap of padding left
60 | commonStyle ratio fontSize colorFont colorBackground
61 | ++ [ Html.Attributes.style "border" "none"
62 | , Html.Attributes.style "margin-left" "-8px"
63 | ]
64 |
65 |
66 | {-| The dropdown.
67 | -}
68 | view :
69 | List (Attribute (R10.Context.ContextInternal z) msg)
70 | ->
71 | { a
72 | | colorBackground : Color
73 | , colorFont : Color
74 | , currentValue : String
75 | , inputHandler : String -> msg
76 | , optionList : List Option
77 | , fontSize : Int
78 | }
79 | -> Type
80 | -> Element (R10.Context.ContextInternal z) msg
81 | view attrs args dropDownType =
82 | withContext <|
83 | \c ->
84 | el
85 | attrs
86 | (html <|
87 | Html.select
88 | ([ Html.Events.on "change" (Json.Decode.map args.inputHandler Html.Events.targetValue)
89 | , Html.Attributes.value args.currentValue
90 | ]
91 | ++ getDropDownStyle c.contextR10.debugger_transitionSpeed args.fontSize args.colorFont args.colorBackground dropDownType
92 | )
93 | (List.map (renderHtmlOption args.currentValue) args.optionList)
94 | )
95 |
96 |
97 |
98 | -- Public interface
99 | -- Facade based on `view` to construct different appearance of drop down components.
100 |
101 |
102 | {-| Slightly different version of the dropdown that has no borders.
103 | -}
104 | viewBorderLess :
105 | List (Attribute (R10.Context.ContextInternal z) msg)
106 | ->
107 | { a
108 | | colorBackground : Color
109 | , colorFont : Color
110 | , currentValue : String
111 | , inputHandler : String -> msg
112 | , optionList : List Option
113 | , fontSize : Int
114 | }
115 | -> Element (R10.Context.ContextInternal z) msg
116 | viewBorderLess attrs args =
117 | view attrs args BorderLess
118 |
119 |
120 |
121 | -- This is some extra CSS that you need to add to the page
122 | -- if you use this module. The String argument is the `colorHover`
123 |
124 |
125 | {-| -}
126 | extraCss : Color -> String
127 | extraCss colorHover =
128 | -- Remove the triangle button (select arrow) from IE11
129 | -- https://stackoverflow.com/questions/20163079/remove-select-arrow-on-ie
130 | """
131 | select::-ms-expand {
132 | display: none;
133 | }
134 | .drop-down:hover, .drop-down:focus {
135 | background-color: """ ++ R10.Color.Utils.toCssRgba colorHover ++ """ !important;
136 | }
137 | """
138 |
--------------------------------------------------------------------------------
/src/R10/Form/Internal/MakerForValues.elm:
--------------------------------------------------------------------------------
1 | module R10.Form.Internal.MakerForValues exposing
2 | ( Outcome
3 | , maker
4 | , viewEntityMulti
5 | )
6 |
7 | import R10.Form.Internal.Conf
8 | import R10.Form.Internal.Dict
9 | import R10.Form.Internal.FieldState
10 | import R10.Form.Internal.Key
11 | import R10.Form.Internal.Shared
12 | import R10.Form.Internal.State
13 | import R10.Form.Internal.StateForValues
14 | import Set
15 |
16 |
17 |
18 | -- ██████ ██ ██ ████████ ██████ ██████ ███ ███ ███████
19 | -- ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██
20 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ █████
21 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
22 | -- ██████ ██████ ██ ██████ ██████ ██ ██ ███████
23 |
24 |
25 | type alias Outcome =
26 | R10.Form.Internal.StateForValues.Entity
27 |
28 |
29 |
30 | -- ██ ██ ███████ ██ ██████ ███████ ██████ ███████
31 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
32 | -- ███████ █████ ██ ██████ █████ ██████ ███████
33 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██
34 | -- ██ ██ ███████ ███████ ██ ███████ ██ ██ ███████
35 |
36 |
37 | viewEntityMulti :
38 | R10.Form.Internal.Key.Key
39 | -> R10.Form.Internal.State.State
40 | -> List R10.Form.Internal.Conf.Entity
41 | -> List Outcome
42 | viewEntityMulti key formState entities =
43 | let
44 | quantity : Int
45 | quantity =
46 | Maybe.withDefault 1 <| R10.Form.Internal.Dict.get key formState.multiplicableQuantities
47 | in
48 | List.concat <|
49 | List.indexedMap
50 | (\index _ ->
51 | let
52 | newKey : R10.Form.Internal.Key.Key
53 | newKey =
54 | R10.Form.Internal.Key.composeKey key (String.fromInt index)
55 |
56 | removed : Bool
57 | removed =
58 | Set.member (R10.Form.Internal.Key.toString newKey) formState.removed
59 | in
60 | if removed then
61 | []
62 |
63 | else
64 | [ R10.Form.Internal.StateForValues.EntityIndex index <| maker { state = formState, conf = entities } newKey ]
65 | )
66 | (List.repeat quantity ())
67 |
68 |
69 |
70 | -- ███ ███ █████ ██ ██ ███████ ██████
71 | -- ████ ████ ██ ██ ██ ██ ██ ██ ██
72 | -- ██ ████ ██ ███████ █████ █████ ██████
73 | -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
74 | -- ██ ██ ██ ██ ██ ██ ███████ ██ ██
75 |
76 |
77 | maker :
78 | R10.Form.Internal.Shared.Form
79 | -> R10.Form.Internal.Key.Key
80 | -> List Outcome
81 | maker form key =
82 | --
83 | -- This is recursive
84 | --
85 | -- ┌─────> maker >─────┐
86 | -- │ │
87 | -- └───────────────────┘
88 | --
89 | List.concat <|
90 | List.map
91 | (\entity ->
92 | case entity of
93 | R10.Form.Internal.Conf.EntityWrappable _ entities ->
94 | maker { form | conf = entities } key
95 |
96 | R10.Form.Internal.Conf.EntityWithBorder _ entities ->
97 | maker { form | conf = entities } key
98 |
99 | R10.Form.Internal.Conf.EntityNormal _ entities ->
100 | maker { form | conf = entities } key
101 |
102 | R10.Form.Internal.Conf.EntityWithTabs _ titleEntityList ->
103 | maker { form | conf = titleEntityList |> List.map Tuple.second } key
104 |
105 | R10.Form.Internal.Conf.EntityMulti key_ entities ->
106 | [ R10.Form.Internal.StateForValues.EntityMulti key_ <| viewEntityMulti key form.state entities ]
107 |
108 | R10.Form.Internal.Conf.EntityField fieldConf ->
109 | let
110 | newKey : R10.Form.Internal.Key.Key
111 | newKey =
112 | R10.Form.Internal.Key.composeKey key fieldConf.id
113 |
114 | fieldState : R10.Form.Internal.FieldState.FieldState
115 | fieldState =
116 | Maybe.withDefault R10.Form.Internal.FieldState.init <| R10.Form.Internal.Dict.get newKey form.state.fieldsState
117 | in
118 | [ R10.Form.Internal.StateForValues.EntityField fieldConf.id fieldState.value ]
119 |
120 | R10.Form.Internal.Conf.EntityTitle _ _ ->
121 | []
122 |
123 | R10.Form.Internal.Conf.EntitySubTitle _ _ ->
124 | []
125 | )
126 | form.conf
127 |
--------------------------------------------------------------------------------
/src/R10/Color/AttrsBorder.elm:
--------------------------------------------------------------------------------
1 | module R10.Color.AttrsBorder exposing (buttonSecondary, inputFieldCheckboxNormal, inputFieldCheckboxOver, inputFieldCheckboxSelected, inputFieldError, inputFieldFocused, inputFieldNormal, inputFieldSuccess, normal, shadow)
2 |
3 | {-| Border colors
4 |
5 | @docs buttonSecondary, inputFieldCheckboxNormal, inputFieldCheckboxOver, inputFieldCheckboxSelected, inputFieldError, inputFieldFocused, inputFieldNormal, inputFieldSuccess, normal, shadow
6 |
7 | -}
8 |
9 | import Element.WithContext exposing (..)
10 | import Element.WithContext.Border as Border
11 | import R10.Color.Internal.Derived
12 | import R10.Color.Utils
13 | import R10.Context
14 |
15 |
16 |
17 | -- NORMAL
18 |
19 |
20 | {-| -}
21 | normal : Attribute (R10.Context.ContextInternal z) msg
22 | normal =
23 | withContextAttribute <|
24 | \c ->
25 | R10.Color.Internal.Derived.Border
26 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
27 | |> R10.Color.Utils.fromColorColor
28 | |> Border.color
29 |
30 |
31 |
32 | -- SHADOW
33 |
34 |
35 | {-| -}
36 | shadow : { offset : ( Float, Float ), size : Float, blur : Float } -> Attribute (R10.Context.ContextInternal z) msg
37 | shadow { offset, size, blur } =
38 | withContextAttribute <|
39 | \c ->
40 | R10.Color.Internal.Derived.Border
41 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
42 | |> R10.Color.Utils.fromColorColor
43 | |> (\color -> { offset = offset, size = size, blur = blur, color = color })
44 | |> Border.shadow
45 |
46 |
47 |
48 | -- BUTTON SECONDARY
49 |
50 |
51 | {-| -}
52 | buttonSecondary : Attribute (R10.Context.ContextInternal z) msg
53 | buttonSecondary =
54 | withContextAttribute <|
55 | \c ->
56 | R10.Color.Internal.Derived.Border
57 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
58 | |> R10.Color.Utils.fromColorColor
59 | |> Border.color
60 |
61 |
62 |
63 | -- INPUT FIELD
64 |
65 |
66 | {-| -}
67 | inputFieldNormal : Attribute (R10.Context.ContextInternal z) msg
68 | inputFieldNormal =
69 | withContextAttribute <|
70 | \c ->
71 | R10.Color.Internal.Derived.Border
72 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
73 | |> R10.Color.Utils.fromColorColor
74 | |> Border.color
75 |
76 |
77 | {-| -}
78 | inputFieldFocused : Attribute (R10.Context.ContextInternal z) msg
79 | inputFieldFocused =
80 | withContextAttribute <|
81 | \c ->
82 | R10.Color.Internal.Derived.Primary
83 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
84 | |> R10.Color.Utils.fromColorColor
85 | |> Border.color
86 |
87 |
88 | {-| -}
89 | inputFieldError : Attribute (R10.Context.ContextInternal z) msg
90 | inputFieldError =
91 | withContextAttribute <|
92 | \c ->
93 | R10.Color.Internal.Derived.FontAlertDanger
94 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
95 | |> R10.Color.Utils.fromColorColor
96 | |> Border.color
97 |
98 |
99 | {-| -}
100 | inputFieldSuccess : Attribute (R10.Context.ContextInternal z) msg
101 | inputFieldSuccess =
102 | withContextAttribute <|
103 | \c ->
104 | R10.Color.Internal.Derived.FontAlertSuccess
105 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
106 | |> R10.Color.Utils.fromColorColor
107 | |> Border.color
108 |
109 |
110 |
111 | -- CHECKBOX
112 |
113 |
114 | {-| -}
115 | inputFieldCheckboxNormal : Attribute (R10.Context.ContextInternal z) msg
116 | inputFieldCheckboxNormal =
117 | withContextAttribute <|
118 | \c ->
119 | R10.Color.Internal.Derived.Border
120 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
121 | |> R10.Color.Utils.fromColorColor
122 | |> Border.color
123 |
124 |
125 | {-| -}
126 | inputFieldCheckboxSelected : Attribute (R10.Context.ContextInternal z) msg
127 | inputFieldCheckboxSelected =
128 | withContextAttribute <|
129 | \c ->
130 | R10.Color.Internal.Derived.Primary
131 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
132 | |> R10.Color.Utils.fromColorColor
133 | |> Border.color
134 |
135 |
136 | {-| -}
137 | inputFieldCheckboxOver : Decoration (R10.Context.ContextInternal z)
138 | inputFieldCheckboxOver =
139 | withContextDecoration <|
140 | \c ->
141 | R10.Color.Internal.Derived.Primary
142 | |> R10.Color.Internal.Derived.toColor c.contextR10.theme
143 | |> R10.Color.Utils.fromColorColor
144 | |> Border.color
145 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # R10
2 |
3 | 
4 |
5 | **R10** is a library of interactive building blocks written in [Elm](https://elm-lang.org/) and [elm-ui](https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/) that we use at [Rakuten](https://global.rakuten.com/) for creating user interfaces.
6 |
7 | **Disclaimer**: This library is actively used in our live projects and the code and the documentation can be rough in most places because, you know, deadlines! It is also tailored for our use so it is probably useful as source of information rather than as a real dependency to add in your projects.
8 |
9 | ### Links
10 |
11 | * [R10 demo with documentation and examples](https://r10.netlify.app/)
12 | * [R10 in the Elm's package website](https://package.elm-lang.org/packages/rakutentech/r10/latest/)
13 | * [R10 in Github](https://github.com/rakutentech/r10)
14 | * [Ellie: R10 Simple View](https://ellie-app.com/j3Xg2HZ4V62a1)
15 | * [Ellie: R10 Simple Form](https://ellie-app.com/j3Xj8dmJzvja1)
16 | * [Ellie: R10 Credit Card Form](https://ellie-app.com/j3Xk8ZqvKGYa1)
17 |
18 | # How to use the R10 library
19 |
20 | If you already have an existing Elm project, install the library with
21 |
22 | ```bash
23 | elm install rakutentech/r10
24 | ```
25 |
26 | See [this Ellie](https://ellie-app.com/gCQvcN4gy3Ra1).
27 |
28 |
29 |
30 | # How to bootstrap a new project
31 |
32 | You can find a fully functional project in the folder [`examples/pwa`](https://github.com/rakutentech/r10/tree/master/examples/pwa). You can use it as a base for a new project simply copying it.
33 |
34 | From the root folder of the example, run
35 |
36 | ```bash
37 | npm install
38 | npm start
39 | ```
40 |
41 | Then you can preview the website at http://localhost:8000.
42 |
43 | Changing `src/Main.elm` will automatically recompile the application and refresh the browser.
44 |
45 | To build the files optimized for the release in production, run:
46 |
47 | ```bash
48 | npm run build
49 | ```
50 |
51 | You can then find the files in `elm-stuff/elm-starter-files/build`.
52 |
53 |
54 | ## Website characteristics
55 |
56 | The bootstrapped website showcases has these characteristics:
57 |
58 | * Single Page Application (**SPA**)
59 | * Progressive Web Application (**PWA**)
60 | * **Static SSR** (pre-render during the build)
61 | * Works **off-line** and **without Javascript**
62 | * **Installable** on desktop and mobile
63 | * Friendly to search engines (**SEO**)
64 | * Supports **custom previews** so it looks good when you share links
65 | * **Best practices**, **Accessibility**, etc. (High scores with Lighthouse)
66 | * Includes **R10 building blocks** such as logos, icons, buttons, forms, etc. with coding playgrounds.
67 | * Supports **multi language** websites
68 | * Standard **header and footer**
69 |
70 | To know more, read the [`elm-starter` documentation](https://github.com/lucamug/elm-starter) and the [`r10` documentation](https://package.elm-lang.org/packages/rakutentech/r10/latest/).
71 |
72 | Note: If you copied the file in a new folder you need to modify the `elm.json` file:
73 |
74 | 1. Remove `../../src` from the list of `source-directories`
75 | 2. Run `elm install rakutentech/r10` that will add this library as dependency
76 |
77 |
78 |
79 | # Other languages or frameworks
80 |
81 | If you are looking for Rakuten UI components written in other languages or frameworks, have a look at the [ReX Github repository](https://github.com/rakuten-rex) and the [ReX Frontend Components Library](https://zeroheight.com/390c074f3/p/080991-).
82 |
83 |
84 |
85 | # Thanks
86 |
87 | Thanks to Evan Czaplicki, Matthew Griffith, Richard Feldman, the folks at NoRedInk, Ryan Haskell-Glatz, Ilias Van Peer, Aaron VonderHaar, Abadi Kurniawaan, Dillon Kearns, Jeroen Engels, Keith Lazuka, Luke Westby, Alex Korban, Thibaut Assus, Brian Hicks and many more from the Elm community that directly or indirectly supported us in this journey.
88 |
89 |
90 |
91 | # Examples
92 |
93 | These are real-life fully working code samples that render these views:
94 |
95 | 
96 |
97 | The primary color and the light/dark mode can be changed through the `theme` definitions. For example:
98 |
99 | ```elm
100 | theme =
101 | { mode = R10.Mode.Light
102 | , primaryColor = R10.Color.primary.blueSky
103 | }
104 |
105 | theme =
106 | { mode = R10.Mode.Light
107 | , primaryColor = R10.Color.primary.green
108 | }
109 |
110 | theme =
111 | { mode = R10.Mode.Dark
112 | , primaryColor = R10.Color.primary.blueSky
113 | }
114 | ```
115 |
116 | This is the source code for the example with two buttons: [Source code](https://github.com/rakutentech/r10/tree/master/examples/simpleView/src/Main.elm).
117 |
118 | This is the code sample for the view with the form: ([Source code](https://github.com/rakutentech/r10/blob/master/examples/simpleForm/src/Main.elm)).
119 |
--------------------------------------------------------------------------------
/examples/simpleForm/src/Main.elm:
--------------------------------------------------------------------------------
1 | module Main exposing (main)
2 |
3 | import Browser
4 | import Element.WithContext exposing (..)
5 | import Element.WithContext.Font as Font
6 | import Html
7 | import R10.Button
8 | import R10.Card
9 | import R10.Color.AttrsBackground
10 | import R10.Color.Svg
11 | import R10.Context
12 | import R10.FontSize
13 | import R10.Form
14 | import R10.FormTypes
15 | import R10.Libu
16 | import R10.Paragraph
17 | import R10.Svg.LogosExtra
18 |
19 |
20 | main : Program () Model Msg
21 | main =
22 | Browser.element
23 | { init = init
24 | , view = view
25 | , update = update
26 | , subscriptions = \_ -> Sub.none
27 | }
28 |
29 |
30 | type alias Model =
31 | { form : R10.Form.Form }
32 |
33 |
34 | type Msg
35 | = MsgForm R10.Form.Msg
36 |
37 |
38 | init : () -> ( Model, Cmd msg )
39 | init _ =
40 | ( { form =
41 | { conf =
42 | [ R10.Form.entity.field
43 | { id = "email"
44 | , idDom = Nothing
45 | , type_ = R10.FormTypes.TypeText R10.FormTypes.TextEmail
46 | , label = "Email"
47 | , clickableLabel = False
48 | , helperText = Just "Helper text for Email"
49 | , requiredLabel = Just "(required)"
50 | , validationSpecs =
51 | Just
52 | { pretendIsNotValidatedIfValid = True
53 | , showAlsoPassedValidation = False
54 | , validationIcon = R10.FormTypes.NoIcon
55 | , validation =
56 | [ R10.Form.commonValidation.email
57 | , R10.Form.validation.minLength 5
58 | , R10.Form.validation.maxLength 50
59 | , R10.Form.validation.required
60 | ]
61 | }
62 | , minWidth = Nothing
63 | , maxWidth = Nothing
64 | , autocomplete = Nothing
65 | , placeholder = Nothing
66 | , allowOverMaxLength = False
67 | }
68 | , R10.Form.entity.field
69 | { id = "password"
70 | , idDom = Nothing
71 | , type_ = R10.FormTypes.TypeText (R10.FormTypes.TextPasswordNew "Show password")
72 | , label = "Password"
73 | , clickableLabel = False
74 | , helperText = Just "Helper text for Password"
75 | , requiredLabel = Just "(required)"
76 | , validationSpecs =
77 | Just
78 | { pretendIsNotValidatedIfValid = True
79 | , showAlsoPassedValidation = False
80 | , validationIcon = R10.FormTypes.NoIcon
81 | , validation =
82 | [ R10.Form.validation.minLength 8
83 | , R10.Form.validation.required
84 | ]
85 | }
86 | , minWidth = Nothing
87 | , maxWidth = Nothing
88 | , autocomplete = Nothing
89 | , placeholder = Nothing
90 | , allowOverMaxLength = False
91 | }
92 | ]
93 | , state = R10.Form.initState
94 | }
95 | }
96 | , Cmd.none
97 | )
98 |
99 |
100 | update : Msg -> Model -> ( Model, Cmd msg )
101 | update msg model =
102 | case msg of
103 | MsgForm msgForm ->
104 | let
105 | form : R10.Form.Form
106 | form =
107 | model.form
108 |
109 | ( newState, cmd ) =
110 | R10.Form.update (\_ a -> a) msgForm form.state
111 |
112 | newForm : R10.Form.Form
113 | newForm =
114 | { form | state = newState }
115 | in
116 | ( { model | form = newForm }, Cmd.none )
117 |
118 |
119 | view : Model -> Html.Html Msg
120 | view model =
121 | layoutWith R10.Context.default
122 | { options =
123 | [ focusStyle
124 | { borderColor = Nothing
125 | , backgroundColor = Nothing
126 | , shadow = Nothing
127 | }
128 | ]
129 | }
130 | [ R10.Color.AttrsBackground.background, padding 20, R10.FontSize.normal ]
131 | (column
132 | (R10.Card.high
133 | ++ [ centerX
134 | , centerY
135 | , width (fill |> maximum 360)
136 | , height shrink
137 | , spacing 30
138 | ]
139 | )
140 | [ withContext <| \c -> R10.Svg.LogosExtra.r10 [ centerX ] (R10.Color.Svg.logo c.contextR10.theme) 32
141 | , R10.Paragraph.normalMarkdown [ Font.center ] "This is an example of a form made with [Elm](https://elm-lang.org/), [elm-ui](https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/) and [R10](https://package.elm-lang.org/packages/rakutentech/r10/latest/) ([Source code](https://github.com/rakutentech/r10/blob/master/examples/simpleForm/src/Main.elm))."
142 | , column [ spacing 20, width fill ] <| R10.Form.view model.form MsgForm
143 | , map MsgForm <|
144 | R10.Button.primary []
145 | { label = text "Sign In"
146 | , libu = R10.Libu.Bu <| Just <| R10.Form.msg.submit model.form.conf
147 | , translation = { key = "example" }
148 | }
149 | ]
150 | )
151 |
--------------------------------------------------------------------------------
/src/R10/FormComponents/Internal/UI/Color.elm:
--------------------------------------------------------------------------------
1 | module R10.FormComponents.Internal.UI.Color exposing
2 | ( background
3 | , backgroundA
4 | , border
5 | , borderA
6 | , container
7 | , containerA
8 | , error
9 | , errorA
10 | , font
11 | , fontA
12 | , fromPalette
13 | , fromPaletteColor
14 | , label
15 | , labelA
16 | , mouseOverPrimary
17 | , mouseOverSurface
18 | , onPrimary
19 | , onPrimaryA
20 | , onSurface
21 | , onSurfaceA
22 | , primary
23 | , primaryA
24 | , primaryVariant
25 | , primaryVariantA
26 | , success
27 | , successA
28 | , surface
29 | , surfaceA
30 | , toCssString
31 | , transparent
32 | )
33 |
34 | import Color
35 | import Color.Blending
36 | import Element.WithContext exposing (..)
37 | import R10.Context exposing (..)
38 | import R10.Palette
39 |
40 |
41 |
42 | -- helpers
43 |
44 |
45 | fromPaletteColor : Color.Color -> Color
46 | fromPaletteColor =
47 | Color.toRgba >> fromRgb
48 |
49 |
50 | fromPalette : (R10.Palette.Palette -> Color.Color) -> R10.Palette.Palette -> Color
51 | fromPalette mapper =
52 | mapper >> fromPaletteColor
53 |
54 |
55 | toPaletteColor : Color -> Color.Color
56 | toPaletteColor =
57 | toRgb >> Color.fromRgba
58 |
59 |
60 | toCssString : Color -> String
61 | toCssString =
62 | toPaletteColor >> Color.toCssString
63 |
64 |
65 |
66 | -- Palette colors
67 |
68 |
69 | primary : R10.Palette.Palette -> Color
70 | primary =
71 | .primary >> fromPaletteColor
72 |
73 |
74 | primaryVariant : R10.Palette.Palette -> Color
75 | primaryVariant =
76 | .primaryVariant >> fromPaletteColor
77 |
78 |
79 | success : R10.Palette.Palette -> Color
80 | success =
81 | .success >> fromPaletteColor
82 |
83 |
84 | error : R10.Palette.Palette -> Color
85 | error =
86 | .error >> fromPaletteColor
87 |
88 |
89 | onSurface : R10.Palette.Palette -> Color
90 | onSurface =
91 | .onSurface >> fromPaletteColor
92 |
93 |
94 | onPrimary : R10.Palette.Palette -> Color
95 | onPrimary =
96 | .onPrimary >> fromPaletteColor
97 |
98 |
99 | surface : R10.Palette.Palette -> Color
100 | surface =
101 | .surface >> fromPaletteColor
102 |
103 |
104 | background : R10.Palette.Palette -> Color
105 | background =
106 | .background >> fromPaletteColor
107 |
108 |
109 |
110 | -- Palette colors helpers
111 |
112 |
113 | primaryA : Float -> R10.Palette.Palette -> Color
114 | primaryA alpha palette =
115 | palette.primary
116 | |> R10.Palette.withOpacity alpha
117 | |> fromPaletteColor
118 |
119 |
120 | primaryVariantA : Float -> R10.Palette.Palette -> Color
121 | primaryVariantA alpha palette =
122 | palette.primaryVariant
123 | |> R10.Palette.withOpacity alpha
124 | |> fromPaletteColor
125 |
126 |
127 | successA : Float -> R10.Palette.Palette -> Color
128 | successA alpha palette =
129 | palette.success
130 | |> R10.Palette.withOpacity alpha
131 | |> fromPaletteColor
132 |
133 |
134 | errorA : Float -> R10.Palette.Palette -> Color
135 | errorA alpha palette =
136 | palette.error
137 | |> R10.Palette.withOpacity alpha
138 | |> fromPaletteColor
139 |
140 |
141 | onSurfaceA : Float -> R10.Palette.Palette -> Color
142 | onSurfaceA alpha palette =
143 | palette.onSurface
144 | |> R10.Palette.withOpacity alpha
145 | |> fromPaletteColor
146 |
147 |
148 | onPrimaryA : Float -> R10.Palette.Palette -> Color
149 | onPrimaryA alpha palette =
150 | palette.onPrimary
151 | |> R10.Palette.withOpacity alpha
152 | |> fromPaletteColor
153 |
154 |
155 | surfaceA : Float -> R10.Palette.Palette -> Color
156 | surfaceA alpha palette =
157 | palette.surface
158 | |> R10.Palette.withOpacity alpha
159 | |> fromPaletteColor
160 |
161 |
162 | backgroundA : Float -> R10.Palette.Palette -> Color
163 | backgroundA alpha palette =
164 | palette.background
165 | |> R10.Palette.withOpacity alpha
166 | |> fromPaletteColor
167 |
168 |
169 |
170 | -- color aliases
171 |
172 |
173 | container : R10.Palette.Palette -> Color
174 | container =
175 | onSurfaceA 0.54
176 |
177 |
178 | containerA : Float -> R10.Palette.Palette -> Color
179 | containerA alpha =
180 | onSurfaceA <| 0.54 * alpha
181 |
182 |
183 | font : R10.Palette.Palette -> Color
184 | font =
185 | onSurfaceA 0.87
186 |
187 |
188 | fontA : Float -> R10.Palette.Palette -> Color
189 | fontA alpha =
190 | onSurfaceA <| 0.87 * alpha
191 |
192 |
193 | label : R10.Palette.Palette -> Color
194 | label =
195 | -- TODO(This is a temporary fix for OMNI (The label color is too light))
196 | onSurfaceA 1
197 |
198 |
199 | labelA : Float -> R10.Palette.Palette -> Color
200 | labelA alpha =
201 | -- TODO(This is a temporary fix for OMNI)
202 | onSurfaceA <| 1 * alpha
203 |
204 |
205 | mouseOverSurface : R10.Palette.Palette -> Color
206 | mouseOverSurface =
207 | -- https://material.io/design/interaction/states.html#hover
208 | onSurfaceA 0.04
209 |
210 |
211 | mouseOverPrimary : R10.Palette.Palette -> Color
212 | mouseOverPrimary palette =
213 | -- https://material.io/design/interaction/states.html#hover
214 | Color.Blending.overlay (onPrimaryA 0.08 palette |> toPaletteColor) (primary palette |> toPaletteColor)
215 | |> fromPaletteColor
216 |
217 |
218 |
219 | -- constant colors
220 |
221 |
222 | transparent : Color
223 | transparent =
224 | R10.Palette.black
225 | |> R10.Palette.withOpacity 0
226 | |> fromPaletteColor
227 |
228 |
229 |
230 | -- border
231 |
232 |
233 | border : R10.Palette.Palette -> Color
234 | border palette =
235 | palette.border
236 | |> fromPaletteColor
237 |
238 |
239 | borderA : Float -> R10.Palette.Palette -> Color
240 | borderA alpha palette =
241 | palette.border
242 | |> R10.Palette.withOpacity alpha
243 | |> fromPaletteColor
244 |
--------------------------------------------------------------------------------