mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-27 13:02:42 +03:00
Re-remove some of the modules
This commit is contained in:
parent
c45f90221f
commit
9a2d89bf9b
6
elm.json
6
elm.json
@ -7,16 +7,10 @@
|
|||||||
"exposed-modules": [
|
"exposed-modules": [
|
||||||
"Nri.Ui",
|
"Nri.Ui",
|
||||||
"Nri.Ui.Accordion.V1",
|
"Nri.Ui.Accordion.V1",
|
||||||
"Nri.Ui.Alert.V2",
|
|
||||||
"Nri.Ui.Alert.V3",
|
|
||||||
"Nri.Ui.Alert.V4",
|
"Nri.Ui.Alert.V4",
|
||||||
"Nri.Ui.AssetPath",
|
"Nri.Ui.AssetPath",
|
||||||
"Nri.Ui.AssignmentIcon.V1",
|
"Nri.Ui.AssignmentIcon.V1",
|
||||||
"Nri.Ui.BannerAlert.V2",
|
|
||||||
"Nri.Ui.BannerAlert.V3",
|
|
||||||
"Nri.Ui.BannerAlert.V6",
|
"Nri.Ui.BannerAlert.V6",
|
||||||
"Nri.Ui.Button.V3",
|
|
||||||
"Nri.Ui.Button.V4",
|
|
||||||
"Nri.Ui.Button.V5",
|
"Nri.Ui.Button.V5",
|
||||||
"Nri.Ui.Button.V6",
|
"Nri.Ui.Button.V6",
|
||||||
"Nri.Ui.Button.V7",
|
"Nri.Ui.Button.V7",
|
||||||
|
@ -17,15 +17,11 @@ src/Nri/Ui/SlideModal/V2.elm,Nri.Ui.Text,2
|
|||||||
src/Nri/Ui/SlideModal/V1.elm,Nri.Ui.Button,8
|
src/Nri/Ui/SlideModal/V1.elm,Nri.Ui.Button,8
|
||||||
src/Nri/Ui/SlideModal/V1.elm,Nri.Ui.Icon,3
|
src/Nri/Ui/SlideModal/V1.elm,Nri.Ui.Icon,3
|
||||||
src/Nri/Ui/SlideModal/V1.elm,Nri.Ui.Text,2
|
src/Nri/Ui/SlideModal/V1.elm,Nri.Ui.Text,2
|
||||||
src/Nri/Ui/Alert/V3.elm,Nri.Ui.Icon,3
|
|
||||||
src/Nri/Ui/Alert/V2.elm,Nri.Ui.Icon,3
|
|
||||||
src/Nri/Ui/Alert/V4.elm,Nri.Ui.Icon,3
|
src/Nri/Ui/Alert/V4.elm,Nri.Ui.Icon,3
|
||||||
src/Nri/Ui/SortableTable/V1.elm,Nri.Ui.Table,4
|
src/Nri/Ui/SortableTable/V1.elm,Nri.Ui.Table,4
|
||||||
src/Nri/Ui/Html/Attributes/Extra.elm,Html,DEPRECATED
|
src/Nri/Ui/Html/Attributes/Extra.elm,Html,DEPRECATED
|
||||||
src/Nri/Ui/Button/V8.elm,Html,DEPRECATED
|
src/Nri/Ui/Button/V8.elm,Html,DEPRECATED
|
||||||
src/Nri/Ui/Button/V3.elm,Nri.Ui.Icon,3
|
|
||||||
src/Nri/Ui/Button/V5.elm,Nri.Ui.Icon,3
|
src/Nri/Ui/Button/V5.elm,Nri.Ui.Icon,3
|
||||||
src/Nri/Ui/Button/V4.elm,Nri.Ui.Icon,3
|
|
||||||
src/Nri/Ui/Button/V6.elm,Nri.Ui.Icon,4
|
src/Nri/Ui/Button/V6.elm,Nri.Ui.Icon,4
|
||||||
src/Nri/Ui/Button/V7.elm,Nri.Ui.Icon,4
|
src/Nri/Ui/Button/V7.elm,Nri.Ui.Icon,4
|
||||||
src/Nri/Ui/SegmentedControl/V6.elm,Nri.Ui.Icon,3
|
src/Nri/Ui/SegmentedControl/V6.elm,Nri.Ui.Icon,3
|
||||||
|
|
@ -1,121 +0,0 @@
|
|||||||
module Nri.Ui.Alert.V2 exposing
|
|
||||||
( error
|
|
||||||
, success
|
|
||||||
, tip
|
|
||||||
, warning
|
|
||||||
)
|
|
||||||
|
|
||||||
{-| UI components that highlight information to the user.
|
|
||||||
|
|
||||||
@docs error
|
|
||||||
@docs success
|
|
||||||
@docs tip
|
|
||||||
@docs warning
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Accessibility.Styled as Html exposing (Html)
|
|
||||||
import Css
|
|
||||||
import Css.Global
|
|
||||||
import Html.Styled exposing (fromUnstyled)
|
|
||||||
import Html.Styled.Attributes exposing (css)
|
|
||||||
import Markdown
|
|
||||||
import Nri.Ui
|
|
||||||
import Nri.Ui.Colors.V1 as Colors
|
|
||||||
import Nri.Ui.Fonts.V1 as Fonts
|
|
||||||
import Nri.Ui.Icon.V3 as Icon
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
error : { r | exclamation : String } -> String -> Html msg
|
|
||||||
error assets content =
|
|
||||||
alert
|
|
||||||
[ iconContainer [ Css.color Colors.purple ]
|
|
||||||
(Icon.decorativeIcon (Icon.exclamation assets))
|
|
||||||
, viewAlertContent Colors.purpleDark content
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
success : { r | checkmark : String } -> String -> Html msg
|
|
||||||
success assets content =
|
|
||||||
alert
|
|
||||||
[ iconContainer
|
|
||||||
[ Css.color Colors.white
|
|
||||||
, Css.backgroundColor Colors.green
|
|
||||||
, Css.Global.children [ Css.Global.svg [ Css.maxWidth (Css.px 12) ] ]
|
|
||||||
]
|
|
||||||
(Icon.decorativeIcon (Icon.checkMarkSvg assets))
|
|
||||||
, viewAlertContent Colors.greenDarkest content
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
tip : { r | bulb : String } -> String -> Html msg
|
|
||||||
tip assets content =
|
|
||||||
alert
|
|
||||||
[ iconContainer [ Css.color Colors.yellow ]
|
|
||||||
(Icon.decorativeIcon (Icon.bulb assets))
|
|
||||||
, viewAlertContent Colors.navy content
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
warning : { r | exclamation : String } -> String -> Html msg
|
|
||||||
warning assets content =
|
|
||||||
alert
|
|
||||||
[ iconContainer [ Css.color Colors.red ]
|
|
||||||
(Icon.decorativeIcon (Icon.exclamation assets))
|
|
||||||
, viewAlertContent Colors.red content
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
alert : List (Html msg) -> Html msg
|
|
||||||
alert =
|
|
||||||
Nri.Ui.styled Html.div
|
|
||||||
"Nri-Ui-Alert-V2__alert"
|
|
||||||
[ Css.displayFlex
|
|
||||||
, Css.justifyContent Css.start
|
|
||||||
, Css.alignItems Css.center
|
|
||||||
, Css.paddingTop (Css.px 6)
|
|
||||||
, Css.paddingBottom (Css.px 8)
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
|
|
||||||
|
|
||||||
iconContainer : List Css.Style -> Html msg -> Html msg
|
|
||||||
iconContainer styles icon =
|
|
||||||
Nri.Ui.styled Html.div
|
|
||||||
"Nri-Ui-Alert-V2__iconContainer"
|
|
||||||
(styles
|
|
||||||
++ [ -- Content positioning
|
|
||||||
Css.displayFlex
|
|
||||||
, Css.justifyContent Css.center
|
|
||||||
, Css.alignItems Css.center
|
|
||||||
, Css.marginRight (Css.px 5)
|
|
||||||
|
|
||||||
-- Size
|
|
||||||
, Css.borderRadius (Css.px 13)
|
|
||||||
, Css.maxHeight (Css.px 20)
|
|
||||||
, Css.maxWidth (Css.px 20)
|
|
||||||
, Css.minHeight (Css.px 20)
|
|
||||||
, Css.minWidth (Css.px 20)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
[]
|
|
||||||
[ icon ]
|
|
||||||
|
|
||||||
|
|
||||||
viewAlertContent : Css.ColorValue compatible -> String -> Html.Styled.Html msg
|
|
||||||
viewAlertContent color content =
|
|
||||||
Nri.Ui.styled Html.div
|
|
||||||
"Nri-Ui-Alert-V2__viewAlertContent"
|
|
||||||
[ Css.color color
|
|
||||||
, Fonts.baseFont
|
|
||||||
, Css.fontSize (Css.px 13)
|
|
||||||
, Css.lineHeight (Css.num 1.2)
|
|
||||||
, Css.listStyleType Css.none
|
|
||||||
, Css.Global.descendants [ Css.Global.p [ Css.margin Css.zero ] ]
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
(Markdown.toHtml Nothing content |> List.map fromUnstyled)
|
|
@ -1,156 +0,0 @@
|
|||||||
module Nri.Ui.Alert.V3 exposing
|
|
||||||
( error
|
|
||||||
, success
|
|
||||||
, tip
|
|
||||||
, warning
|
|
||||||
)
|
|
||||||
|
|
||||||
{-| UI components that highlight information to the user.
|
|
||||||
|
|
||||||
@docs error
|
|
||||||
@docs success
|
|
||||||
@docs tip
|
|
||||||
@docs warning
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Accessibility.Styled as Html exposing (Html)
|
|
||||||
import Css
|
|
||||||
import Css.Global
|
|
||||||
import Html.Styled exposing (fromUnstyled)
|
|
||||||
import Html.Styled.Attributes exposing (css)
|
|
||||||
import Markdown
|
|
||||||
import Nri.Ui
|
|
||||||
import Nri.Ui.Colors.V1 as Colors
|
|
||||||
import Nri.Ui.Fonts.V1 as Fonts
|
|
||||||
import Nri.Ui.Icon.V3 as Icon
|
|
||||||
import Nri.Ui.SpriteSheet exposing (bulb, checkmark, exclamationMark)
|
|
||||||
import Nri.Ui.Svg.V1 as NriSvg exposing (Svg)
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
error : String -> Html msg
|
|
||||||
error content =
|
|
||||||
alert
|
|
||||||
[ exclamation Colors.purple
|
|
||||||
, viewAlertContent Colors.purpleDark content
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
success : String -> Html msg
|
|
||||||
success content =
|
|
||||||
alert
|
|
||||||
[ iconContainer
|
|
||||||
[ Css.color Colors.white
|
|
||||||
, Css.backgroundColor Colors.green
|
|
||||||
]
|
|
||||||
(Html.div
|
|
||||||
[ css
|
|
||||||
[ Css.width (Css.px 12)
|
|
||||||
, Css.height (Css.px 12)
|
|
||||||
, Css.margin Css.auto
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ NriSvg.toHtml checkmark ]
|
|
||||||
)
|
|
||||||
, viewAlertContent Colors.greenDarkest content
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
tip : String -> Html msg
|
|
||||||
tip content =
|
|
||||||
alert
|
|
||||||
[ iconContainer [ Css.color Colors.yellow ] (NriSvg.toHtml bulb)
|
|
||||||
, viewAlertContent Colors.navy content
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
warning : String -> Html msg
|
|
||||||
warning content =
|
|
||||||
alert
|
|
||||||
[ exclamation Colors.red
|
|
||||||
, viewAlertContent Colors.red content
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
alert : List (Html msg) -> Html msg
|
|
||||||
alert =
|
|
||||||
Nri.Ui.styled Html.div
|
|
||||||
"Nri-Ui-Alert-V3__alert"
|
|
||||||
[ Css.displayFlex
|
|
||||||
, Css.justifyContent Css.start
|
|
||||||
, Css.alignItems Css.center
|
|
||||||
, Css.paddingTop (Css.px 6)
|
|
||||||
, Css.paddingBottom (Css.px 8)
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
|
|
||||||
|
|
||||||
exclamation : Css.Color -> Html msg
|
|
||||||
exclamation backgroundColor =
|
|
||||||
iconContainer
|
|
||||||
[ Css.color Colors.white
|
|
||||||
, Css.backgroundColor backgroundColor
|
|
||||||
]
|
|
||||||
(Html.div
|
|
||||||
[ css [ Css.marginTop (Css.px 1), Css.height (Css.px 13) ] ]
|
|
||||||
[ NriSvg.toHtml exclamationMark ]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
iconContainer : List Css.Style -> Html msg -> Html msg
|
|
||||||
iconContainer styles icon =
|
|
||||||
Nri.Ui.styled Html.div
|
|
||||||
"Nri-Ui-Alert-V3__iconContainer"
|
|
||||||
(styles
|
|
||||||
++ [ -- Content positioning
|
|
||||||
Css.marginRight (Css.px 5)
|
|
||||||
|
|
||||||
-- Size
|
|
||||||
, Css.borderRadius (Css.px 13)
|
|
||||||
, Css.lineHeight iconContainerSize
|
|
||||||
, Css.maxHeight iconContainerSize
|
|
||||||
, Css.maxWidth iconContainerSize
|
|
||||||
, Css.minHeight iconContainerSize
|
|
||||||
, Css.minWidth iconContainerSize
|
|
||||||
]
|
|
||||||
)
|
|
||||||
[]
|
|
||||||
[ icon ]
|
|
||||||
|
|
||||||
|
|
||||||
viewAlertContent : Css.ColorValue compatible -> String -> Html.Styled.Html msg
|
|
||||||
viewAlertContent color content =
|
|
||||||
Nri.Ui.styled Html.div
|
|
||||||
"Nri-Ui-Alert-V3__viewAlertContent"
|
|
||||||
[ Css.color color
|
|
||||||
, Fonts.baseFont
|
|
||||||
, Css.fontSize (Css.px 13)
|
|
||||||
, Css.lineHeight iconContainerSize
|
|
||||||
, Css.listStyleType Css.none
|
|
||||||
|
|
||||||
-- This global selector and overrides are necessary due to
|
|
||||||
-- old stylesheets used on the monolith that set the
|
|
||||||
-- `.txt p { font-size: 18px; }` -- without these overrides,
|
|
||||||
-- we may see giant ugly alerts.
|
|
||||||
-- Remove these if you want to! but be emotionally prepped
|
|
||||||
-- to deal with visual regressions. 🙏
|
|
||||||
, Css.Global.descendants
|
|
||||||
[ Css.Global.p
|
|
||||||
[ Css.margin Css.zero
|
|
||||||
, Css.lineHeight iconContainerSize
|
|
||||||
, Css.fontSize (Css.px 13)
|
|
||||||
, Fonts.baseFont
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
(Markdown.toHtml Nothing content |> List.map fromUnstyled)
|
|
||||||
|
|
||||||
|
|
||||||
iconContainerSize : Css.Px
|
|
||||||
iconContainerSize =
|
|
||||||
Css.px 20
|
|
@ -1,114 +0,0 @@
|
|||||||
module Nri.Ui.BannerAlert.V2 exposing
|
|
||||||
( error
|
|
||||||
, neutral
|
|
||||||
, success
|
|
||||||
)
|
|
||||||
|
|
||||||
{-|
|
|
||||||
|
|
||||||
@docs error
|
|
||||||
@docs neutral
|
|
||||||
@docs success
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Accessibility.Styled as Accessibility
|
|
||||||
import Css exposing (..)
|
|
||||||
import Css.Global exposing (Snippet, children, descendants, everything, selector)
|
|
||||||
import Html.Styled as Html exposing (Html)
|
|
||||||
import Nri.Ui.Colors.V1
|
|
||||||
import Nri.Ui.Fonts.V1
|
|
||||||
|
|
||||||
|
|
||||||
{-| A banner to show error alerts
|
|
||||||
-}
|
|
||||||
error : String -> Html msg
|
|
||||||
error =
|
|
||||||
banner errorStyles
|
|
||||||
|
|
||||||
|
|
||||||
{-| A banner to show neutral alerts
|
|
||||||
-}
|
|
||||||
neutral : String -> Html msg
|
|
||||||
neutral =
|
|
||||||
banner neutralStyles
|
|
||||||
|
|
||||||
|
|
||||||
{-| A banner for success alerts
|
|
||||||
-}
|
|
||||||
success : String -> Html msg
|
|
||||||
success =
|
|
||||||
banner successStyles
|
|
||||||
|
|
||||||
|
|
||||||
banner : Css.Style -> String -> Html msg
|
|
||||||
banner bannerType alertMessage =
|
|
||||||
Html.styled Accessibility.div
|
|
||||||
[ bannerStyles, bannerType ]
|
|
||||||
[]
|
|
||||||
[ notification alertMessage ]
|
|
||||||
|
|
||||||
|
|
||||||
notification : String -> Html msg
|
|
||||||
notification message =
|
|
||||||
Html.styled Html.div [ alertMessageStyles ] [] [ Accessibility.text message ]
|
|
||||||
|
|
||||||
|
|
||||||
type CssClasses
|
|
||||||
= AlertMessage
|
|
||||||
| Banner
|
|
||||||
| Error
|
|
||||||
| Neutral
|
|
||||||
| Success
|
|
||||||
|
|
||||||
|
|
||||||
alertMessageStyles : Style
|
|
||||||
alertMessageStyles =
|
|
||||||
batch
|
|
||||||
[ Css.fontSize (Css.px 20)
|
|
||||||
, Css.fontWeight (Css.int 700)
|
|
||||||
, Css.lineHeight (Css.px 25)
|
|
||||||
, Css.maxWidth (Css.px 600)
|
|
||||||
, Nri.Ui.Fonts.V1.baseFont
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
bannerStyles : Style
|
|
||||||
bannerStyles =
|
|
||||||
batch
|
|
||||||
[ Css.alignItems Css.center
|
|
||||||
, Css.displayFlex
|
|
||||||
, Css.justifyContent Css.center
|
|
||||||
, Css.padding (Css.px 20)
|
|
||||||
, Css.width (Css.pct 100)
|
|
||||||
, Css.Global.children
|
|
||||||
[ Css.Global.button
|
|
||||||
[ Css.position Css.absolute
|
|
||||||
, Css.right (Css.px 15)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
errorStyles : Style
|
|
||||||
errorStyles =
|
|
||||||
batch
|
|
||||||
[ Css.backgroundColor Nri.Ui.Colors.V1.purpleLight
|
|
||||||
, Css.color Nri.Ui.Colors.V1.purpleDark
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
neutralStyles : Style
|
|
||||||
neutralStyles =
|
|
||||||
batch
|
|
||||||
[ Css.backgroundColor Nri.Ui.Colors.V1.frost
|
|
||||||
, Css.color Nri.Ui.Colors.V1.navy
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
successStyles : Style
|
|
||||||
successStyles =
|
|
||||||
batch
|
|
||||||
[ Css.backgroundColor Nri.Ui.Colors.V1.greenLightest
|
|
||||||
, Css.color Nri.Ui.Colors.V1.greenDarkest
|
|
||||||
]
|
|
@ -1,138 +0,0 @@
|
|||||||
module Nri.Ui.BannerAlert.V3 exposing (error, neutral, success)
|
|
||||||
|
|
||||||
{-|
|
|
||||||
|
|
||||||
@docs error, neutral, success
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Accessibility.Styled as Html exposing (Html)
|
|
||||||
import Css
|
|
||||||
import Css.Global
|
|
||||||
import Html.Styled.Attributes as Attributes exposing (css)
|
|
||||||
import Nri.Ui.Colors.V1 as Colors
|
|
||||||
import Nri.Ui.Fonts.V1
|
|
||||||
import Nri.Ui.SpriteSheet exposing (bulb, checkmark, exclamationMark)
|
|
||||||
import Nri.Ui.Svg.V1 as NriSvg exposing (Svg)
|
|
||||||
|
|
||||||
|
|
||||||
{-| A banner to show error alerts
|
|
||||||
-}
|
|
||||||
error : String -> Html msg
|
|
||||||
error =
|
|
||||||
banner
|
|
||||||
{ backgroundColor = Colors.purpleLight
|
|
||||||
, color = Colors.purpleDark
|
|
||||||
, icon =
|
|
||||||
{ backgroundColor = Colors.purple
|
|
||||||
, height = Css.px 25
|
|
||||||
, asset = exclamationMark
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| A banner to show neutral alerts
|
|
||||||
-}
|
|
||||||
neutral : String -> Html msg
|
|
||||||
neutral =
|
|
||||||
banner
|
|
||||||
{ backgroundColor = Colors.frost
|
|
||||||
, color = Colors.navy
|
|
||||||
, icon =
|
|
||||||
{ backgroundColor = Colors.navy
|
|
||||||
, height = Css.px 32
|
|
||||||
, asset = bulb
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| A banner for success alerts
|
|
||||||
-}
|
|
||||||
success : String -> Html msg
|
|
||||||
success =
|
|
||||||
banner
|
|
||||||
{ backgroundColor = Colors.greenLightest
|
|
||||||
, color = Colors.greenDarkest
|
|
||||||
, icon =
|
|
||||||
{ backgroundColor = Colors.green
|
|
||||||
, height = Css.px 20
|
|
||||||
, asset = checkmark
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type alias Config =
|
|
||||||
{ color : Css.Color
|
|
||||||
, backgroundColor : Css.Color
|
|
||||||
, icon : IconConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
banner : Config -> String -> Html msg
|
|
||||||
banner config alertMessage =
|
|
||||||
Html.div
|
|
||||||
[ css
|
|
||||||
[ Css.alignItems Css.center
|
|
||||||
, Css.displayFlex
|
|
||||||
, Css.justifyContent Css.center
|
|
||||||
, Css.padding (Css.px 20)
|
|
||||||
, Css.width (Css.pct 100)
|
|
||||||
, Css.Global.children
|
|
||||||
[ Css.Global.button
|
|
||||||
[ Css.position Css.absolute
|
|
||||||
, Css.right (Css.px 15)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, Css.backgroundColor config.backgroundColor
|
|
||||||
, Css.color config.color
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ icon config.icon
|
|
||||||
, notification alertMessage
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
type alias IconConfig =
|
|
||||||
{ backgroundColor : Css.Color
|
|
||||||
, height : Css.Px
|
|
||||||
, asset : Svg
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
icon : IconConfig -> Html msg
|
|
||||||
icon config =
|
|
||||||
Html.div
|
|
||||||
[ css
|
|
||||||
[ Css.boxSizing Css.borderBox
|
|
||||||
, Css.borderRadius (Css.pct 50)
|
|
||||||
, Css.color Colors.white
|
|
||||||
, Css.displayFlex
|
|
||||||
, Css.alignItems Css.center
|
|
||||||
, Css.justifyContent Css.center
|
|
||||||
, Css.width (Css.px 50)
|
|
||||||
, Css.height (Css.px 50)
|
|
||||||
, Css.marginRight (Css.px 20)
|
|
||||||
, Css.padding (Css.px 8)
|
|
||||||
, Css.flexShrink (Css.num 0)
|
|
||||||
, Css.backgroundColor config.backgroundColor
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ Html.div
|
|
||||||
[ css [ Css.height config.height ]
|
|
||||||
]
|
|
||||||
[ NriSvg.toHtml config.asset ]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
notification : String -> Html msg
|
|
||||||
notification message =
|
|
||||||
Html.div
|
|
||||||
[ css
|
|
||||||
[ Css.fontSize (Css.px 20)
|
|
||||||
, Css.fontWeight (Css.int 700)
|
|
||||||
, Css.lineHeight (Css.px 25)
|
|
||||||
, Css.maxWidth (Css.px 600)
|
|
||||||
, Nri.Ui.Fonts.V1.baseFont
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ Html.text message ]
|
|
@ -1,780 +0,0 @@
|
|||||||
module Nri.Ui.Button.V3 exposing
|
|
||||||
( ButtonSize(..), ButtonStyle(..), ButtonState(..), ButtonContent
|
|
||||||
, ButtonConfig, button, customButton, delete, copyToClipboard, ToggleButtonConfig, toggleButton
|
|
||||||
, LinkConfig, link, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
|
||||||
)
|
|
||||||
|
|
||||||
{-|
|
|
||||||
|
|
||||||
|
|
||||||
# Changes from V2:
|
|
||||||
|
|
||||||
- Uses Html.Styled
|
|
||||||
- Removes buttonDeprecated
|
|
||||||
- Removes Tiny size
|
|
||||||
- Removes one-off Active hack
|
|
||||||
- Removes "submit" button - we just used that for forms that were partially in Elm
|
|
||||||
|
|
||||||
|
|
||||||
# About:
|
|
||||||
|
|
||||||
Common NoRedInk buttons. For accessibility purposes, buttons that perform an
|
|
||||||
action on the current page should be HTML `<button>` elements and are created here
|
|
||||||
with `*Button` functions. Buttons that take the user to a new page should be
|
|
||||||
HTML `<a>` elements and are created here with `*Link` functions. Both versions
|
|
||||||
should be able to use the same CSS class in all cases.
|
|
||||||
|
|
||||||
There will generally be a `*Button` and `*Link` version of each button style.
|
|
||||||
(These will be created as they are needed.)
|
|
||||||
|
|
||||||
|
|
||||||
## Common configs
|
|
||||||
|
|
||||||
@docs ButtonSize, ButtonStyle, ButtonState, ButtonContent
|
|
||||||
|
|
||||||
|
|
||||||
## `<button>` Buttons
|
|
||||||
|
|
||||||
@docs ButtonConfig, button, customButton, delete, copyToClipboard, ToggleButtonConfig, toggleButton
|
|
||||||
|
|
||||||
|
|
||||||
## `<a>` Buttons
|
|
||||||
|
|
||||||
@docs LinkConfig, link, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Accessibility.Styled as Html exposing (Attribute, Html)
|
|
||||||
import Accessibility.Styled.Role as Role
|
|
||||||
import Accessibility.Styled.Widget as Widget
|
|
||||||
import Css exposing (Style)
|
|
||||||
import Css.Global
|
|
||||||
import EventExtras.Styled as EventExtras
|
|
||||||
import Html.Styled as Styled
|
|
||||||
import Html.Styled.Attributes as Attributes
|
|
||||||
import Html.Styled.Events as Events
|
|
||||||
import Json.Decode
|
|
||||||
import Markdown.Block
|
|
||||||
import Markdown.Inline
|
|
||||||
import Nri.Ui
|
|
||||||
import Nri.Ui.AssetPath as AssetPath exposing (Asset)
|
|
||||||
import Nri.Ui.Colors.Extra as ColorsExtra
|
|
||||||
import Nri.Ui.Colors.V1 as Colors
|
|
||||||
import Nri.Ui.Fonts.V1
|
|
||||||
import Nri.Ui.Icon.V3 as Icon exposing (IconType)
|
|
||||||
|
|
||||||
|
|
||||||
{-| Sizes for buttons and links that have button classes
|
|
||||||
-}
|
|
||||||
type ButtonSize
|
|
||||||
= Small
|
|
||||||
| Medium
|
|
||||||
| Large
|
|
||||||
|
|
||||||
|
|
||||||
{-| Styleguide-approved styles for your buttons!
|
|
||||||
|
|
||||||
Note on borderless buttons:
|
|
||||||
A borderless button that performs an action on the current page
|
|
||||||
This button is intended to look like a link.
|
|
||||||
Only use a borderless button when the clickable text in question follows the same layout/margin/padding as a bordered button
|
|
||||||
|
|
||||||
-}
|
|
||||||
type ButtonStyle
|
|
||||||
= Primary
|
|
||||||
| Secondary
|
|
||||||
| Borderless
|
|
||||||
| Danger
|
|
||||||
| Premium
|
|
||||||
|
|
||||||
|
|
||||||
{-| Describes the state of a button. Has consequences for appearance and disabled attribute.
|
|
||||||
|
|
||||||
- Enabled: An enabled button. Takes the appearance of ButtonStyle
|
|
||||||
- Unfulfilled: A button which appears with the InactiveColors palette but is not disabled.
|
|
||||||
- Disabled: A button which appears with the InactiveColors palette and is disabled.
|
|
||||||
- Error: A button which appears with the ErrorColors palette and is disabled.
|
|
||||||
- Loading: A button which appears with the LoadingColors palette and is disabled
|
|
||||||
- Success: A button which appears with the SuccessColors palette and is disabled
|
|
||||||
|
|
||||||
-}
|
|
||||||
type ButtonState
|
|
||||||
= Enabled
|
|
||||||
| Unfulfilled
|
|
||||||
| Disabled
|
|
||||||
| Error
|
|
||||||
| Loading
|
|
||||||
| Success
|
|
||||||
|
|
||||||
|
|
||||||
{-| The part of a button that remains constant through different button states
|
|
||||||
-}
|
|
||||||
type alias ButtonConfig msg =
|
|
||||||
{ onClick : msg
|
|
||||||
, size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, width : Maybe Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| ButtonContent, often changes based on ButtonState. For example, a button in the "Success"
|
|
||||||
state may have a different label than a button in the "Error" state
|
|
||||||
-}
|
|
||||||
type alias ButtonContent =
|
|
||||||
{ label : String
|
|
||||||
, state : ButtonState
|
|
||||||
, icon : Maybe IconType
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| A delightful button which can trigger an effect when clicked!
|
|
||||||
|
|
||||||
This button will trigger the passed-in message if the button state is:
|
|
||||||
|
|
||||||
- Enabled
|
|
||||||
- Unfulfilled
|
|
||||||
|
|
||||||
This button will be Disabled if the button state is:
|
|
||||||
|
|
||||||
- Disabled
|
|
||||||
- Error
|
|
||||||
- Loading
|
|
||||||
- Success
|
|
||||||
|
|
||||||
-}
|
|
||||||
button : ButtonConfig msg -> ButtonContent -> Html msg
|
|
||||||
button config content =
|
|
||||||
customButton [] config content
|
|
||||||
|
|
||||||
|
|
||||||
{-| Exactly the same as button but you can pass in a list of attributes
|
|
||||||
-}
|
|
||||||
customButton : List (Attribute msg) -> ButtonConfig msg -> ButtonContent -> Html msg
|
|
||||||
customButton attributes config content =
|
|
||||||
let
|
|
||||||
buttonStyle_ =
|
|
||||||
case content.state of
|
|
||||||
Enabled ->
|
|
||||||
styleToColorPalette config.style
|
|
||||||
|
|
||||||
Disabled ->
|
|
||||||
InactiveColors
|
|
||||||
|
|
||||||
Error ->
|
|
||||||
ErrorColors
|
|
||||||
|
|
||||||
Unfulfilled ->
|
|
||||||
InactiveColors
|
|
||||||
|
|
||||||
Loading ->
|
|
||||||
LoadingColors
|
|
||||||
|
|
||||||
Success ->
|
|
||||||
SuccessColors
|
|
||||||
|
|
||||||
disabled =
|
|
||||||
case content.state of
|
|
||||||
Enabled ->
|
|
||||||
False
|
|
||||||
|
|
||||||
Disabled ->
|
|
||||||
True
|
|
||||||
|
|
||||||
Error ->
|
|
||||||
True
|
|
||||||
|
|
||||||
Unfulfilled ->
|
|
||||||
False
|
|
||||||
|
|
||||||
Loading ->
|
|
||||||
True
|
|
||||||
|
|
||||||
Success ->
|
|
||||||
True
|
|
||||||
in
|
|
||||||
Nri.Ui.styled Html.button
|
|
||||||
(styledName "customButton")
|
|
||||||
(buttonStyles config.size config.width buttonStyle_ Button)
|
|
||||||
([ Events.onClick config.onClick
|
|
||||||
, Attributes.disabled disabled
|
|
||||||
, Attributes.type_ "button"
|
|
||||||
]
|
|
||||||
++ attributes
|
|
||||||
)
|
|
||||||
(viewLabel content.icon content.label)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- COPY TO CLIPBOARD BUTTON
|
|
||||||
|
|
||||||
|
|
||||||
{-| Config for copyToClipboard
|
|
||||||
-}
|
|
||||||
type alias CopyToClipboardConfig =
|
|
||||||
{ size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, copyText : String
|
|
||||||
, buttonLabel : String
|
|
||||||
, withIcon : Bool
|
|
||||||
, width : Maybe Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| See ui/src/Page/Teach/Courses/Assignments/index.coffee
|
|
||||||
You will need to hook this up to clipboard.js
|
|
||||||
-}
|
|
||||||
copyToClipboard : { r | teach_assignments_copyWhite_svg : Asset } -> CopyToClipboardConfig -> Html msg
|
|
||||||
copyToClipboard assets config =
|
|
||||||
let
|
|
||||||
maybeIcon =
|
|
||||||
if config.withIcon then
|
|
||||||
Just (Icon.copy assets)
|
|
||||||
|
|
||||||
else
|
|
||||||
Nothing
|
|
||||||
in
|
|
||||||
Nri.Ui.styled Html.button
|
|
||||||
(styledName "copyToClipboard")
|
|
||||||
(buttonStyles config.size config.width (styleToColorPalette config.style) Button)
|
|
||||||
[ Widget.label "Copy URL to clipboard"
|
|
||||||
, Attributes.attribute "data-clipboard-text" config.copyText
|
|
||||||
]
|
|
||||||
(viewLabel maybeIcon config.buttonLabel)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- DELETE BUTTON
|
|
||||||
|
|
||||||
|
|
||||||
type alias DeleteButtonConfig msg =
|
|
||||||
{ label : String
|
|
||||||
, onClick : msg
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| A delete button (blue X)
|
|
||||||
-}
|
|
||||||
delete : { r | x : String } -> DeleteButtonConfig msg -> Html msg
|
|
||||||
delete assets config =
|
|
||||||
Nri.Ui.styled Html.button
|
|
||||||
(styledName "delete")
|
|
||||||
[ Css.display Css.inlineBlock
|
|
||||||
, Css.backgroundRepeat Css.noRepeat
|
|
||||||
, Css.backgroundColor Css.transparent
|
|
||||||
, Css.backgroundPosition Css.center
|
|
||||||
, Css.backgroundSize Css.contain
|
|
||||||
, Css.border Css.zero
|
|
||||||
, Css.width (Css.px 15)
|
|
||||||
, Css.height (Css.px 15)
|
|
||||||
, Css.padding Css.zero
|
|
||||||
, Css.margin2 Css.zero (Css.px 6)
|
|
||||||
, Css.cursor Css.pointer
|
|
||||||
, Css.color Colors.azure
|
|
||||||
]
|
|
||||||
[ Events.onClick config.onClick
|
|
||||||
, Attributes.type_ "button"
|
|
||||||
, -- reference: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Labeling_buttons
|
|
||||||
Widget.label config.label
|
|
||||||
]
|
|
||||||
[ Icon.icon { alt = "Delete", icon = Icon.xSvg assets } ]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- TOGGLE BUTTON
|
|
||||||
|
|
||||||
|
|
||||||
{-| Buttons can be toggled into a pressed state and back again.
|
|
||||||
-}
|
|
||||||
type alias ToggleButtonConfig msg =
|
|
||||||
{ label : String
|
|
||||||
, onSelect : msg
|
|
||||||
, onDeselect : msg
|
|
||||||
, pressed : Bool
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
toggleButton : ToggleButtonConfig msg -> Html msg
|
|
||||||
toggleButton config =
|
|
||||||
let
|
|
||||||
toggledStyles =
|
|
||||||
if config.pressed then
|
|
||||||
[ Css.color Colors.gray20
|
|
||||||
, Css.backgroundColor Colors.glacier
|
|
||||||
, Css.boxShadow5 Css.inset Css.zero (Css.px 3) Css.zero (ColorsExtra.withAlpha 0.2 Colors.gray20)
|
|
||||||
, Css.border3 (Css.px 1) Css.solid Colors.azure
|
|
||||||
, Css.fontWeight Css.bold
|
|
||||||
]
|
|
||||||
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
in
|
|
||||||
Nri.Ui.styled Html.button
|
|
||||||
(styledName "toggleButton")
|
|
||||||
(buttonStyles Medium Nothing SecondaryColors Button
|
|
||||||
++ toggledStyles
|
|
||||||
)
|
|
||||||
[ Events.onClick
|
|
||||||
(if config.pressed then
|
|
||||||
config.onDeselect
|
|
||||||
|
|
||||||
else
|
|
||||||
config.onSelect
|
|
||||||
)
|
|
||||||
, Widget.pressed <| Just config.pressed
|
|
||||||
|
|
||||||
-- reference: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Labeling_buttons
|
|
||||||
, Role.button
|
|
||||||
|
|
||||||
-- Note: setting type: 'button' removes the default behavior of submit
|
|
||||||
-- equivalent to preventDefaultBehavior = false
|
|
||||||
-- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
|
|
||||||
, Attributes.type_ "button"
|
|
||||||
]
|
|
||||||
(viewLabel Nothing config.label)
|
|
||||||
|
|
||||||
|
|
||||||
{-| Inputs can be a clickable thing used in a form
|
|
||||||
-}
|
|
||||||
type alias InputConfig =
|
|
||||||
{ content : Html Never
|
|
||||||
, name : String
|
|
||||||
, size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, value : String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- LINKS THAT LOOK LIKE BUTTONS
|
|
||||||
|
|
||||||
|
|
||||||
{-| Links are clickable things with a url.
|
|
||||||
|
|
||||||
NOTE: Links do not support two-line labels.
|
|
||||||
|
|
||||||
-}
|
|
||||||
type alias LinkConfig =
|
|
||||||
{ label : String
|
|
||||||
, icon : Maybe IconType
|
|
||||||
, url : String
|
|
||||||
, size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, width : Maybe Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
|
||||||
some url
|
|
||||||
-}
|
|
||||||
link : LinkConfig -> Html msg
|
|
||||||
link =
|
|
||||||
linkBase "link" [ Attributes.target "_self" ]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Use this link for routing within a single page app.
|
|
||||||
|
|
||||||
This will make a normal <a> tag, but change the Events.onClick behavior to avoid reloading the page.
|
|
||||||
|
|
||||||
See <https://github.com/elm-lang/html/issues/110> for details on this implementation.
|
|
||||||
|
|
||||||
-}
|
|
||||||
linkSpa :
|
|
||||||
(route -> String)
|
|
||||||
-> (route -> msg)
|
|
||||||
->
|
|
||||||
{ label : String
|
|
||||||
, icon : Maybe IconType
|
|
||||||
, size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, width : Maybe Int
|
|
||||||
, route : route
|
|
||||||
}
|
|
||||||
-> Html msg
|
|
||||||
linkSpa toUrl toMsg config =
|
|
||||||
linkBase
|
|
||||||
"linkSpa"
|
|
||||||
[ EventExtras.onClickPreventDefaultForLinkWithHref (toMsg config.route)
|
|
||||||
]
|
|
||||||
{ label = config.label
|
|
||||||
, icon = config.icon
|
|
||||||
, size = config.size
|
|
||||||
, style = config.style
|
|
||||||
, width = config.width
|
|
||||||
, url = toUrl config.route
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
|
||||||
some url and have it open to an external site
|
|
||||||
-}
|
|
||||||
linkExternal : LinkConfig -> Html msg
|
|
||||||
linkExternal =
|
|
||||||
linkBase "linkExternal" [ Attributes.target "_blank" ]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
|
||||||
some url, and it's an HTTP request (Rails includes JS to make this use the given HTTP method)
|
|
||||||
-}
|
|
||||||
linkWithMethod : String -> LinkConfig -> Html msg
|
|
||||||
linkWithMethod method =
|
|
||||||
linkBase "linkWithMethod" [ Attributes.attribute "data-method" method ]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to some url.
|
|
||||||
This should only take in messages that result in a Msg that triggers Analytics.trackAndRedirect. For buttons that trigger other effects on the page, please use Nri.Button.button instead
|
|
||||||
-}
|
|
||||||
linkWithTracking : msg -> LinkConfig -> Html msg
|
|
||||||
linkWithTracking onTrack =
|
|
||||||
linkBase
|
|
||||||
"linkWithTracking"
|
|
||||||
[ Events.preventDefaultOn "click"
|
|
||||||
(Json.Decode.succeed ( onTrack, True ))
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to some url and have it open to an external site
|
|
||||||
|
|
||||||
This should only take in messages that result in tracking events. For buttons that trigger other effects on the page, please use Nri.Ui.Button.V2.button instead
|
|
||||||
|
|
||||||
-}
|
|
||||||
linkExternalWithTracking : msg -> LinkConfig -> Html msg
|
|
||||||
linkExternalWithTracking onTrack =
|
|
||||||
linkBase
|
|
||||||
"linkExternalWithTracking"
|
|
||||||
[ Attributes.target "_blank"
|
|
||||||
, EventExtras.onClickForLinkWithHref onTrack
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Helper function for building links with an arbitrary number of Attributes
|
|
||||||
-}
|
|
||||||
linkBase : String -> List (Attribute msg) -> LinkConfig -> Html msg
|
|
||||||
linkBase linkFunctionName extraAttrs config =
|
|
||||||
Nri.Ui.styled Styled.a
|
|
||||||
(styledName linkFunctionName)
|
|
||||||
(Css.whiteSpace Css.noWrap
|
|
||||||
:: buttonStyles config.size config.width (styleToColorPalette config.style) Anchor
|
|
||||||
)
|
|
||||||
(Attributes.href config.url
|
|
||||||
:: extraAttrs
|
|
||||||
)
|
|
||||||
(viewLabel config.icon config.label)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- HELPERS
|
|
||||||
|
|
||||||
|
|
||||||
type ColorPalette
|
|
||||||
= PrimaryColors
|
|
||||||
| SecondaryColors
|
|
||||||
| BorderlessColors
|
|
||||||
| DangerColors
|
|
||||||
| PremiumColors
|
|
||||||
| InactiveColors
|
|
||||||
| LoadingColors
|
|
||||||
| SuccessColors
|
|
||||||
| ErrorColors
|
|
||||||
|
|
||||||
|
|
||||||
styleToColorPalette : ButtonStyle -> ColorPalette
|
|
||||||
styleToColorPalette style =
|
|
||||||
case style of
|
|
||||||
Primary ->
|
|
||||||
PrimaryColors
|
|
||||||
|
|
||||||
Secondary ->
|
|
||||||
SecondaryColors
|
|
||||||
|
|
||||||
Borderless ->
|
|
||||||
BorderlessColors
|
|
||||||
|
|
||||||
Danger ->
|
|
||||||
DangerColors
|
|
||||||
|
|
||||||
Premium ->
|
|
||||||
PremiumColors
|
|
||||||
|
|
||||||
|
|
||||||
buttonStyles : ButtonSize -> Maybe Int -> ColorPalette -> ElementType -> List Style
|
|
||||||
buttonStyles size width colorPalette elementType =
|
|
||||||
List.concat
|
|
||||||
[ buttonStyle
|
|
||||||
, colorStyle colorPalette
|
|
||||||
, sizeStyle size width elementType
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
viewLabel : Maybe IconType -> String -> List (Html msg)
|
|
||||||
viewLabel icn label =
|
|
||||||
case icn of
|
|
||||||
Nothing ->
|
|
||||||
renderMarkdown label
|
|
||||||
|
|
||||||
Just iconType ->
|
|
||||||
[ Html.span [] (Icon.decorativeIcon iconType :: renderMarkdown label) ]
|
|
||||||
|
|
||||||
|
|
||||||
renderMarkdown : String -> List (Html msg)
|
|
||||||
renderMarkdown markdown =
|
|
||||||
case Markdown.Block.parse Nothing markdown of
|
|
||||||
-- It seems to be always first wrapped in a `Paragraph` and never directly a `PlainInline`
|
|
||||||
[ Markdown.Block.Paragraph _ inlines ] ->
|
|
||||||
List.map (Markdown.Inline.toHtml >> Styled.fromUnstyled) inlines
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
[ Html.text markdown ]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- STYLES
|
|
||||||
|
|
||||||
|
|
||||||
buttonStyle : List Style
|
|
||||||
buttonStyle =
|
|
||||||
[ Css.cursor Css.pointer
|
|
||||||
, Css.display Css.inlineBlock
|
|
||||||
, -- Specifying the font can and should go away after bootstrap is removed from application.css
|
|
||||||
Nri.Ui.Fonts.V1.baseFont
|
|
||||||
, Css.textOverflow Css.ellipsis
|
|
||||||
, Css.overflow Css.hidden
|
|
||||||
, Css.textDecoration Css.none
|
|
||||||
, Css.backgroundImage Css.none
|
|
||||||
, Css.textShadow Css.none
|
|
||||||
, Css.property "transition" "all 0.2s"
|
|
||||||
, Css.boxShadow Css.none
|
|
||||||
, Css.border Css.zero
|
|
||||||
, Css.marginBottom Css.zero
|
|
||||||
, Css.hover [ Css.textDecoration Css.none ]
|
|
||||||
, Css.disabled [ Css.cursor Css.notAllowed ]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
colorStyle : ColorPalette -> List Style
|
|
||||||
colorStyle colorPalette =
|
|
||||||
let
|
|
||||||
( config, additionalStyles ) =
|
|
||||||
case colorPalette of
|
|
||||||
PrimaryColors ->
|
|
||||||
( { background = Colors.azure
|
|
||||||
, hover = Colors.azureDark
|
|
||||||
, text = Colors.white
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.azureDark
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
SecondaryColors ->
|
|
||||||
( { background = Colors.white
|
|
||||||
, hover = Colors.glacier
|
|
||||||
, text = Colors.azure
|
|
||||||
, border = Just <| Colors.azure
|
|
||||||
, shadow = Colors.azure
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
BorderlessColors ->
|
|
||||||
( { background = Css.rgba 0 0 0 0
|
|
||||||
, hover = Css.rgba 0 0 0 0
|
|
||||||
, text = Colors.azure
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Css.rgba 0 0 0 0
|
|
||||||
}
|
|
||||||
, [ Css.hover
|
|
||||||
[ Css.textDecoration Css.underline
|
|
||||||
, Css.disabled [ Css.textDecoration Css.none ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
DangerColors ->
|
|
||||||
( { background = Colors.red
|
|
||||||
, hover = Colors.redDark
|
|
||||||
, text = Colors.white
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.redDark
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
PremiumColors ->
|
|
||||||
( { background = Colors.yellow
|
|
||||||
, hover = Colors.ochre
|
|
||||||
, text = Colors.navy
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.ochre
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
InactiveColors ->
|
|
||||||
( { background = Colors.gray92
|
|
||||||
, hover = Colors.gray92
|
|
||||||
, text = Colors.gray45
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.gray92
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
LoadingColors ->
|
|
||||||
( { background = Colors.glacier
|
|
||||||
, hover = Colors.glacier
|
|
||||||
, text = Colors.navy
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.glacier
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
SuccessColors ->
|
|
||||||
( { background = Colors.greenDark
|
|
||||||
, hover = Colors.greenDark
|
|
||||||
, text = Colors.white
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.greenDark
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
ErrorColors ->
|
|
||||||
( { background = Colors.purple
|
|
||||||
, hover = Colors.purple
|
|
||||||
, text = Colors.white
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.purple
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
in
|
|
||||||
[ Css.batch additionalStyles
|
|
||||||
, Css.color config.text
|
|
||||||
, Css.backgroundColor config.background
|
|
||||||
, Css.fontWeight (Css.int 700)
|
|
||||||
, Css.textAlign Css.center
|
|
||||||
, case config.border of
|
|
||||||
Nothing ->
|
|
||||||
Css.borderStyle Css.none
|
|
||||||
|
|
||||||
Just color ->
|
|
||||||
Css.batch
|
|
||||||
[ Css.borderColor color
|
|
||||||
, Css.borderStyle Css.solid
|
|
||||||
]
|
|
||||||
, Css.borderBottomStyle Css.solid
|
|
||||||
, Css.borderBottomColor config.shadow
|
|
||||||
, Css.fontStyle Css.normal
|
|
||||||
, Css.hover
|
|
||||||
[ Css.color config.text
|
|
||||||
, Css.backgroundColor config.hover
|
|
||||||
, Css.disabled [ Css.backgroundColor config.background ]
|
|
||||||
]
|
|
||||||
, Css.visited [ Css.color config.text ]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
type ElementType
|
|
||||||
= Anchor
|
|
||||||
| Button
|
|
||||||
|
|
||||||
|
|
||||||
sizeStyle : ButtonSize -> Maybe Int -> ElementType -> List Style
|
|
||||||
sizeStyle size width elementType =
|
|
||||||
let
|
|
||||||
config =
|
|
||||||
case size of
|
|
||||||
Small ->
|
|
||||||
{ fontSize = 15
|
|
||||||
, height = 36
|
|
||||||
, imageHeight = 15
|
|
||||||
, shadowHeight = 2
|
|
||||||
, minWidth = 75
|
|
||||||
}
|
|
||||||
|
|
||||||
Medium ->
|
|
||||||
{ fontSize = 17
|
|
||||||
, height = 45
|
|
||||||
, imageHeight = 15
|
|
||||||
, shadowHeight = 3
|
|
||||||
, minWidth = 100
|
|
||||||
}
|
|
||||||
|
|
||||||
Large ->
|
|
||||||
{ fontSize = 20
|
|
||||||
, height = 56
|
|
||||||
, imageHeight = 20
|
|
||||||
, shadowHeight = 4
|
|
||||||
, minWidth = 200
|
|
||||||
}
|
|
||||||
|
|
||||||
widthAttributes =
|
|
||||||
case width of
|
|
||||||
Just pxWidth ->
|
|
||||||
[ Css.maxWidth (Css.pct 100)
|
|
||||||
, Css.width (Css.px <| toFloat pxWidth)
|
|
||||||
]
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
[ Css.padding2 Css.zero (Css.px 16)
|
|
||||||
, Css.minWidth (Css.px config.minWidth)
|
|
||||||
]
|
|
||||||
|
|
||||||
lineHeightPx =
|
|
||||||
case elementType of
|
|
||||||
Anchor ->
|
|
||||||
config.height
|
|
||||||
|
|
||||||
Button ->
|
|
||||||
case size of
|
|
||||||
Small ->
|
|
||||||
15
|
|
||||||
|
|
||||||
Medium ->
|
|
||||||
19
|
|
||||||
|
|
||||||
Large ->
|
|
||||||
22
|
|
||||||
in
|
|
||||||
[ Css.fontSize (Css.px config.fontSize)
|
|
||||||
, Css.borderRadius (Css.px 8)
|
|
||||||
, Css.height (Css.px config.height)
|
|
||||||
, Css.lineHeight (Css.px lineHeightPx)
|
|
||||||
, Css.boxSizing Css.borderBox
|
|
||||||
, Css.borderWidth (Css.px 1)
|
|
||||||
, Css.borderBottomWidth (Css.px config.shadowHeight)
|
|
||||||
, Css.batch widthAttributes
|
|
||||||
, Css.Global.descendants
|
|
||||||
[ Css.Global.img
|
|
||||||
[ Css.height (Css.px config.imageHeight)
|
|
||||||
, Css.marginRight (Css.px <| config.imageHeight / 6)
|
|
||||||
, Css.position Css.relative
|
|
||||||
, Css.bottom (Css.px 2)
|
|
||||||
, Css.verticalAlign Css.middle
|
|
||||||
]
|
|
||||||
, Css.Global.svg
|
|
||||||
[ Css.height (Css.px config.imageHeight) |> Css.important
|
|
||||||
, Css.width (Css.px config.imageHeight) |> Css.important
|
|
||||||
, Css.marginRight (Css.px <| config.imageHeight / 6)
|
|
||||||
, Css.position Css.relative
|
|
||||||
, Css.bottom (Css.px 2)
|
|
||||||
, Css.verticalAlign Css.middle
|
|
||||||
]
|
|
||||||
, Css.Global.svg
|
|
||||||
[ Css.important <| Css.height (Css.px config.imageHeight)
|
|
||||||
, Css.important <| Css.width Css.auto
|
|
||||||
, Css.maxWidth (Css.px (config.imageHeight * 1.25))
|
|
||||||
, Css.paddingRight (Css.px <| config.imageHeight / 6)
|
|
||||||
, Css.position Css.relative
|
|
||||||
, Css.bottom (Css.px 2)
|
|
||||||
, Css.verticalAlign Css.middle
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
styledName : String -> String
|
|
||||||
styledName suffix =
|
|
||||||
"Nri-Ui-Button-V3-" ++ suffix
|
|
@ -1,811 +0,0 @@
|
|||||||
module Nri.Ui.Button.V4 exposing
|
|
||||||
( ButtonSize(..), ButtonWidth(..), ButtonStyle(..), ButtonState(..), ButtonContent
|
|
||||||
, ButtonConfig, button, customButton, delete, copyToClipboard, ToggleButtonConfig, toggleButton
|
|
||||||
, LinkConfig, link, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
|
||||||
)
|
|
||||||
|
|
||||||
{-|
|
|
||||||
|
|
||||||
|
|
||||||
# Changes from V3:
|
|
||||||
|
|
||||||
- Adds `ButtonWidth`.
|
|
||||||
- Button now grows vertically to fit content.
|
|
||||||
To limit the height use attributes on its container or consider truncating content before rendering.
|
|
||||||
|
|
||||||
|
|
||||||
# About:
|
|
||||||
|
|
||||||
Common NoRedInk buttons. For accessibility purposes, buttons that perform an
|
|
||||||
action on the current page should be HTML `<button>` elements and are created here
|
|
||||||
with `*Button` functions. Buttons that take the user to a new page should be
|
|
||||||
HTML `<a>` elements and are created here with `*Link` functions. Both versions
|
|
||||||
should be able to use the same CSS class in all cases.
|
|
||||||
|
|
||||||
There will generally be a `*Button` and `*Link` version of each button style.
|
|
||||||
(These will be created as they are needed.)
|
|
||||||
|
|
||||||
In general a button should never truncate or obscure its contents. This could
|
|
||||||
make it difficult or impossible for a student or teacher to use the site, so in
|
|
||||||
general choose buttons that grow to fit their contents. It is better to risk
|
|
||||||
weird layout than to block users. Might this be a golden rule? Of course there
|
|
||||||
may be exceptions, for example if button content is supplied by an end-user.
|
|
||||||
|
|
||||||
|
|
||||||
## Common configs
|
|
||||||
|
|
||||||
@docs ButtonSize, ButtonWidth, ButtonStyle, ButtonState, ButtonContent
|
|
||||||
|
|
||||||
|
|
||||||
## `<button>` Buttons
|
|
||||||
|
|
||||||
@docs ButtonConfig, button, customButton, delete, copyToClipboard, ToggleButtonConfig, toggleButton
|
|
||||||
|
|
||||||
|
|
||||||
## `<a>` Buttons
|
|
||||||
|
|
||||||
@docs LinkConfig, link, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Accessibility.Styled as Html exposing (Attribute, Html)
|
|
||||||
import Accessibility.Styled.Role as Role
|
|
||||||
import Accessibility.Styled.Widget as Widget
|
|
||||||
import Css exposing (Style)
|
|
||||||
import Css.Global
|
|
||||||
import EventExtras.Styled as EventExtras
|
|
||||||
import Html.Styled as Styled
|
|
||||||
import Html.Styled.Attributes as Attributes
|
|
||||||
import Html.Styled.Events as Events
|
|
||||||
import Json.Decode
|
|
||||||
import Markdown.Block
|
|
||||||
import Markdown.Inline
|
|
||||||
import Nri.Ui
|
|
||||||
import Nri.Ui.AssetPath as AssetPath exposing (Asset)
|
|
||||||
import Nri.Ui.Colors.Extra as ColorsExtra
|
|
||||||
import Nri.Ui.Colors.V1 as Colors
|
|
||||||
import Nri.Ui.Fonts.V1
|
|
||||||
import Nri.Ui.Icon.V3 as Icon exposing (IconType)
|
|
||||||
|
|
||||||
|
|
||||||
{-| Sizes for buttons and links that have button classes
|
|
||||||
-}
|
|
||||||
type ButtonSize
|
|
||||||
= Small
|
|
||||||
| Medium
|
|
||||||
| Large
|
|
||||||
|
|
||||||
|
|
||||||
{-| Width sizing behavior for buttons.
|
|
||||||
|
|
||||||
`WidthExact Int` defines a size in `px` for the button's total width, and
|
|
||||||
`WidthUnbounded` leaves the maxiumum width unbounded (there is a minimum width).
|
|
||||||
|
|
||||||
-}
|
|
||||||
type ButtonWidth
|
|
||||||
= WidthExact Int
|
|
||||||
| WidthUnbounded
|
|
||||||
|
|
||||||
|
|
||||||
{-| Styleguide-approved styles for your buttons!
|
|
||||||
|
|
||||||
Note on borderless buttons:
|
|
||||||
A borderless button that performs an action on the current page
|
|
||||||
This button is intended to look like a link.
|
|
||||||
Only use a borderless button when the clickable text in question follows the same layout/margin/padding as a bordered button
|
|
||||||
|
|
||||||
-}
|
|
||||||
type ButtonStyle
|
|
||||||
= Primary
|
|
||||||
| Secondary
|
|
||||||
| Borderless
|
|
||||||
| Danger
|
|
||||||
| Premium
|
|
||||||
|
|
||||||
|
|
||||||
{-| Describes the state of a button. Has consequences for appearance and disabled attribute.
|
|
||||||
|
|
||||||
- Enabled: An enabled button. Takes the appearance of ButtonStyle
|
|
||||||
- Unfulfilled: A button which appears with the InactiveColors palette but is not disabled.
|
|
||||||
- Disabled: A button which appears with the InactiveColors palette and is disabled.
|
|
||||||
- Error: A button which appears with the ErrorColors palette and is disabled.
|
|
||||||
- Loading: A button which appears with the LoadingColors palette and is disabled
|
|
||||||
- Success: A button which appears with the SuccessColors palette and is disabled
|
|
||||||
|
|
||||||
-}
|
|
||||||
type ButtonState
|
|
||||||
= Enabled
|
|
||||||
| Unfulfilled
|
|
||||||
| Disabled
|
|
||||||
| Error
|
|
||||||
| Loading
|
|
||||||
| Success
|
|
||||||
|
|
||||||
|
|
||||||
{-| The part of a button that remains constant through different button states
|
|
||||||
-}
|
|
||||||
type alias ButtonConfig msg =
|
|
||||||
{ onClick : msg
|
|
||||||
, size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, width : ButtonWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| ButtonContent, often changes based on ButtonState. For example, a button in the "Success"
|
|
||||||
state may have a different label than a button in the "Error" state
|
|
||||||
-}
|
|
||||||
type alias ButtonContent =
|
|
||||||
{ label : String
|
|
||||||
, state : ButtonState
|
|
||||||
, icon : Maybe IconType
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| A delightful button which can trigger an effect when clicked!
|
|
||||||
|
|
||||||
This button will trigger the passed-in message if the button state is:
|
|
||||||
|
|
||||||
- Enabled
|
|
||||||
- Unfulfilled
|
|
||||||
|
|
||||||
This button will be Disabled if the button state is:
|
|
||||||
|
|
||||||
- Disabled
|
|
||||||
- Error
|
|
||||||
- Loading
|
|
||||||
- Success
|
|
||||||
|
|
||||||
-}
|
|
||||||
button : ButtonConfig msg -> ButtonContent -> Html msg
|
|
||||||
button config content =
|
|
||||||
customButton [] config content
|
|
||||||
|
|
||||||
|
|
||||||
{-| Exactly the same as button but you can pass in a list of attributes
|
|
||||||
-}
|
|
||||||
customButton : List (Attribute msg) -> ButtonConfig msg -> ButtonContent -> Html msg
|
|
||||||
customButton attributes config content =
|
|
||||||
let
|
|
||||||
buttonStyle_ =
|
|
||||||
case content.state of
|
|
||||||
Enabled ->
|
|
||||||
styleToColorPalette config.style
|
|
||||||
|
|
||||||
Disabled ->
|
|
||||||
InactiveColors
|
|
||||||
|
|
||||||
Error ->
|
|
||||||
ErrorColors
|
|
||||||
|
|
||||||
Unfulfilled ->
|
|
||||||
InactiveColors
|
|
||||||
|
|
||||||
Loading ->
|
|
||||||
LoadingColors
|
|
||||||
|
|
||||||
Success ->
|
|
||||||
SuccessColors
|
|
||||||
|
|
||||||
disabled =
|
|
||||||
case content.state of
|
|
||||||
Enabled ->
|
|
||||||
False
|
|
||||||
|
|
||||||
Disabled ->
|
|
||||||
True
|
|
||||||
|
|
||||||
Error ->
|
|
||||||
True
|
|
||||||
|
|
||||||
Unfulfilled ->
|
|
||||||
False
|
|
||||||
|
|
||||||
Loading ->
|
|
||||||
True
|
|
||||||
|
|
||||||
Success ->
|
|
||||||
True
|
|
||||||
in
|
|
||||||
Nri.Ui.styled Html.button
|
|
||||||
(styledName "customButton")
|
|
||||||
(buttonStyles config.size config.width buttonStyle_ Button)
|
|
||||||
([ Events.onClick config.onClick
|
|
||||||
, Attributes.disabled disabled
|
|
||||||
, Attributes.type_ "button"
|
|
||||||
]
|
|
||||||
++ attributes
|
|
||||||
)
|
|
||||||
(viewLabel content.icon content.label)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- COPY TO CLIPBOARD BUTTON
|
|
||||||
|
|
||||||
|
|
||||||
{-| Config for copyToClipboard
|
|
||||||
-}
|
|
||||||
type alias CopyToClipboardConfig =
|
|
||||||
{ size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, copyText : String
|
|
||||||
, buttonLabel : String
|
|
||||||
, withIcon : Bool
|
|
||||||
, width : ButtonWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| See ui/src/Page/Teach/Courses/Assignments/index.coffee
|
|
||||||
You will need to hook this up to clipboard.js
|
|
||||||
-}
|
|
||||||
copyToClipboard : { r | teach_assignments_copyWhite_svg : Asset } -> CopyToClipboardConfig -> Html msg
|
|
||||||
copyToClipboard assets config =
|
|
||||||
let
|
|
||||||
maybeIcon =
|
|
||||||
if config.withIcon then
|
|
||||||
Just (Icon.copy assets)
|
|
||||||
|
|
||||||
else
|
|
||||||
Nothing
|
|
||||||
in
|
|
||||||
Nri.Ui.styled Html.button
|
|
||||||
(styledName "copyToClipboard")
|
|
||||||
(buttonStyles config.size config.width (styleToColorPalette config.style) Button)
|
|
||||||
[ Widget.label "Copy URL to clipboard"
|
|
||||||
, Attributes.attribute "data-clipboard-text" config.copyText
|
|
||||||
]
|
|
||||||
(viewLabel maybeIcon config.buttonLabel)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- DELETE BUTTON
|
|
||||||
|
|
||||||
|
|
||||||
type alias DeleteButtonConfig msg =
|
|
||||||
{ label : String
|
|
||||||
, onClick : msg
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| A delete button (blue X)
|
|
||||||
-}
|
|
||||||
delete : { r | x : String } -> DeleteButtonConfig msg -> Html msg
|
|
||||||
delete assets config =
|
|
||||||
Nri.Ui.styled Html.button
|
|
||||||
(styledName "delete")
|
|
||||||
[ Css.display Css.inlineBlock
|
|
||||||
, Css.backgroundRepeat Css.noRepeat
|
|
||||||
, Css.backgroundColor Css.transparent
|
|
||||||
, Css.backgroundPosition Css.center
|
|
||||||
, Css.backgroundSize Css.contain
|
|
||||||
, Css.border Css.zero
|
|
||||||
, Css.width (Css.px 15)
|
|
||||||
, Css.height (Css.px 15)
|
|
||||||
, Css.padding Css.zero
|
|
||||||
, Css.margin2 Css.zero (Css.px 6)
|
|
||||||
, Css.cursor Css.pointer
|
|
||||||
, Css.color Colors.azure
|
|
||||||
]
|
|
||||||
[ Events.onClick config.onClick
|
|
||||||
, Attributes.type_ "button"
|
|
||||||
, -- reference: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Labeling_buttons
|
|
||||||
Widget.label config.label
|
|
||||||
]
|
|
||||||
[ Icon.icon { alt = "Delete", icon = Icon.xSvg assets } ]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- TOGGLE BUTTON
|
|
||||||
|
|
||||||
|
|
||||||
{-| Buttons can be toggled into a pressed state and back again.
|
|
||||||
-}
|
|
||||||
type alias ToggleButtonConfig msg =
|
|
||||||
{ label : String
|
|
||||||
, onSelect : msg
|
|
||||||
, onDeselect : msg
|
|
||||||
, pressed : Bool
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
toggleButton : ToggleButtonConfig msg -> Html msg
|
|
||||||
toggleButton config =
|
|
||||||
let
|
|
||||||
toggledStyles =
|
|
||||||
if config.pressed then
|
|
||||||
[ Css.color Colors.gray20
|
|
||||||
, Css.backgroundColor Colors.glacier
|
|
||||||
, Css.boxShadow5 Css.inset Css.zero (Css.px 3) Css.zero (ColorsExtra.withAlpha 0.2 Colors.gray20)
|
|
||||||
, Css.border3 (Css.px 1) Css.solid Colors.azure
|
|
||||||
, Css.fontWeight Css.bold
|
|
||||||
]
|
|
||||||
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
in
|
|
||||||
Nri.Ui.styled Html.button
|
|
||||||
(styledName "toggleButton")
|
|
||||||
(buttonStyles Medium WidthUnbounded SecondaryColors Button
|
|
||||||
++ toggledStyles
|
|
||||||
)
|
|
||||||
[ Events.onClick
|
|
||||||
(if config.pressed then
|
|
||||||
config.onDeselect
|
|
||||||
|
|
||||||
else
|
|
||||||
config.onSelect
|
|
||||||
)
|
|
||||||
, Widget.pressed <| Just config.pressed
|
|
||||||
|
|
||||||
-- reference: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Labeling_buttons
|
|
||||||
, Role.button
|
|
||||||
|
|
||||||
-- Note: setting type: 'button' removes the default behavior of submit
|
|
||||||
-- equivalent to preventDefaultBehavior = false
|
|
||||||
-- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
|
|
||||||
, Attributes.type_ "button"
|
|
||||||
]
|
|
||||||
(viewLabel Nothing config.label)
|
|
||||||
|
|
||||||
|
|
||||||
{-| Inputs can be a clickable thing used in a form
|
|
||||||
-}
|
|
||||||
type alias InputConfig =
|
|
||||||
{ content : Html Never
|
|
||||||
, name : String
|
|
||||||
, size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, value : String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- LINKS THAT LOOK LIKE BUTTONS
|
|
||||||
|
|
||||||
|
|
||||||
{-| Links are clickable things with a url.
|
|
||||||
|
|
||||||
NOTE: Links do not support two-line labels.
|
|
||||||
|
|
||||||
-}
|
|
||||||
type alias LinkConfig =
|
|
||||||
{ label : String
|
|
||||||
, icon : Maybe IconType
|
|
||||||
, url : String
|
|
||||||
, size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, width : ButtonWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
|
||||||
some url
|
|
||||||
-}
|
|
||||||
link : LinkConfig -> Html msg
|
|
||||||
link =
|
|
||||||
linkBase "link" [ Attributes.target "_self" ]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Use this link for routing within a single page app.
|
|
||||||
|
|
||||||
This will make a normal <a> tag, but change the Events.onClick behavior to avoid reloading the page.
|
|
||||||
|
|
||||||
See <https://github.com/elm-lang/html/issues/110> for details on this implementation.
|
|
||||||
|
|
||||||
-}
|
|
||||||
linkSpa :
|
|
||||||
(route -> String)
|
|
||||||
-> (route -> msg)
|
|
||||||
->
|
|
||||||
{ label : String
|
|
||||||
, icon : Maybe IconType
|
|
||||||
, size : ButtonSize
|
|
||||||
, style : ButtonStyle
|
|
||||||
, width : ButtonWidth
|
|
||||||
, route : route
|
|
||||||
}
|
|
||||||
-> Html msg
|
|
||||||
linkSpa toUrl toMsg config =
|
|
||||||
linkBase
|
|
||||||
"linkSpa"
|
|
||||||
[ EventExtras.onClickPreventDefaultForLinkWithHref (toMsg config.route)
|
|
||||||
]
|
|
||||||
{ label = config.label
|
|
||||||
, icon = config.icon
|
|
||||||
, size = config.size
|
|
||||||
, style = config.style
|
|
||||||
, width = config.width
|
|
||||||
, url = toUrl config.route
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
|
||||||
some url and have it open to an external site
|
|
||||||
-}
|
|
||||||
linkExternal : LinkConfig -> Html msg
|
|
||||||
linkExternal =
|
|
||||||
linkBase "linkExternal" [ Attributes.target "_blank" ]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
|
||||||
some url, and it's an HTTP request (Rails includes JS to make this use the given HTTP method)
|
|
||||||
-}
|
|
||||||
linkWithMethod : String -> LinkConfig -> Html msg
|
|
||||||
linkWithMethod method =
|
|
||||||
linkBase "linkWithMethod" [ Attributes.attribute "data-method" method ]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to some url.
|
|
||||||
This should only take in messages that result in a Msg that triggers Analytics.trackAndRedirect. For buttons that trigger other effects on the page, please use Nri.Button.button instead
|
|
||||||
-}
|
|
||||||
linkWithTracking : msg -> LinkConfig -> Html msg
|
|
||||||
linkWithTracking onTrack =
|
|
||||||
linkBase
|
|
||||||
"linkWithTracking"
|
|
||||||
[ Events.preventDefaultOn "click"
|
|
||||||
(Json.Decode.succeed ( onTrack, True ))
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to some url and have it open to an external site
|
|
||||||
|
|
||||||
This should only take in messages that result in tracking events. For buttons that trigger other effects on the page, please use Nri.Ui.Button.V2.button instead
|
|
||||||
|
|
||||||
-}
|
|
||||||
linkExternalWithTracking : msg -> LinkConfig -> Html msg
|
|
||||||
linkExternalWithTracking onTrack =
|
|
||||||
linkBase
|
|
||||||
"linkExternalWithTracking"
|
|
||||||
[ Attributes.target "_blank"
|
|
||||||
, EventExtras.onClickForLinkWithHref onTrack
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Helper function for building links with an arbitrary number of Attributes
|
|
||||||
-}
|
|
||||||
linkBase : String -> List (Attribute msg) -> LinkConfig -> Html msg
|
|
||||||
linkBase linkFunctionName extraAttrs config =
|
|
||||||
Nri.Ui.styled Styled.a
|
|
||||||
(styledName linkFunctionName)
|
|
||||||
(Css.whiteSpace Css.noWrap
|
|
||||||
:: buttonStyles config.size config.width (styleToColorPalette config.style) Anchor
|
|
||||||
)
|
|
||||||
(Attributes.href config.url
|
|
||||||
:: extraAttrs
|
|
||||||
)
|
|
||||||
(viewLabel config.icon config.label)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- HELPERS
|
|
||||||
|
|
||||||
|
|
||||||
type ColorPalette
|
|
||||||
= PrimaryColors
|
|
||||||
| SecondaryColors
|
|
||||||
| BorderlessColors
|
|
||||||
| DangerColors
|
|
||||||
| PremiumColors
|
|
||||||
| InactiveColors
|
|
||||||
| LoadingColors
|
|
||||||
| SuccessColors
|
|
||||||
| ErrorColors
|
|
||||||
|
|
||||||
|
|
||||||
styleToColorPalette : ButtonStyle -> ColorPalette
|
|
||||||
styleToColorPalette style =
|
|
||||||
case style of
|
|
||||||
Primary ->
|
|
||||||
PrimaryColors
|
|
||||||
|
|
||||||
Secondary ->
|
|
||||||
SecondaryColors
|
|
||||||
|
|
||||||
Borderless ->
|
|
||||||
BorderlessColors
|
|
||||||
|
|
||||||
Danger ->
|
|
||||||
DangerColors
|
|
||||||
|
|
||||||
Premium ->
|
|
||||||
PremiumColors
|
|
||||||
|
|
||||||
|
|
||||||
buttonStyles : ButtonSize -> ButtonWidth -> ColorPalette -> ElementType -> List Style
|
|
||||||
buttonStyles size width colorPalette elementType =
|
|
||||||
List.concat
|
|
||||||
[ buttonStyle
|
|
||||||
, colorStyle colorPalette
|
|
||||||
, sizeStyle size width elementType
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
viewLabel : Maybe IconType -> String -> List (Html msg)
|
|
||||||
viewLabel icn label =
|
|
||||||
case icn of
|
|
||||||
Nothing ->
|
|
||||||
renderMarkdown label
|
|
||||||
|
|
||||||
Just iconType ->
|
|
||||||
[ Html.span [] (Icon.decorativeIcon iconType :: renderMarkdown label) ]
|
|
||||||
|
|
||||||
|
|
||||||
renderMarkdown : String -> List (Html msg)
|
|
||||||
renderMarkdown markdown =
|
|
||||||
case Markdown.Block.parse Nothing markdown of
|
|
||||||
-- It seems to be always first wrapped in a `Paragraph` and never directly a `PlainInline`
|
|
||||||
[ Markdown.Block.Paragraph _ inlines ] ->
|
|
||||||
List.map (Markdown.Inline.toHtml >> Styled.fromUnstyled) inlines
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
[ Html.text markdown ]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- STYLES
|
|
||||||
|
|
||||||
|
|
||||||
buttonStyle : List Style
|
|
||||||
buttonStyle =
|
|
||||||
[ Css.cursor Css.pointer
|
|
||||||
, Css.display Css.inlineBlock
|
|
||||||
, -- Specifying the font can and should go away after bootstrap is removed from application.css
|
|
||||||
Nri.Ui.Fonts.V1.baseFont
|
|
||||||
, Css.textOverflow Css.ellipsis
|
|
||||||
, Css.overflow Css.hidden
|
|
||||||
, Css.textDecoration Css.none
|
|
||||||
, Css.backgroundImage Css.none
|
|
||||||
, Css.textShadow Css.none
|
|
||||||
, Css.property "transition" "all 0.2s"
|
|
||||||
, Css.boxShadow Css.none
|
|
||||||
, Css.border Css.zero
|
|
||||||
, Css.marginBottom Css.zero
|
|
||||||
, Css.hover [ Css.textDecoration Css.none ]
|
|
||||||
, Css.disabled [ Css.cursor Css.notAllowed ]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
colorStyle : ColorPalette -> List Style
|
|
||||||
colorStyle colorPalette =
|
|
||||||
let
|
|
||||||
( config, additionalStyles ) =
|
|
||||||
case colorPalette of
|
|
||||||
PrimaryColors ->
|
|
||||||
( { background = Colors.azure
|
|
||||||
, hover = Colors.azureDark
|
|
||||||
, text = Colors.white
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.azureDark
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
SecondaryColors ->
|
|
||||||
( { background = Colors.white
|
|
||||||
, hover = Colors.glacier
|
|
||||||
, text = Colors.azure
|
|
||||||
, border = Just <| Colors.azure
|
|
||||||
, shadow = Colors.azure
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
BorderlessColors ->
|
|
||||||
( { background = Css.rgba 0 0 0 0
|
|
||||||
, hover = Css.rgba 0 0 0 0
|
|
||||||
, text = Colors.azure
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Css.rgba 0 0 0 0
|
|
||||||
}
|
|
||||||
, [ Css.hover
|
|
||||||
[ Css.textDecoration Css.underline
|
|
||||||
, Css.disabled [ Css.textDecoration Css.none ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
DangerColors ->
|
|
||||||
( { background = Colors.red
|
|
||||||
, hover = Colors.redDark
|
|
||||||
, text = Colors.white
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.redDark
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
PremiumColors ->
|
|
||||||
( { background = Colors.yellow
|
|
||||||
, hover = Colors.ochre
|
|
||||||
, text = Colors.navy
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.ochre
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
InactiveColors ->
|
|
||||||
( { background = Colors.gray92
|
|
||||||
, hover = Colors.gray92
|
|
||||||
, text = Colors.gray45
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.gray92
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
LoadingColors ->
|
|
||||||
( { background = Colors.glacier
|
|
||||||
, hover = Colors.glacier
|
|
||||||
, text = Colors.navy
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.glacier
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
SuccessColors ->
|
|
||||||
( { background = Colors.greenDark
|
|
||||||
, hover = Colors.greenDark
|
|
||||||
, text = Colors.white
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.greenDark
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
|
|
||||||
ErrorColors ->
|
|
||||||
( { background = Colors.purple
|
|
||||||
, hover = Colors.purple
|
|
||||||
, text = Colors.white
|
|
||||||
, border = Nothing
|
|
||||||
, shadow = Colors.purple
|
|
||||||
}
|
|
||||||
, []
|
|
||||||
)
|
|
||||||
in
|
|
||||||
[ Css.batch additionalStyles
|
|
||||||
, Css.color config.text
|
|
||||||
, Css.backgroundColor config.background
|
|
||||||
, Css.fontWeight (Css.int 700)
|
|
||||||
, Css.textAlign Css.center
|
|
||||||
, case config.border of
|
|
||||||
Nothing ->
|
|
||||||
Css.borderStyle Css.none
|
|
||||||
|
|
||||||
Just color ->
|
|
||||||
Css.batch
|
|
||||||
[ Css.borderColor color
|
|
||||||
, Css.borderStyle Css.solid
|
|
||||||
]
|
|
||||||
, Css.borderBottomStyle Css.solid
|
|
||||||
, Css.borderBottomColor config.shadow
|
|
||||||
, Css.fontStyle Css.normal
|
|
||||||
, Css.hover
|
|
||||||
[ Css.color config.text
|
|
||||||
, Css.backgroundColor config.hover
|
|
||||||
, Css.disabled [ Css.backgroundColor config.background ]
|
|
||||||
]
|
|
||||||
, Css.visited [ Css.color config.text ]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
type ElementType
|
|
||||||
= Anchor
|
|
||||||
| Button
|
|
||||||
|
|
||||||
|
|
||||||
sizeStyle : ButtonSize -> ButtonWidth -> ElementType -> List Style
|
|
||||||
sizeStyle size width elementType =
|
|
||||||
let
|
|
||||||
config =
|
|
||||||
case size of
|
|
||||||
Small ->
|
|
||||||
{ fontSize = 15
|
|
||||||
, height = 36
|
|
||||||
, imageHeight = 15
|
|
||||||
, shadowHeight = 2
|
|
||||||
, minWidth = 75
|
|
||||||
}
|
|
||||||
|
|
||||||
Medium ->
|
|
||||||
{ fontSize = 17
|
|
||||||
, height = 45
|
|
||||||
, imageHeight = 15
|
|
||||||
, shadowHeight = 3
|
|
||||||
, minWidth = 100
|
|
||||||
}
|
|
||||||
|
|
||||||
Large ->
|
|
||||||
{ fontSize = 20
|
|
||||||
, height = 56
|
|
||||||
, imageHeight = 20
|
|
||||||
, shadowHeight = 4
|
|
||||||
, minWidth = 200
|
|
||||||
}
|
|
||||||
|
|
||||||
sizingAttributes =
|
|
||||||
case elementType of
|
|
||||||
Button ->
|
|
||||||
let
|
|
||||||
verticalPaddingPx =
|
|
||||||
4
|
|
||||||
in
|
|
||||||
[ Css.minHeight (Css.px config.height)
|
|
||||||
, Css.paddingTop (Css.px verticalPaddingPx)
|
|
||||||
, Css.paddingBottom (Css.px verticalPaddingPx)
|
|
||||||
]
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
[]
|
|
||||||
|
|
||||||
widthAttributes =
|
|
||||||
case width of
|
|
||||||
WidthExact pxWidth ->
|
|
||||||
[ Css.maxWidth (Css.pct 100)
|
|
||||||
, Css.width (Css.px <| toFloat pxWidth)
|
|
||||||
]
|
|
||||||
|
|
||||||
WidthUnbounded ->
|
|
||||||
[ Css.paddingLeft (Css.px 16)
|
|
||||||
, Css.paddingRight (Css.px 16)
|
|
||||||
, Css.minWidth (Css.px config.minWidth)
|
|
||||||
]
|
|
||||||
|
|
||||||
lineHeightPx =
|
|
||||||
case elementType of
|
|
||||||
Anchor ->
|
|
||||||
config.height
|
|
||||||
|
|
||||||
Button ->
|
|
||||||
case size of
|
|
||||||
Small ->
|
|
||||||
15
|
|
||||||
|
|
||||||
Medium ->
|
|
||||||
19
|
|
||||||
|
|
||||||
Large ->
|
|
||||||
22
|
|
||||||
in
|
|
||||||
[ Css.fontSize (Css.px config.fontSize)
|
|
||||||
, Css.borderRadius (Css.px 8)
|
|
||||||
, Css.lineHeight (Css.px lineHeightPx)
|
|
||||||
, Css.boxSizing Css.borderBox
|
|
||||||
, Css.borderWidth (Css.px 1)
|
|
||||||
, Css.borderBottomWidth (Css.px config.shadowHeight)
|
|
||||||
, Css.batch sizingAttributes
|
|
||||||
, Css.batch widthAttributes
|
|
||||||
, Css.Global.descendants
|
|
||||||
[ Css.Global.img
|
|
||||||
[ Css.height (Css.px config.imageHeight)
|
|
||||||
, Css.marginRight (Css.px <| config.imageHeight / 6)
|
|
||||||
, Css.position Css.relative
|
|
||||||
, Css.bottom (Css.px 2)
|
|
||||||
, Css.verticalAlign Css.middle
|
|
||||||
]
|
|
||||||
, Css.Global.svg
|
|
||||||
[ Css.height (Css.px config.imageHeight) |> Css.important
|
|
||||||
, Css.width (Css.px config.imageHeight) |> Css.important
|
|
||||||
, Css.marginRight (Css.px <| config.imageHeight / 6)
|
|
||||||
, Css.position Css.relative
|
|
||||||
, Css.bottom (Css.px 2)
|
|
||||||
, Css.verticalAlign Css.middle
|
|
||||||
]
|
|
||||||
, Css.Global.svg
|
|
||||||
[ Css.important <| Css.height (Css.px config.imageHeight)
|
|
||||||
, Css.important <| Css.width Css.auto
|
|
||||||
, Css.maxWidth (Css.px (config.imageHeight * 1.25))
|
|
||||||
, Css.paddingRight (Css.px <| config.imageHeight / 6)
|
|
||||||
, Css.position Css.relative
|
|
||||||
, Css.bottom (Css.px 2)
|
|
||||||
, Css.verticalAlign Css.middle
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
styledName : String -> String
|
|
||||||
styledName suffix =
|
|
||||||
"Nri-Ui-Button-V4-" ++ suffix
|
|
@ -3,16 +3,10 @@
|
|||||||
"tests": [
|
"tests": [
|
||||||
"Nri.Ui",
|
"Nri.Ui",
|
||||||
"Nri.Ui.Accordion.V1",
|
"Nri.Ui.Accordion.V1",
|
||||||
"Nri.Ui.Alert.V2",
|
|
||||||
"Nri.Ui.Alert.V3",
|
|
||||||
"Nri.Ui.Alert.V4",
|
"Nri.Ui.Alert.V4",
|
||||||
"Nri.Ui.AssetPath",
|
"Nri.Ui.AssetPath",
|
||||||
"Nri.Ui.AssignmentIcon.V1",
|
"Nri.Ui.AssignmentIcon.V1",
|
||||||
"Nri.Ui.BannerAlert.V2",
|
|
||||||
"Nri.Ui.BannerAlert.V3",
|
|
||||||
"Nri.Ui.BannerAlert.V6",
|
"Nri.Ui.BannerAlert.V6",
|
||||||
"Nri.Ui.Button.V3",
|
|
||||||
"Nri.Ui.Button.V4",
|
|
||||||
"Nri.Ui.Button.V5",
|
"Nri.Ui.Button.V5",
|
||||||
"Nri.Ui.Button.V6",
|
"Nri.Ui.Button.V6",
|
||||||
"Nri.Ui.Button.V7",
|
"Nri.Ui.Button.V7",
|
||||||
|
Loading…
Reference in New Issue
Block a user