Merge remote-tracking branch 'origin/master' into tessa/select-with-label

This commit is contained in:
Tessa Kelly 2021-11-08 14:51:16 -08:00
commit 4978d449b5
48 changed files with 751 additions and 183 deletions

View File

@ -3,7 +3,7 @@
"name": "NoRedInk/noredink-ui",
"summary": "UI Widgets we use at NRI",
"license": "BSD-3-Clause",
"version": "14.8.0",
"version": "14.8.1",
"exposed-modules": [
"Nri.Ui",
"Nri.Ui.Accordion.V1",

View File

@ -33,11 +33,7 @@ hint = 'Use Accessibility.Widgetd.Widget'
[forbidden.Html]
hint = 'Use Html.Styled'
usages = [
'styleguide-app/../src/Nri/Ui/Button/V8.elm',
'styleguide-app/Examples/Modal.elm',
'styleguide-app/Main.elm',
]
usages = ['styleguide-app/../src/Nri/Ui/Button/V8.elm']
[forbidden."Nri.Ui.Accordion.V1"]
hint = 'upgrade to V3'

View File

@ -1,7 +1,8 @@
let
sources = import ./nix/sources.nix;
nixpkgs = import sources.nixpkgs { };
niv = import sources.niv { };
system = if builtins.currentSystem == "aarch64-darwin" then "x86_64-darwin" else builtins.currentSystem;
nixpkgs = import sources.nixpkgs { inherit system; };
niv = nixpkgs.callPackage sources.niv { };
in with nixpkgs;
stdenv.mkDerivation {
name = "noredink-ui";

View File

@ -23,7 +23,7 @@ import Nri.Ui.Html.V3 exposing (viewIf)
{-| The default page information is for the button
which will direct the user back to the main page of
the SPA. Specify it's name and the message which will
the SPA. Specify its name and the message which will
navigate to the page.
-}
type alias DefaultPage msg =

View File

@ -1,8 +1,8 @@
module Nri.Ui.Switch.V1 exposing (view, Attribute, onSwitch, disabled, id, label)
module Nri.Ui.Switch.V1 exposing (view, Attribute, onSwitch, disabled, id, label, custom)
{-|
@docs view, Attribute, onSwitch, disabled, id, label
@docs view, Attribute, onSwitch, disabled, id, label, custom
-}
@ -27,6 +27,7 @@ type Attribute msg
| Id String
| Label (Html msg)
| Disabled
| Custom (List (Html.Attribute Never))
{-| Specify what happens when the switch is toggled.
@ -63,10 +64,18 @@ label =
Label
{-| Pass custom attributes through to be attached to the underlying input.
-}
custom : List (Html.Attribute Never) -> Attribute msg
custom =
Custom
type alias Config msg =
{ onSwitch : Maybe (Bool -> msg)
, id : String
, label : Maybe (Html msg)
, attributes : List (Html.Attribute Never)
}
@ -75,6 +84,7 @@ defaultConfig =
{ onSwitch = Nothing
, id = "nri-ui-switch-with-default-id"
, label = Nothing
, attributes = []
}
@ -93,6 +103,9 @@ customize attr config =
Label label_ ->
{ config | label = Just label_ }
Custom custom_ ->
{ config | attributes = custom_ }
{-| Render a switch. The boolean here indicates whether the switch is on
or not.
@ -133,6 +146,7 @@ view attrs isOn =
{ id = config.id
, onCheck = config.onSwitch
, checked = isOn
, attributes = config.attributes
}
, Nri.Ui.Svg.V1.toHtml
(viewSwitch
@ -162,26 +176,29 @@ viewCheckbox :
{ id : String
, onCheck : Maybe (Bool -> msg)
, checked : Bool
, attributes : List (Html.Attribute Never)
}
-> Html msg
viewCheckbox config =
Html.checkbox config.id
(Just config.checked)
[ Attributes.id config.id
, Attributes.css
([ Attributes.id config.id
, Attributes.css
[ Css.position Css.absolute
, Css.top (Css.px 10)
, Css.left (Css.px 10)
, Css.zIndex (Css.int 0)
, Css.opacity (Css.num 0)
]
, case config.onCheck of
, case config.onCheck of
Just onCheck ->
Events.onCheck onCheck
Nothing ->
Widget.disabled True
]
]
++ List.map (Attributes.map never) config.attributes
)
viewSwitch :

View File

@ -770,6 +770,7 @@ resetButton config =
else
Css.top (Css.px 25)
]
, ClickableSvg.custom [ Attributes.type_ "button" ]
]
@ -796,4 +797,5 @@ viewPasswordFloatingContent label toggle config =
Css.top (Css.px 22)
, Css.fontSize (Css.px 13)
]
, ClickableText.custom [ Attributes.type_ "button" ]
]

View File

@ -1,15 +1,22 @@
module Example exposing (Example, view, wrapMsg, wrapState)
module Example exposing (Example, preview, view, wrapMsg, wrapState)
import Category exposing (Category)
import Css exposing (..)
import Css.Global exposing (a, descendants)
import Html.Styled as Html exposing (Html)
import Html.Styled.Attributes as Attributes
import Html.Styled.Events as Events
import Html.Styled.Lazy as Lazy
import KeyboardSupport exposing (KeyboardSupport)
import Nri.Ui.Colors.V1 exposing (..)
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
import Nri.Ui.ClickableText.V3 as ClickableText
import Nri.Ui.Colors.V1 as Colors exposing (..)
import Nri.Ui.Container.V2 as Container
import Nri.Ui.Fonts.V1 as Fonts
import Nri.Ui.Heading.V2 as Heading
import Nri.Ui.Html.Attributes.V2 as AttributeExtras exposing (targetBlank)
import Nri.Ui.UiIcon.V1 as UiIcon
import Routes exposing (Route)
type alias Example state msg =
@ -18,12 +25,18 @@ type alias Example state msg =
, state : state
, update : msg -> state -> ( state, Cmd msg )
, subscriptions : state -> Sub msg
, preview : List (Html Never)
, view : state -> List (Html msg)
, categories : List Category
, keyboardSupport : List KeyboardSupport
}
fullName : Example state msg -> String
fullName example =
"Nri.Ui." ++ example.name ++ ".V" ++ String.fromInt example.version
wrapMsg :
(msg -> msg2)
-> (msg2 -> Maybe msg)
@ -43,6 +56,7 @@ wrapMsg wrapMsg_ unwrapMsg example =
Nothing ->
( state, Cmd.none )
, subscriptions = \state -> Sub.map wrapMsg_ (example.subscriptions state)
, preview = example.preview
, view = \state -> List.map (Html.map wrapMsg_) (example.view state)
, categories = example.categories
, keyboardSupport = example.keyboardSupport
@ -71,6 +85,7 @@ wrapState wrapState_ unwrapState example =
unwrapState
>> Maybe.map example.subscriptions
>> Maybe.withDefault Sub.none
, preview = example.preview
, view =
unwrapState
>> Maybe.map example.view
@ -80,22 +95,77 @@ wrapState wrapState_ unwrapState example =
}
view : Example state msg -> Html msg
view =
Lazy.lazy view_
preview : (Route -> msg2) -> Example state msg -> Html msg2
preview navigate =
Lazy.lazy (preview_ navigate)
preview_ : (Route -> msg2) -> Example state msg -> Html msg2
preview_ navigate example =
Container.view
[ Container.gray
, Container.css
[ Css.flexBasis (Css.px 150)
, Css.hover
[ Css.backgroundColor Colors.glacier
, Css.cursor Css.pointer
]
]
, Container.custom [ Events.onClick (navigate (Routes.Doodad example.name)) ]
, Container.html
(ClickableText.link example.name
[ ClickableText.href (exampleHref example)
, ClickableText.css [ Css.marginBottom (Css.px 10) ]
]
:: [ Html.div
[ Attributes.css
[ Css.displayFlex
, Css.flexDirection Css.column
]
]
(List.map (Html.map never) example.preview)
]
)
]
view : Maybe Route -> Example state msg -> Html msg
view previousRoute example =
Container.view
[ Container.pillow
, Container.css
[ Css.position Css.relative
, Css.margin (Css.px 10)
, Css.minHeight (Css.calc (Css.vh 100) Css.minus (Css.px 20))
, Css.boxSizing Css.borderBox
]
, Container.html
[ Lazy.lazy view_ example
, ClickableSvg.link ("Close " ++ example.name ++ " example")
UiIcon.x
[ ClickableSvg.href
(Maybe.withDefault Routes.All previousRoute
|> Routes.toString
)
, ClickableSvg.small
, ClickableSvg.css
[ Css.position Css.absolute
, Css.top (Css.px 15)
, Css.right (Css.px 15)
]
]
]
]
view_ : Example state msg -> Html msg
view_ example =
let
fullName =
"Nri.Ui." ++ example.name ++ ".V" ++ String.fromInt example.version
in
Html.div
[ -- this class makes the axe accessibility checking output easier to parse
String.replace "." "-" example.name
|> (++) "module-example__"
|> Attributes.class
, Attributes.id (String.replace "." "-" example.name)
]
[ Html.div
[ Attributes.css
@ -107,52 +177,57 @@ view_ example =
, descendants [ Css.Global.a [ textDecoration none ] ]
]
]
[ Html.styled Html.h2
[ color navy
, fontSize (px 20)
, marginTop zero
, marginBottom zero
, Fonts.baseFont
]
[]
[ Html.a
[ Attributes.href ("#/doodad/" ++ example.name)
, Attributes.class "module-example__doodad-link"
, -- this data attribute is used to name the Percy screenshots
String.replace "." "-" example.name
|> Attributes.attribute "data-percy-name"
]
[ Html.text fullName ]
]
, String.replace "." "-" fullName
|> (++) "https://package.elm-lang.org/packages/NoRedInk/noredink-ui/latest/"
|> viewLink "Docs"
, String.replace "." "/" fullName
++ ".elm"
|> (++) "https://github.com/NoRedInk/noredink-ui/blob/master/src/"
|> viewLink "Source"
[ exampleLink example
, docsLink example
, srcLink example
]
, KeyboardSupport.view example.keyboardSupport
, Html.div
[ Attributes.css
[ padding (px 40)
, boxShadow5 zero (px 2) (px 4) zero (rgba 0 0 0 0.25)
, border3 (px 1) solid gray92
, borderRadius (px 20)
, margin3 (px 10) zero (px 40)
, Html.div [] (example.view example.state)
]
exampleHref : Example state msg -> String
exampleHref example =
Routes.toString (Routes.Doodad example.name)
exampleLink : Example state msg -> Html msg
exampleLink example =
Heading.h2 []
[ ClickableText.link (fullName example)
[ ClickableText.href (exampleHref example)
, ClickableText.large
, ClickableText.custom
[ -- this data attribute is used to name the Percy screenshots
String.replace "." "-" example.name
|> Attributes.attribute "data-percy-name"
]
]
(example.view example.state)
]
viewLink : String -> String -> Html msg
viewLink text href =
Html.a
([ Attributes.href href
, Attributes.css [ Css.display Css.block, marginLeft (px 20) ]
]
++ targetBlank
)
[ Html.text text
docsLink : Example state msg -> Html msg
docsLink example =
let
link =
"https://package.elm-lang.org/packages/NoRedInk/noredink-ui/latest/"
++ String.replace "." "-" (fullName example)
in
ClickableText.link "Docs"
[ ClickableText.linkExternal link
, ClickableText.css [ Css.marginLeft (Css.px 20) ]
]
srcLink : Example state msg -> Html msg
srcLink example =
let
link =
String.replace "." "/" (fullName example)
++ ".elm"
|> (++) "https://github.com/NoRedInk/noredink-ui/blob/master/src/"
in
ClickableText.link "Source"
[ ClickableText.linkExternal link
, ClickableText.css [ Css.marginLeft (Css.px 20) ]
]

View File

@ -25,6 +25,7 @@ import Nri.Ui.DisclosureIndicator.V2 as DisclosureIndicator
import Nri.Ui.Fonts.V1 as Fonts
import Nri.Ui.Heading.V2 as Heading
import Nri.Ui.Svg.V1 as Svg
import Nri.Ui.Text.V6 as Text
import Nri.Ui.UiIcon.V1 as UiIcon
import Set exposing (Set)
import Task
@ -38,6 +39,21 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ -- faking a mini version of the Accordion component to give styleguide users a sense of what the
-- component might look like
Html.div []
[ Html.div [ css [ Css.displayFlex, Css.alignItems Css.center ] ]
[ defaultCaret False
, Text.smallBody [ Text.plaintext "Closed" ]
]
, Html.div [ css [ Css.displayFlex, Css.alignItems Css.center ] ]
[ defaultCaret True
, Text.smallBody [ Text.plaintext "Open" ]
]
, Text.caption [ Text.plaintext "Accordion content." ]
]
]
, view = view
, categories = [ Layout ]
, keyboardSupport =
@ -57,13 +73,14 @@ example =
}
defaultCaret : Bool -> Html msg
defaultCaret =
DisclosureIndicator.large [ Css.marginRight (Css.px 8) ]
{-| -}
view : State -> List (Html Msg)
view model =
let
defaultCaret =
DisclosureIndicator.large [ Css.marginRight (Css.px 8) ]
in
[ Heading.h3 [] [ Html.text "Accordion.view" ]
, Accordion.view
{ entries =

View File

@ -33,6 +33,21 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview =
IconExamples.preview
[ AssignmentIcon.planningDiagnosticCircled
, AssignmentIcon.unitDiagnosticCircled
, AssignmentIcon.practiceCircled
, AssignmentIcon.quizCircled
, AssignmentIcon.quickWriteCircled
, AssignmentIcon.guidedDraftCircled
, AssignmentIcon.peerReviewCircled
, AssignmentIcon.selfReviewCircled
, AssignmentIcon.startPrimary
, AssignmentIcon.assessment
, AssignmentIcon.standards
, AssignmentIcon.writing
]
, view =
\_ ->
[ IconExamples.view "Diagnostic"

View File

@ -29,6 +29,14 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ Balloon.balloon
[ Balloon.onTop
, Balloon.navy
, Balloon.paddingPx 15
]
(text "This is a balloon.")
]
, view = view
}

View File

@ -6,6 +6,7 @@ module Examples.Button exposing (Msg, State, example)
-}
import Accessibility.Styled.Key as Key
import Category exposing (Category(..))
import Css exposing (middle, verticalAlign)
import Debug.Control as Control exposing (Control)
@ -28,6 +29,27 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ Button.link "Primary"
[ Button.small
, Button.fillContainerWidth
, Button.custom [ Key.tabbable False ]
]
, Button.link "Secondary"
[ Button.small
, Button.fillContainerWidth
, Button.secondary
, Button.css [ Css.marginTop (Css.px 8) ]
, Button.custom [ Key.tabbable False ]
]
, Button.link "Premium"
[ Button.small
, Button.fillContainerWidth
, Button.premium
, Button.css [ Css.marginTop (Css.px 8) ]
, Button.custom [ Key.tabbable False ]
]
]
, view = \state -> [ viewButtonExamples state ]
, categories = [ Buttons ]
, keyboardSupport = []

View File

@ -38,6 +38,7 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview = []
, view =
\state ->
[ viewInteractableCheckbox "styleguide-checkbox-interactable" state

View File

@ -6,6 +6,7 @@ module Examples.ClickableSvg exposing (Msg, State, example)
-}
import Accessibility.Styled.Key as Key
import Category exposing (Category(..))
import Css
import Debug.Control as Control exposing (Control)
@ -35,6 +36,23 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ ClickableSvg.link "ClickableSvg small"
UiIcon.link
[ ClickableSvg.small
, ClickableSvg.custom [ Key.tabbable False ]
]
, ClickableSvg.link "ClickableSvg medium"
UiIcon.link
[ ClickableSvg.medium
, ClickableSvg.custom [ Key.tabbable False ]
]
, ClickableSvg.link "ClickableSvg large"
UiIcon.link
[ ClickableSvg.large
, ClickableSvg.custom [ Key.tabbable False ]
]
]
, view =
\state ->
let

View File

@ -6,6 +6,7 @@ module Examples.ClickableText exposing (Msg, State, example)
-}
import Accessibility.Styled.Key as Key
import Category exposing (Category(..))
import Css exposing (middle, verticalAlign)
import Debug.Control as Control exposing (Control)
@ -32,6 +33,23 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ ClickableText.link "Small"
[ ClickableText.icon UiIcon.link
, ClickableText.small
, ClickableText.custom [ Key.tabbable False ]
]
, ClickableText.link "Medium"
[ ClickableText.icon UiIcon.link
, ClickableText.medium
, ClickableText.custom [ Key.tabbable False ]
]
, ClickableText.link "Large"
[ ClickableText.icon UiIcon.link
, ClickableText.large
, ClickableText.custom [ Key.tabbable False ]
]
]
, view = \state -> [ viewExamples state ]
, categories = [ Buttons ]
, keyboardSupport = []

View File

@ -14,6 +14,7 @@ import Html.Styled.Attributes as Attributes exposing (css)
import KeyboardSupport exposing (Direction(..), Key(..))
import Nri.Ui.Colors.Extra
import Nri.Ui.Colors.V1 as Colors
import Nri.Ui.Fonts.V1 as Fonts
import Nri.Ui.Heading.V2 as Heading
import SolidColor exposing (highContrast)
@ -41,6 +42,12 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview =
[ ( "green", Colors.green )
, ( "purple", Colors.purple )
, ( "mustard", Colors.mustard )
]
|> List.map viewPreviewSwatch
, view =
\_ ->
[ [ ( "gray20", Colors.gray20, "Main text" )
@ -117,6 +124,22 @@ example =
}
viewPreviewSwatch : ( String, Css.Color ) -> Html.Html msg
viewPreviewSwatch ( name, color ) =
Html.div
[ Attributes.css
[ Css.textAlign Css.center
, Css.padding2 (Css.px 8) Css.zero
, Css.margin2 (Css.px 4) Css.zero
, Css.borderRadius (Css.px 4)
, Css.backgroundColor color
, Css.color color
, Css.fontSize (Css.px 14)
]
]
[ Html.text name ]
viewColors : List ColorExample -> Html.Html msg
viewColors colors =
colors

View File

@ -33,6 +33,7 @@ example =
[ Browser.Events.onResize WindowResized
, Confetti.subscriptions ConfettiMsg state
]
, preview = []
, view =
\state ->
[ Button.button "Launch confetti!"

View File

@ -35,6 +35,17 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ Container.view []
, Container.view
[ Container.invalid
, Container.css [ Css.marginTop (Css.px 8) ]
]
, Container.view
[ Container.disabled
, Container.css [ Css.marginTop (Css.px 8) ]
]
]
, view =
\state ->
let

View File

@ -36,6 +36,12 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ DisclosureIndicator.medium [] False
, DisclosureIndicator.medium [] True
, DisclosureIndicator.large [] False
, DisclosureIndicator.large [] True
]
, view =
\state ->
[ Text.smallBodyGray [ Text.plaintext "The disclosure indicator is only the caret. It is NOT a button -- you must create a button or clickabletext yourself!" ]

View File

@ -35,5 +35,6 @@ example =
, state = {}
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview = [ Divider.view "Dividing Line" ]
, view = \state -> [ Divider.view "Dividing Line" ]
}

View File

@ -7,8 +7,9 @@ module Examples.Fonts exposing (example, State, Msg)
-}
import Category exposing (Category(..))
import Css exposing (Style)
import Example exposing (Example)
import Html.Styled as Html
import Html.Styled as Html exposing (Html)
import Html.Styled.Attributes exposing (css)
import KeyboardSupport exposing (Direction(..), Key(..))
import Nri.Ui.Fonts.V1 as Fonts
@ -35,6 +36,12 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview =
[ ( "baseFont", Fonts.baseFont )
, ( "quizFont", Fonts.quizFont )
, ( "ugFont", Fonts.ugFont )
]
|> List.map viewPreview
, view =
\_ ->
[ Heading.h3 [] [ Html.text "baseFont" ]
@ -48,3 +55,20 @@ example =
[ Html.text "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" ]
]
}
viewPreview : ( String, Style ) -> Html msg
viewPreview ( name, font ) =
Html.div
[ css
[ Css.displayFlex
, Css.justifyContent Css.spaceBetween
, font
, Css.fontSize (Css.px 14)
]
]
[ Html.p [ css [ Css.margin2 (Css.px 8) Css.zero ] ]
[ Html.text name ]
, Html.p [ css [ Css.margin2 (Css.px 8) Css.zero ] ]
[ Html.text "AaBbCc" ]
]

View File

@ -35,6 +35,12 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview =
[ Heading.h1 [] [ Html.text "h1" ]
, Heading.h2 [] [ Html.text "h2" ]
, Heading.h3 [] [ Html.text "h3" ]
, Heading.h4 [] [ Html.text "h4" ]
]
, view =
\_ ->
[ Heading.h1 [] [ Html.text "This is the main page heading." ]

View File

@ -1,4 +1,4 @@
module Examples.IconExamples exposing (view, viewWithCustomStyles)
module Examples.IconExamples exposing (preview, view, viewWithCustomStyles)
import Css
import Html.Styled as Html exposing (Html)
@ -9,6 +9,23 @@ import Nri.Ui.Svg.V1 as Svg
import Nri.Ui.Text.V6 as Text
preview : List Svg.Svg -> List (Html msg)
preview icons =
[ Html.div
[ css
[ Css.displayFlex
, Css.flexWrap Css.wrap
, Css.property "gap" "10px"
, Css.color Colors.gray45
]
]
(List.map
(Svg.withWidth (Css.px 30) >> Svg.withHeight (Css.px 30) >> Svg.toHtml)
icons
)
]
view : String -> List ( String, Svg.Svg ) -> Html msg
view headerText icons =
let

View File

@ -94,6 +94,7 @@ example =
, state = init
, update = update
, subscriptions = subscriptions
, preview = []
, view =
\{ showLoadingFadeIn, showLoading, showSpinners } ->
[ if showLoading then

View File

@ -10,9 +10,12 @@ import Category exposing (Category(..))
import Css
import Example exposing (Example)
import Examples.IconExamples as IconExamples
import Html.Styled as Html exposing (Html)
import Html.Styled.Attributes exposing (css)
import KeyboardSupport exposing (Direction(..), Key(..))
import Nri.Ui.Colors.V1 as Colors
import Nri.Ui.Logo.V1 as Logo
import Nri.Ui.Svg.V1 as Svg
{-| -}
@ -35,6 +38,14 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview =
Html.div [ css [ Css.marginBottom (Css.px 8) ] ] [ Svg.toHtml Logo.noredink ]
:: IconExamples.preview
[ Logo.facebook
, Logo.twitter
, Logo.cleverC
, Logo.googleG
]
, view =
\_ ->
[ IconExamples.viewWithCustomStyles "NRI"

View File

@ -34,6 +34,7 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview = []
, view =
\_ ->
[ IconExamples.view "Levels"

View File

@ -47,6 +47,7 @@ example =
}
, { keys = [ Esc ], result = "Closes the menu" }
]
, preview = []
, view = view
}

View File

@ -177,6 +177,11 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ Message.view [ Message.plaintext "Tiny tip" ]
, Message.view [ Message.success, Message.plaintext "Tiny success" ]
, Message.view [ Message.error, Message.plaintext "Tiny error" ]
]
, view =
\state ->
let

View File

@ -7,22 +7,26 @@ module Examples.Modal exposing (Msg, State, example)
-}
import Accessibility.Styled as Html exposing (Html, div, h3, h4, p, span, text)
import Accessibility.Styled.Key as Key
import Browser.Dom as Dom
import Category exposing (Category(..))
import Css exposing (..)
import Debug.Control as Control exposing (Control)
import Debug.Control.Extra as ControlExtra
import Example exposing (Example)
import Html as Root
import Html.Styled.Attributes as Attributes exposing (css)
import KeyboardSupport exposing (Direction(..), Key(..))
import Nri.Ui.Button.V10 as Button
import Nri.Ui.Checkbox.V5 as Checkbox
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
import Nri.Ui.ClickableText.V3 as ClickableText
import Nri.Ui.Colors.Extra
import Nri.Ui.Colors.V1 as Colors
import Nri.Ui.FocusTrap.V1 as FocusTrap
import Nri.Ui.Fonts.V1 as Fonts
import Nri.Ui.Modal.V11 as Modal
import Nri.Ui.Text.V6 as Text
import Nri.Ui.UiIcon.V1 as UiIcon
import Task
@ -125,6 +129,51 @@ example =
, state = init
, update = update
, subscriptions = subscriptions
, preview =
[ -- faking a mini version of the Modal component to give styleguide users a sense of what the
-- component might look like
div
[ css
[ Css.backgroundColor (Nri.Ui.Colors.Extra.withAlpha 0.9 Colors.navy)
, Css.borderRadius (Css.px 4)
, Css.padding2 (Css.px 25) Css.zero
, Css.displayFlex
, Css.alignItems Css.center
, Css.justifyContent Css.center
]
]
[ div
[ css
[ Css.backgroundColor Colors.white
, Css.padding (Css.px 10)
, Css.borderRadius (Css.px 10)
, Css.boxShadow5 Css.zero (Css.px 1) (Css.px 10) Css.zero (Css.rgba 0 0 0 0.35)
, Css.textAlign Css.center
, Css.color Colors.navy
, Fonts.baseFont
, Css.margin Css.auto
, Css.width (Css.px 100)
, Css.height (Css.px 60)
, Css.fontSize (Css.px 10)
, Css.fontWeight Css.bold
, Css.position Css.relative
]
]
[ text "Modal"
, ClickableSvg.link "Close"
UiIcon.x
[ ClickableSvg.exactWidth 10
, ClickableSvg.exactHeight 10
, ClickableSvg.css
[ Css.position absolute
, Css.top (Css.px 10)
, Css.right (Css.px 10)
]
, ClickableSvg.custom [ Key.tabbable False ]
]
]
]
]
, view =
\state ->
let

View File

@ -17,6 +17,7 @@ import Html.Styled.Attributes exposing (css)
import Http
import KeyboardSupport exposing (Direction(..), Key(..))
import Nri.Ui.Colors.V1 as Colors
import Nri.Ui.Fonts.V1 as Fonts
import Nri.Ui.Heading.V2 as Heading
import Nri.Ui.Page.V3 as Page exposing (RecoveryText(..))
@ -62,6 +63,32 @@ example =
, state = { httpError = CommonControls.httpError, recoveryText = initRecoveryText }
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ -- faking a mini version of the Page component to give styleguide users a sense of what the
-- component might look like
Html.div
[ css
[ Css.displayFlex
, Css.alignItems Css.center
, Css.flexDirection Css.column
, Css.backgroundColor Colors.white
, Css.borderRadius (Css.px 4)
, Css.padding (Css.px 20)
]
]
[ Html.div [ css [ Css.fontSize (Css.px 40) ] ] [ Html.text "😵" ]
, Html.p
[ css
[ Css.color Colors.navy
, Fonts.baseFont
, Css.fontWeight Css.bold
, Css.textAlign Css.center
, Css.margin Css.zero
]
]
[ Html.text "There was a problem!" ]
]
]
, view =
\model ->
let

View File

@ -38,6 +38,12 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview =
IconExamples.preview
[ Pennant.premiumFlag
, Pennant.expiredPremiumFlag
, Pennant.disabledPremiumFlag
]
, view =
\_ ->
[ IconExamples.viewWithCustomStyles "Premium Pennants"

View File

@ -34,6 +34,7 @@ example =
, state = init
, update = update
, subscriptions = subscriptions
, preview = []
, view = view
, categories = [ Inputs ]
, keyboardSupport =

View File

@ -36,6 +36,7 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview = []
, view =
\state ->
let

View File

@ -29,6 +29,7 @@ example =
, subscriptions = \_ -> Sub.none
, categories = [ Inputs ]
, keyboardSupport = []
, preview = []
, view =
\state ->
let

View File

@ -42,6 +42,7 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview = []
, view =
\state ->
[ Keyed.node "div"

View File

@ -40,6 +40,7 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview = []
, view =
\state ->
[ viewModal state.modal

View File

@ -41,6 +41,7 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview = []
, view =
\{ sortState } ->
let

View File

@ -32,6 +32,7 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview = []
, view =
\state ->
[ viewSettings state

View File

@ -6,12 +6,12 @@ module Examples.Switch exposing (Msg, State, example)
-}
import Accessibility.Styled.Key as Key
import Category
import Example exposing (Example)
import Html.Styled as Html
import Nri.Ui.Heading.V2 as Heading
import Nri.Ui.Switch.V1 as Switch
import Nri.Ui.Text.V6 as Text
{-| -}
@ -31,46 +31,47 @@ example =
, state = True
, update = \(Switch new) _ -> ( new, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview =
[ Switch.view
[ Switch.label (Html.text "Toggle On")
, Switch.custom [ Key.tabbable False ]
]
False
, Switch.view
[ Switch.label (Html.text "Toggle Off")
, Switch.custom [ Key.tabbable False ]
]
True
]
, view =
\interactiveIsOn ->
[ Heading.h3 [] [ Html.text "Interactive" ]
, Text.mediumBody
[ Text.html
[ Switch.view
[ Switch.onSwitch Switch
, Switch.id "switch-interactive"
, Switch.label
(if interactiveIsOn then
Html.text "On"
, Switch.view
[ Switch.onSwitch Switch
, Switch.id "switch-interactive"
, Switch.label
(if interactiveIsOn then
Html.text "On"
else
Html.text "Off"
)
]
interactiveIsOn
]
else
Html.text "Off"
)
]
, Heading.h3 [] [ Html.text "Disabled" ]
, Text.mediumBody
[ Text.html
[ Switch.view
[ Switch.disabled
, Switch.id "switch-disabled-on"
, Switch.label (Html.text "Permanently on")
]
True
]
interactiveIsOn
, Heading.h3 [] [ Html.text "Disabled (On)" ]
, Switch.view
[ Switch.disabled
, Switch.id "switch-disabled-on"
, Switch.label (Html.text "Permanently on")
]
, Text.mediumBody
[ Text.html
[ Switch.view
[ Switch.disabled
, Switch.id "switch-disabled-off"
, Switch.label (Html.text "Permanently off")
]
False
]
True
, Heading.h3 [] [ Html.text "Disabled (Off)" ]
, Switch.view
[ Switch.disabled
, Switch.id "switch-disabled-off"
, Switch.label (Html.text "Permanently off")
]
False
]
, categories = [ Category.Inputs ]
, keyboardSupport = [{- TODO -}]

View File

@ -37,6 +37,29 @@ example =
, subscriptions = \_ -> Sub.none
, categories = [ Tables, Layout ]
, keyboardSupport = []
, preview =
[ Table.view
[ Table.string
{ header = "A"
, value = .a
, width = px 50
, cellStyles = always []
}
, Table.string
{ header = "B"
, value = .b
, width = px 50
, cellStyles = always []
}
]
[ { a = "Row 1 A"
, b = "Row 1 B"
}
, { a = "Row 2 A"
, b = "Row 2 B"
}
]
]
, view =
\() ->
let

View File

@ -19,10 +19,13 @@ import Html.Styled as Html exposing (Html, fromUnstyled)
import Html.Styled.Attributes exposing (css)
import KeyboardSupport exposing (Key(..))
import List.Zipper exposing (Zipper)
import Nri.Ui.Colors.V1 as Colors
import Nri.Ui.Svg.V1 as Svg
import Nri.Ui.Tabs.V7 as Tabs exposing (Alignment(..), Tab)
import Nri.Ui.Text.V6 as Text
import Nri.Ui.Tooltip.V2 as Tooltip
import Nri.Ui.UiIcon.V1 as UiIcon
import Routes
import Task
@ -117,9 +120,14 @@ update msg model =
)
exampleName : String
exampleName =
"Tabs"
example : Example State Msg
example =
{ name = "Tabs"
{ name = exampleName
, version = 7
, categories = [ Layout ]
, keyboardSupport =
@ -136,6 +144,49 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ -- faking a mini version of the Tabs component to give styleguide users a sense of what the
-- component might look like
Html.div [ css [ Css.displayFlex, Css.flexWrap Css.wrap ] ]
[ Html.div
[ css
[ Css.backgroundColor Colors.white
, Css.padding (Css.px 4)
, Css.borderRadius4 (Css.px 4) (Css.px 4) Css.zero Css.zero
, Css.border3 (Css.px 1) Css.solid Colors.navy
, Css.borderBottomWidth Css.zero
]
]
[ Text.smallBody [ Text.plaintext "Tab 1" ] ]
, Html.div
[ css [ Css.width (Css.px 4), Css.borderBottom3 (Css.px 1) Css.solid Colors.navy ]
]
[]
, Html.div
[ css
[ Css.backgroundColor Colors.frost
, Css.padding (Css.px 4)
, Css.borderRadius4 (Css.px 4) (Css.px 4) Css.zero Css.zero
, Css.border3 (Css.px 1) Css.solid Colors.navy
]
]
[ Text.smallBody [ Text.plaintext "Tab 1" ] ]
, Html.div
[ css
[ Css.width (Css.px 30)
, Css.borderBottom3 (Css.px 1) Css.solid Colors.navy
]
]
[]
, Html.div
[ css
[ Css.paddingTop (Css.px 4)
, Css.minWidth (Css.px 100)
]
]
[ Text.caption [ Text.plaintext "Tab 1 content" ] ]
]
]
, view =
\model ->
let
@ -167,7 +218,7 @@ allTabs openTooltipId labelledBy =
|> Svg.toHtml
in
[ Tabs.build { id = First, idString = "tab-0" }
([ Tabs.spaHref "/#/doodad/Tabs"
([ Tabs.spaHref <| Routes.toString (Routes.Doodad exampleName)
, Tabs.tabString "1"
, Tabs.withTooltip
[ Tooltip.plaintext "Link Example"

View File

@ -30,6 +30,13 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ ( "caption", Text.caption )
, ( "smallBody", Text.smallBody )
, ( "mediumBody", Text.mediumBody )
, ( "ugMediumBody", Text.ugMediumBody )
]
|> List.map viewPreview
, view =
\state ->
let
@ -57,6 +64,11 @@ example =
}
viewPreview : ( String, List (Text.Attribute msg) -> Html msg ) -> Html msg
viewPreview ( name, view ) =
view [ Text.plaintext name ]
viewExamples : List ( String, List (Text.Attribute msg) -> Html msg ) -> List (Text.Attribute msg) -> Html msg
viewExamples examples attributes =
let

View File

@ -32,6 +32,7 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview = [ TextWriting.footnote [ text "This is a footnote. " ] ]
, view =
\_ ->
let

View File

@ -44,6 +44,7 @@ example =
, subscriptions = \_ -> Sub.none
, categories = [ Inputs ]
, keyboardSupport = []
, preview = []
, view =
\state ->
[ Heading.h1 [] [ Html.text "Textarea controls" ]

View File

@ -7,6 +7,7 @@ module Examples.TextInput exposing (Msg, State, example)
-}
import Accessibility.Styled as Html exposing (..)
import Accessibility.Styled.Key as Key
import Category exposing (Category(..))
import Css exposing (..)
import Debug.Control as Control exposing (Control)
@ -32,6 +33,16 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ TextInput.view "Text Input"
[ TextInput.custom [ Key.tabbable False ]
]
, TextInput.view "Errored"
[ TextInput.value "invalid content"
, TextInput.errorIf True
, TextInput.custom [ Key.tabbable False ]
]
]
, view =
\state ->
let

View File

@ -7,6 +7,7 @@ module Examples.Tooltip exposing (example, State, Msg)
-}
import Accessibility.Styled as Html exposing (Html)
import Accessibility.Styled.Key as Key
import Category exposing (Category(..))
import Css
import Debug.Control as Control exposing (Control)
@ -33,6 +34,32 @@ example =
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[ Html.div
[ css
[ Css.marginTop (Css.px 60)
, Css.alignSelf Css.center
]
]
[ Tooltip.view
{ id = "preview-tooltip"
, trigger =
\attributes ->
ClickableSvg.button "example-preview-tooltip-icon"
UiIcon.gear
[ ClickableSvg.custom attributes
, ClickableSvg.small
, ClickableSvg.custom [ Key.tabbable False ]
]
}
[ Tooltip.plaintext "This is a tooltip."
, Tooltip.open True
, Tooltip.onTop
, Tooltip.smallPadding
, Tooltip.fitToContent
]
]
]
, view = view
}

View File

@ -33,6 +33,21 @@ example =
, state = ()
, update = \_ state -> ( state, Cmd.none )
, subscriptions = \_ -> Sub.none
, preview =
IconExamples.preview
[ UiIcon.seeMore
, UiIcon.archive
, UiIcon.share
, UiIcon.footsteps
, UiIcon.person
, UiIcon.calendar
, UiIcon.missingDocument
, UiIcon.speechBalloon
, UiIcon.edit
, UiIcon.arrowTop
, UiIcon.checkmark
, UiIcon.equals
]
, view =
\_ ->
[ IconExamples.view "Interface"

View File

@ -1,6 +1,6 @@
module Main exposing (init, main)
import Accessibility.Styled as Html exposing (Html, img, text)
import Accessibility.Styled as Html exposing (Html)
import Browser exposing (Document, UrlRequest(..))
import Browser.Dom
import Browser.Navigation exposing (Key)
@ -10,15 +10,16 @@ import Css.Media exposing (withMedia)
import Dict exposing (Dict)
import Example exposing (Example)
import Examples
import Html as RootHtml
import Html.Attributes
import Html.Styled.Attributes as Attributes exposing (..)
import Html.Styled.Events as Events
import Nri.Ui.ClickableText.V3 as ClickableText
import Nri.Ui.Colors.V1 as Colors
import Nri.Ui.CssVendorPrefix.V1 as VendorPrefixed
import Nri.Ui.Fonts.V1 as Fonts
import Nri.Ui.Heading.V2 as Heading
import Nri.Ui.MediaQuery.V1 exposing (mobile, notMobile)
import Nri.Ui.Page.V3 as Page
import Routes as Routes exposing (Route(..))
import Sort.Set as Set exposing (Set)
import Task
@ -40,6 +41,7 @@ main =
type alias Model =
{ -- Global UI
route : Route
, previousRoute : Maybe Route
, moduleStates : Dict String (Example Examples.State Examples.Msg)
, navigationKey : Key
}
@ -48,6 +50,7 @@ type alias Model =
init : () -> Url -> Key -> ( Model, Cmd Msg )
init () url key =
( { route = Routes.fromLocation url
, previousRoute = Nothing
, moduleStates =
Dict.fromList
(List.map (\example -> ( example.name, example )) Examples.all)
@ -61,6 +64,7 @@ type Msg
= UpdateModuleStates String Examples.Msg
| OnUrlRequest Browser.UrlRequest
| OnUrlChange Url
| ChangeRoute Route
| SkipToMainContent
| NoOp
@ -95,7 +99,18 @@ update action model =
( model, Browser.Navigation.load loc )
OnUrlChange route ->
( { model | route = Routes.fromLocation route }, Cmd.none )
( { model
| route = Routes.fromLocation route
, previousRoute = Just model.route
}
, Cmd.none
)
ChangeRoute route ->
( model
, Browser.Navigation.pushUrl model.navigationKey
(Routes.toString route)
)
SkipToMainContent ->
( model
@ -125,69 +140,86 @@ view_ model =
let
examples filterBy =
List.filter (\m -> filterBy m) (Dict.values model.moduleStates)
mainContentHeader heading =
Heading.h1
[ Heading.customAttr (id "maincontent")
, Heading.customAttr (tabindex -1)
, Heading.css [ marginBottom (px 30) ]
]
[ Html.text heading ]
in
case model.route of
Routes.Doodad doodad ->
case List.head (examples (\m -> m.name == doodad)) of
Just example ->
Html.main_ []
[ Example.view model.previousRoute example
|> Html.map (UpdateModuleStates example.name)
]
Nothing ->
Page.notFound
{ link = ChangeRoute Routes.All
, recoveryText = Page.ReturnTo "Component Library"
}
Routes.Category category ->
withSideNav model.route
[ mainContentHeader (Category.forDisplay category)
, examples
(\doodad ->
Set.memberOf
(Set.fromList Category.sorter doodad.categories)
category
)
|> viewPreviews (Category.forId category)
]
Routes.All ->
withSideNav model.route
[ mainContentHeader "All"
, viewPreviews "all" (examples (\_ -> True))
]
withSideNav : Route -> List (Html Msg) -> Html Msg
withSideNav currentRoute content =
Html.div
[ css
[ displayFlex
, withMedia [ mobile ] [ flexDirection column, alignItems stretch ]
, alignItems flexStart
, minHeight (vh 100)
]
]
[ navigation model.route
, Html.main_ [ css [ flexGrow (int 1), sectionStyles ] ]
(case model.route of
Routes.Doodad doodad ->
case List.head (examples (\m -> m.name == doodad)) of
Just example ->
[ mainContentHeader ("Viewing " ++ doodad ++ " doodad only")
, Html.div [ id (String.replace "." "-" example.name) ]
[ Example.view example
|> Html.map (UpdateModuleStates example.name)
]
]
Nothing ->
[ Html.text <| "Oops! We couldn't find " ++ doodad ]
Routes.Category category ->
[ mainContentHeader (Category.forDisplay category)
, examples
(\doodad ->
Set.memberOf
(Set.fromList Category.sorter doodad.categories)
category
)
|> List.map
(\example ->
Example.view example
|> Html.map (UpdateModuleStates example.name)
)
|> Html.div [ id (Category.forId category) ]
]
Routes.All ->
[ mainContentHeader "All"
, examples (\_ -> True)
|> List.map
(\example ->
Example.view example
|> Html.map (UpdateModuleStates example.name)
)
|> Html.div []
]
)
[ navigation currentRoute
, Html.main_
[ css
[ flexGrow (int 1)
, margin2 (px 40) zero
, Css.minHeight (Css.vh 100)
]
]
content
]
mainContentHeader : String -> Html msg
mainContentHeader heading =
Heading.h1
[ Heading.customAttr (id "maincontent")
, Heading.customAttr (tabindex -1)
, Heading.css [ marginBottom (px 30) ]
]
[ Html.text heading ]
viewPreviews : String -> List (Example state msg) -> Html Msg
viewPreviews containerId examples =
examples
|> List.map (\example -> Example.preview ChangeRoute example)
|> Html.div
[ id containerId
, css
[ Css.displayFlex
, Css.flexWrap Css.wrap
, Css.property "gap" "10px"
]
]
navigation : Route -> Html Msg
navigation route =
let
@ -200,31 +232,31 @@ navigation route =
False
link active hash displayName =
Html.a
[ css
[ backgroundColor transparent
, borderStyle none
, textDecoration none
ClickableText.link displayName
[ ClickableText.small
, ClickableText.css
[ Css.color Colors.navy
, Css.display Css.block
, Css.padding (Css.px 8)
, Css.borderRadius (Css.px 8)
, if active then
color Colors.navy
Css.backgroundColor Colors.glacier
else
color Colors.azure
, Fonts.baseFont
Css.batch []
]
, Attributes.href hash
, ClickableText.href hash
]
[ Html.text displayName ]
navLink category =
link (isActive category)
("#/category/" ++ Debug.toString category)
(Routes.toString (Routes.Category category))
(Category.forDisplay category)
toNavLi element =
Html.li
[ css
[ margin2 (px 10) zero
[ margin zero
, listStyle none
, textDecoration none
]
@ -269,18 +301,12 @@ navigation route =
, id "skip"
]
[ Html.text "Skip to main content" ]
, Heading.h4 [] [ Html.text "Categories" ]
, (link (route == Routes.All) "#/" "All"
:: List.map navLink Category.all
)
|> List.map toNavLi
|> Html.ul
[ css [ margin4 zero zero (px 40) zero, padding zero ]
[ css [ margin zero, padding zero ]
, id "categories"
]
]
sectionStyles : Css.Style
sectionStyles =
Css.batch [ margin2 (px 40) zero ]

View File

@ -1,4 +1,4 @@
module Routes exposing (Route(..), fromLocation)
module Routes exposing (Route(..), fromLocation, toString)
import Browser.Navigation as Navigation
import Category
@ -12,6 +12,19 @@ type Route
| All
toString : Route -> String
toString route_ =
case route_ of
Doodad exampleName ->
"#/doodad/" ++ exampleName
Category c ->
"#/category/" ++ Debug.toString c
All ->
"#/"
route : Parser Route
route =
Parser.oneOf