git.iko.soy/rowtype-yoga/ry-blocks
on main help sign in
Refactoring input
commit2b690c5e073b827b99851d97d8a91523e5f56cec authorMark Eibes <mark.eibes@gmail.com> dateTue 29 Dec 2020, 16:33 (6 years ago) parent3c1f4df
6 files changed+272−150
src/Yoga.purs+3−3 src/Yoga/Block/Atom/Button/Style.purs+3−4 src/Yoga/Block/Atom/Input/Story.purs+8−2 src/Yoga/Block/Atom/Input/Style.purs+66−50 src/Yoga/Block/Atom/Input/View.purs+181−91 src/Yoga/Block/Container/Style.purs+11
src/Yoga.purs+3−3
@@ -10,13 +10,13 @@ import React.Basic.Hooks (JSX, ReactComponent)
1010import React.Basic.Hooks as Hooks
1111import Record as Record
1212
13−div :: forall attrs attrs_. Union attrs attrs_ Props_div => ReactComponent (Record attrs)
13+div ∷ ∀ attrs attrs_. Union attrs attrs_ Props_div => ReactComponent (Record attrs)
1414div = R.div'
1515
16−span :: forall attrs attrs_. Union attrs attrs_ Props_span => ReactComponent (Record attrs)
16+span ∷ ∀ attrs attrs_. Union attrs attrs_ Props_span => ReactComponent (Record attrs)
1717span = R.span'
1818
19−button :: forall attrs attrs_. Union attrs attrs_ Props_button => ReactComponent (Record attrs)
19+button ∷ ∀ attrs attrs_. Union attrs attrs_ Props_button => ReactComponent (Record attrs)
2020button = R.button'
2121
2222el ∷
src/Yoga/Block/Atom/Button/Style.purs+3−4
@@ -55,7 +55,8 @@ button =
5555 , """&[data-button-shape="pill"]""":
5656 nest
5757 { borderRadius: str "calc(var(--s1) * 0.85)"
58− , padding: str "calc(var(--s-1) * 0.9) var(--s0)"
58+ , padding: str "calc(var(--s-1) * 0.85) var(--s0)"
59+ , paddingBottom: str "calc(var(--s-1))"
5960 }
6061 , """&[data-button-type="primary"]""":
6162 nest
@@ -95,9 +96,7 @@ button =
9596 }
9697 , """&:active""":
9798 nest
98− { boxShadow:
99− str
100− $ "inset 0 1px var(--s-1) rgba(0,0,0,0.20)"
99+ { boxShadow: str $ "inset 0 1px var(--s-1) rgba(0,0,0,0.20)"
101100 , borderTop: str $ i "1px solid " colour.interfaceBackgroundShadow
102101 , borderBottom: str $ i "1px solid " colour.interfaceBackgroundShadow
103102 , transform: str "scale3d(0.95,0.95,0.95)"
src/Yoga/Block/Atom/Input/Story.purs+8−2
@@ -10,7 +10,7 @@ import React.Basic (JSX, element, fragment)
1010import React.Basic.DOM as R
1111import React.Basic.Emotion as E
1212import React.Basic.Events (handler_)
13−import Yoga (el, (</), (/>), (</>))
13+import Yoga ((/>), (</), (</>))
1414import Yoga.Block as Block
1515import Yoga.Block.Atom.Input as Input
1616import Yoga.Block.Atom.Input.Types as HTMLInput
@@ -58,11 +58,17 @@ input = do
5858 , element Input.component { label: nes (SProxy ∷ _ "Pig nose"), leading: R.text "🌭" }
5959 , element Input.component { label: nes (SProxy ∷ _ "Pig nose"), leading: R.text "⭐", trailing: R.text "🔮" }
6060 ]
61− , R.h2_ [ R.text "[BUG] Overflowing label" ]
61+ , R.h2_ [ R.text "Overflowing label" ]
6262 , element Input.component
6363 { type: HTMLInput.Text
6464 , label: nes (SProxy ∷ _ "Is undefined really a function?")
6565 }
66+ , Input.component </> { type: HTMLInput.Text, label: nes (SProxy ∷ _ "Now this is really just excessively long and you should avoid it.") }
67+ , Input.component
68+ </> { css: E.css { width: E.str "500px" }
69+ , type: HTMLInput.Text
70+ , label: nes (SProxy ∷ _ "You can avoid this problem by setting a custom width")
71+ }
6672 , R.h2_ [ R.text "Password" ]
6773 , element Input.component { type: HTMLInput.Password }
6874 , R.h2_ [ R.text "Text Input" ]
src/Yoga/Block/Atom/Input/Style.purs+66−50
@@ -57,6 +57,7 @@ labelSmall =
5757 { fontSize: var "--s-1"
5858 , marginTop: str "calc(var(--s-3) * -1)"
5959 , marginLeft: var "--s-2"
60+ , userSelect: none
6061 , """&[data-required="true"] > span:after""":
6162 nest
6263 { content: str "'*'"
@@ -64,6 +65,7 @@ labelSmall =
6465 , "& > span":
6566 nest
6667 { fontWeight: str "500"
68+ , whiteSpace: str "nowrap"
6769 , background: str colour.inputBackground
6870 , color: str colour.text
6971 , borderRadius: var "--s-4"
@@ -94,11 +96,15 @@ labelSmall =
9496 }
9597 }
9698
97−labelLarge ∷ { leftIconWidth ∷ Maybe Number } -> Style
98−labelLarge { leftIconWidth } =
99+labelLarge ∷ { leftIconWidth ∷ Maybe Number, inputWidth ∷ Number } -> Style
100+labelLarge { leftIconWidth, inputWidth } =
99101 css
100102 { fontSize: str "calc(var(--s0) * 0.85)"
101103 , padding: _0
104+ , whiteSpace: nowrap -- force on one line
105+ , overflow: str "hidden"
106+ , maxWidth: str $ i "calc(" inputWidth "px)"
107+ , textOverflow: str "ellipsis"
102108 , marginTop: str "calc(var(--s-1) + var(--s-5))"
103109 , marginBottom: str "calc(var(--s-1) + var(--s-5))"
104110 , marginLeft:
@@ -108,7 +114,6 @@ labelLarge { leftIconWidth } =
108114 , marginRight: str "var(--input-side-padding)"
109115 , color: str colour.placeholderText
110116 , fontWeight: str "400"
111− , whiteSpace: nowrap -- force on one line
112117 , """&[data-required="true"]:after""":
113118 nest
114119 { content: str "'*'"
@@ -148,46 +153,57 @@ leftIconContainer =
148153 }
149154 }
150155
156+inputContainer ∷ ∀ r. { | Props OptionalProp r } -> Style
157+inputContainer props = theCss <>? props.css
158+ where
159+ theCss =
160+ css
161+ { position: relative
162+ , boxSizing: borderBox
163+ , backgroundColor: str colour.inputBackground
164+ , display: flex
165+ , width: str "calc(var(--s4) * 2)"
166+ , "--left-icon-size": var "--s0"
167+ , "--right-icon-size": str "calc(var(--s0) * 1.2)"
168+ , "--input-border-radius": var "--s-1"
169+ , "--input-side-padding": var "--s-1"
170+ , "--input-top-padding": var "--s-5"
171+ , "--input-bottom-padding": var "--s-5"
172+ , alignItems: center
173+ , justifyContent: center
174+ , paddingLeft: str "calc(var(--input-side-padding) - var(--border-width))"
175+ , paddingRight: str "calc(var(--input-side-padding) - var(--border-width))"
176+ , paddingTop: str "calc(var(--input-top-padding) - var(--border-width))"
177+ , paddingBottom: str "calc(var(--input-bottom-padding) - var(--border-width))"
178+ , gap: str "calc(var(--input-side-padding) / 2)"
179+ , "--border-width": str "1px"
180+ , border: str $ "var(--border-width) solid " <> colour.inputBorder
181+ , borderRadius: var "--input-border-radius"
182+ , """&[data-invalid="false"]""":
183+ nest
184+ { borderColor: str colour.success
185+ , "--border-width": str "var(--s-5)"
186+ }
187+ , """&[data-invalid="true"]""":
188+ nest
189+ { borderColor: str colour.invalid
190+ , "--border-width": str "var(--s-5)"
191+ }
192+ , "&:focus-within":
193+ nest
194+ { "--border-width": str "var(--s-5)"
195+ , borderColor: str colour.highlight
196+ , transition: str "border-color 0s linear 0.1s"
197+ }
198+ }
199+
151200inputWrapper ∷ Style
152201inputWrapper =
153202 css
154− { position: relative
155− , boxSizing: borderBox
156− , backgroundColor: str colour.inputBackground
157− , display: flex
158− , minWidth: str "calc(var(--s4) *2 )"
159− , "--left-icon-size": var "--s0"
160− , "--right-icon-size": str "calc(var(--s0) * 1.2)"
161− , "--input-border-radius": var "--s-1"
162− , "--input-side-padding": var "--s-1"
163− , "--input-top-padding": var "--s-5"
164− , "--input-bottom-padding": var "--s-5"
165− , alignItems: center
166− , justifyContent: center
167− , paddingLeft: str "calc(var(--input-side-padding) - var(--border-width))"
168− , paddingRight: str "calc(var(--input-side-padding) - var(--border-width))"
169− , paddingTop: str "calc(var(--input-top-padding) - var(--border-width))"
170− , paddingBottom: str "calc(var(--input-bottom-padding) - var(--border-width))"
171− , gap: str "calc(var(--input-side-padding) / 2)"
172− , "--border-width": str "1px"
173− , border: str $ "var(--border-width) solid " <> colour.inputBorder
174− , borderRadius: var "--input-border-radius"
175− , """&[data-invalid="false"]""":
176− nest
177− { borderColor: str colour.success
178− , "--border-width": str "var(--s-5)"
179− }
180− , """&[data-invalid="true"]""":
181− nest
182− { borderColor: str colour.invalid
183− , "--border-width": str "var(--s-5)"
184− }
185− , "&:focus-within":
186− nest
187− { "--border-width": str "var(--s-5)"
188− , borderColor: str colour.highlight
189− , transition: str "border-color 0s linear 0.1s"
190− }
203+ { margin: _0
204+ , minWidth: _0
205+ , padding: _0
206+ , flex: str "1"
191207 }
192208
193209input ∷ Style
@@ -195,8 +211,16 @@ input =
195211 css
196212 { "&[type=text],&[type=search],&[type=password],&[type=number],&:not([type])":
197213 nest
198− { color: str colour.text
199− , flex: str "2"
214+ { background: str "transparent"
215+ , color: str colour.text
216+ , width: _100percent
217+ , minWidth: _0
218+ , margin: _0
219+ , paddingTop: var "--padding-top"
220+ , paddingBottom: var "--padding-bottom"
221+ , paddingLeft: _0
222+ , paddingRight: _0
223+ , fontSize: str "calc(var(--s0) * 0.85)"
200224 , "--padding-top": var "--s-1"
201225 , "--padding-bottom": var "--s-1"
202226 , "&[aria-labelledby]":
@@ -204,14 +228,6 @@ input =
204228 { paddingTop: str "calc(var(--padding-top) + (var(--s-5)/2))"
205229 , paddingBottom: str "calc(var(--padding-bottom) - (var(--s-5)/2))"
206230 }
207− , background: str "transparent"
208− , margin: _0
209− , paddingTop: var "--padding-top"
210− , paddingBottom: var "--padding-bottom"
211− , paddingLeft: _0
212− , paddingRight: _0
213− , fontSize: str "calc(var(--s0) * 0.85)"
214− , gap: str gapSize
215231 , border: none
216232 }
217233 , "&[type=search]":
src/Yoga/Block/Atom/Input/View.purs+181−91
@@ -5,13 +5,15 @@ import Data.Array as Array
55import Data.Interpolate (i)
66import Data.String.NonEmpty (NonEmptyString)
77import Data.String.NonEmpty as NonEmptyString
8−import Data.Symbol (SProxy(..))
8+import Effect.Unsafe (unsafePerformEffect)
99import Foreign.Object (Object)
1010import Foreign.Object as Object
1111import Framer.Motion as M
1212import Partial.Unsafe (unsafeCrashWith)
13−import React.Basic.DOM (CSS, css)
13+import React.Basic.DOM (CSS, Props_input, css)
1414import React.Basic.DOM as R
15+import React.Basic.Emotion (Style)
16+import React.Basic.Hooks (reactComponent)
1517import React.Basic.Hooks as React
1618import Web.HTML.HTMLInputElement as InputElement
1719import Yoga.Block.Atom.Icon as Icon
@@ -57,7 +59,7 @@ containerVariants =
5759 { focussed:
5860 css
5961 { clipPath
60− , transition: { duration: 0.7 }
62+ , transition: { duration: 0.6 }
6163 }
6264 , blurred:
6365 css
@@ -71,9 +73,6 @@ containerVariants =
7173type Point =
7274 { x ∷ Int, y ∷ Int }
7375
74−p ∷ Int -> Int -> Point
75−p x y = { x, y }
76−
7776drawPathUntil ∷ Int -> Array Point -> String
7877drawPathUntil idx thePath = do
7978 let fn { x, y } = i x "%" " " y "%"
@@ -83,7 +82,7 @@ drawPathUntil idx thePath = do
8382 i "polygon(" rendered ")"
8483
8584path ∷ Array Point
86−path = mkPath 3 7
85+path = mkPath 4 8
8786
8887mkPath ∷ Int -> Int -> Array Point
8988mkPath borderX borderY = do
@@ -96,13 +95,22 @@ mkPath borderX borderY = do
9695 , {- ⌜ -} p borderX borderY
9796 ]
9897 outside =
99− [ {- ⌜ -} p 0 0
100− , {- ⌞ -} p 0 100
101− , {- ⌟ -} p 100 100
102− , {- ⌝ -} p 100 0
103− , {- ⌜ -} p 0 0
98+ [ {-⌜ -} p 0 0
99+ , {-⌞ -} p 0 100
100+ , {- . -} p 25 100
101+ , {- . -} p 50 100
102+ , {- . -} p 75 100
103+ , {- ⌟-} p 100 100
104+ , {- ⌝-} p 100 0
105+ , {- ^ -} p 75 0
106+ , {- ^ -} p 50 0
107+ , {- ^ -} p 25 0
108+ , {-⌜ -} p 0 0
104109 ]
105110 inside <> outside <> (Array.reverse inside)
111+ where
112+ p ∷ Int -> Int -> Point
113+ p x y = { x, y }
106114
107115containerVariantLabels ∷
108116 { blurred ∷ M.VariantLabel
@@ -110,31 +118,67 @@ containerVariantLabels ∷
110118 }
111119containerVariantLabels = M.makeVariantLabels containerVariants
112120
113−rawComponent ∷ ∀ p. ReactComponent { | p }
114−rawComponent =
121+rawInput ∷ ∀ p. ReactComponent { | p }
122+rawInput =
123+ mkForwardRefComponent "Input" do
124+ \(props ∷ { | PropsOptional }) ref -> React.do
125+ let
126+ result = inputWrapper [ input ]
127+ inputWrapper = div </* { className: "ry-input-wrapper", css: Style.inputWrapper }
128+ input = emotionInput ref inputProps { className: "ry-input", css: Style.input }
129+ inputProps = props { type = HTMLInput.toString <$> props.type # unsafeUnOptional }
130+ pure result
131+
132+rawContainer ∷ ∀ p. ReactComponent { | p }
133+rawContainer =
115134 mkForwardRefComponent "Input" do
135+ \( props ∷
136+ { children ∷ Array JSX
137+ , label ∷ JSX
138+ , css ∷ OptionalProp Style
139+ , hasFocus ∷ Boolean
140+ , inputProps ∷ { | InputPropsF OptionalProp () }
141+ }
142+ ) propsRef -> React.do
143+ -- Left icon width to correctly place the label
144+ let
145+ aria ∷ Object String
146+ aria = props.inputProps._aria # opToMaybe # fold
147+ inputContainer =
148+ M.div
149+ </* M.motion
150+ { variants: M.variants containerVariants
151+ , animate: M.animate if props.hasFocus then containerVariantLabels.focussed else containerVariantLabels.blurred
152+ }
153+ { className: "ry-input-container"
154+ , css: Style.inputContainer props
155+ , _data:
156+ Object.fromHomogeneous
157+ { "invalid": aria # Object.lookup "invalid" # fromMaybe ""
158+ }
159+ }
160+ /> props.children
161+ pure
162+ $ div
163+ </* { className: "ry-label-and-input-wrapper"
164+ , css: Style.labelAndInputWrapper
165+ }
166+ /> [ inputContainer, props.label ]
167+
168+rawComponent ∷ ∀ p. ReactComponent (Record p)
169+rawComponent =
170+ mkForwardRefComponent "InputContainer" do
116171 \(props ∷ { | PropsOptional }) propsRef -> React.do
117− inputBbox /\ setInputBbox <- useState' (zero ∷ DOMRect)
118172 hasFocus /\ setHasFocus <- useState' false
119173 backupRef ∷ NodeRef <- useRef null -- [TODO] test this
120174 let ref = forwardedRefAsMaybe propsRef # fromMaybe backupRef
121− useEffectOnce do
122− maybeBBox <- getBoundingBoxFromRef ref
123− for_ maybeBBox setInputBbox
124− mempty
125175 let
126− focusInput = do
176+ focusInput =
127177 unless hasFocus do
128178 maybeHTMLElement <- getHTMLElementFromRef ref
129179 for_ maybeHTMLElement focus
130180 -- Left icon width to correctly place the label
131181 leftIconRef ∷ NodeRef <- useRef null
132− leftIconBbox /\ setLeftIconBbox <- useState' Nothing
133− useEffectAlways do
134− when (isJust (props.leading # opToMaybe) && leftIconBbox == Nothing) do
135− maybeBBox <- getBoundingBoxFromRef leftIconRef
136− for_ maybeBBox (setLeftIconBbox <<< Just)
137− mempty
138182 let (maybeValue ∷ Maybe String) = cast props.value # opToMaybe
139183 hasValue /\ setHasValue <- useState' ((maybeValue # isJust) && (maybeValue /= Just ""))
140184 let
@@ -148,39 +192,18 @@ rawComponent =
148192 maybeLabelText = props.label # opToMaybe
149193 mkLabel ∷ NonEmptyString -> JSX
150194 mkLabel labelText =
151− R.div'
152− </* { className: "ry-input-label-container", css: Style.labelContainer }
153− /> [ M.animateSharedLayout </ { type: M.switch }
154− /> [ guard (inputBbox /= zero)
155− $ M.div
156− </* { className: if renderLargeLabel then "ry-input-label-large" else "ry-input-label-small"
157− , layoutId: M.layoutId "ry-input-label"
158− , css:
159− if renderLargeLabel then
160− Style.labelLarge { leftIconWidth: leftIconBbox <#> _.width }
161− else
162− Style.labelSmall
163− , layout: M.layout true
164− , transition: M.transition { duration: 0.18, ease: "easeOut" }
165− , _data:
166− Object.fromHomogeneous
167− { "has-focus": show hasFocus
168− , "invalid": aria # Object.lookup "invalid" # fromMaybe ""
169− , "required": aria # Object.lookup "required" # fromMaybe ""
170− }
171− , initial: M.initial false
172− }
173− /> [ M.span
174− </ { onClick: handler preventDefault (const focusInput)
175− , layout: M.layout true
176− , layoutId: M.layoutId "ry-input-label-text"
177− , htmlFor: props.id
178− , id: labelId
179− }
180− /> [ R.text $ NonEmptyString.toString labelText ]
181− ]
182− ]
183− ]
195+ inputLabel
196+ </> { onClickLargeLabel: handler preventDefault (const focusInput)
197+ , isFocussed: hasFocus
198+ , isRequired: aria # Object.lookup "required" # (_ == Just "true")
199+ , isInvalid: aria # Object.lookup "invalid" # (_ == Just "true")
200+ , renderLargeLabel
201+ , leftIconRef
202+ , labelId
203+ , inputId: props.id
204+ , inputRef: ref
205+ , labelText
206+ }
184207 leading ∷ Maybe JSX
185208 leading =
186209 opToMaybe props.leading
@@ -205,51 +228,118 @@ rawComponent =
205228 setHasValue (v /= "")
206229 )
207230 onFocus = handler preventDefault (const $ unless hasFocus $ setHasFocus true)
208− inputWrapper =
231+ inputContainer =
209232 M.div
210233 </* M.motion
211234 { variants: M.variants containerVariants
212235 , animate: M.animate if hasFocus then containerVariantLabels.focussed else containerVariantLabels.blurred
213236 }
214− { className: "ry-input-wrapper"
215− , css: Style.inputWrapper
237+ { className: "ry-input-container"
238+ , css: Style.inputContainer props
216239 , _data:
217240 Object.fromHomogeneous
218241 { "invalid": aria # Object.lookup "invalid" # fromMaybe ""
219242 }
220243 }
221244 /> [ leading # foldMap \l -> div </ { ref: leftIconRef } /> [ l ]
222− , emotionInput
223− ref
224− ( props { type = HTMLInput.toString <$> props.type # unsafeUnOptional }
225− # setOrDelete (SProxy ∷ _ "placeholder") (maybePlaceholder # maybeToOp)
226− # setOrDelete (SProxy ∷ _ "value") (maybeValue # maybeToOp)
227− )
228− { className: "ry-input"
229− , css: Style.input
230− , onFocus: composeHandler props.onFocus onFocus
231− , onBlur: composeHandler props.onBlur onBlur
232− , _aria:
233− if props.label # opToMaybe # isJust then
234− aria # Object.insert "labelledby" labelId
235− else
236− aria
237− }
245+ , rawInput
246+ </> ( props
247+ { onFocus = composeHandler props.onFocus onFocus
248+ , onBlur = composeHandler props.onBlur onBlur
249+ , ref = ref
250+ , placeholder = maybePlaceholder # maybeToOp # unsafeUnOptional
251+ , _aria =
252+ if props.label # opToMaybe # isJust then
253+ aria # Object.insert "labelledby" labelId
254+ else
255+ aria
256+ }
257+ )
258+ -- ref
259+ -- ( props { type = HTMLInput.toString <$> props.type # unsafeUnOptional }
260+ -- # setOrDelete (SProxy ∷ _ "placeholder") (maybePlaceholder # maybeToOp)
261+ -- # setOrDelete (SProxy ∷ _ "value") (maybeValue # maybeToOp)
262+ -- )
263+ -- { className: "ry-input"
264+ -- , css: Style.input
265+ -- }
238266 , trailing # foldMap \t -> div </ {} /> [ t ]
239267 ]
240268 pure
241269 $ case props.type # opToMaybe of
242270 Just HTMLInput.Password -> password </> props
243271 _ -> case maybeLabelText of
244− Nothing -> inputWrapper
272+ Nothing -> inputContainer
245273 Just labelText ->
246274 div
247275 </* { className: "ry-label-and-input-wrapper"
248276 , css: Style.labelAndInputWrapper
249277 }
250− /> [ inputWrapper
251− , mkLabel $ labelText
278+ /> [ inputContainer, mkLabel labelText ]
279+
280+inputLabel ∷
281+ ReactComponent
282+ { onClickLargeLabel ∷ EventHandler
283+ , isRequired ∷ Boolean
284+ , isInvalid ∷ Boolean
285+ , isFocussed ∷ Boolean
286+ , renderLargeLabel ∷ Boolean
287+ , leftIconRef ∷ NodeRef
288+ , inputRef ∷ NodeRef
289+ , labelId ∷ String
290+ , inputId ∷ String
291+ , labelText ∷ NonEmptyString
292+ }
293+inputLabel =
294+ unsafePerformEffect
295+ $ reactComponent "Password" \props -> React.do
296+ inputBbox /\ setInputBbox <- useState' (zero ∷ DOMRect)
297+ useEffectOnce do
298+ maybeBBox <- getBoundingBoxFromRef props.inputRef
299+ for_ maybeBBox setInputBbox
300+ mempty
301+ -- Left Icon
302+ leftIconBbox /\ setLeftIconBbox <- useState' Nothing
303+ useEffectAlways do
304+ when (leftIconBbox == Nothing) do
305+ maybeBBox <- getBoundingBoxFromRef props.leftIconRef
306+ for_ maybeBBox (setLeftIconBbox <<< Just)
307+ mempty
308+ let container = div </* { className: "ry-input-label-container", css: Style.labelContainer }
309+ let
310+ labelSpan =
311+ M.span
312+ </ { onClick: props.onClickLargeLabel
313+ , layout: M.layout true
314+ , layoutId: M.layoutId "ry-input-label-text"
315+ , htmlFor: props.inputId
316+ , id: props.labelId
317+ }
318+ pure
319+ $ container
320+ [ M.animateSharedLayout </ { type: M.switch }
321+ /> [ guard (inputBbox /= zero)
322+ $ M.div
323+ </* { className: if props.renderLargeLabel then "ry-input-label-large" else "ry-input-label-small"
324+ , layoutId: M.layoutId "ry-input-label"
325+ , css:
326+ if props.renderLargeLabel then
327+ Style.labelLarge { leftIconWidth: leftIconBbox <#> _.width, inputWidth: inputBbox.width }
328+ else
329+ Style.labelSmall
330+ , layout: M.layout true
331+ , transition: M.transition { duration: 0.18, ease: "easeOut" }
332+ , _data:
333+ Object.fromHomogeneous
334+ { "has-focus": show props.isFocussed
335+ , "invalid": show props.isInvalid
336+ , "required": show props.isRequired
337+ }
338+ , initial: M.initial false
339+ }
340+ /> [ labelSpan [ R.text $ NonEmptyString.toString props.labelText ] ]
252341 ]
342+ ]
253343
254344password ∷ ∀ p. ReactComponent { | p }
255345password =
@@ -298,16 +388,16 @@ password =
298388 let leading = props.leading ?|| mempty
299389 pure
300390 $ div
301− </* { className: "ry-input-wrapper"
302− , css: Style.inputWrapper
303− }
391+ </* { className: "ry-input-wrapper", css: Style.inputContainer props }
304392 /> [ leading
305− , emotionInput
306− ref
307− props { type = HTMLInput.toString <$> props.type # unsafeUnOptional }
308− { className: "ry-input"
309− , css: Style.input
310− , type: if hidePassword then "password" else "text"
311− }
393+ , R.div' </ {}
394+ /> [ emotionInput
395+ ref
396+ props { type = HTMLInput.toString <$> props.type # unsafeUnOptional }
397+ { className: "ry-input"
398+ , css: Style.input
399+ , type: if hidePassword then "password" else "text"
400+ }
401+ ]
312402 , trailing
313403 ]
src/Yoga/Block/Container/Style.purs+11
@@ -96,6 +96,17 @@ mkGlobal maybeMode =
9696 nested
9797 $ css
9898 { boxSizing: str "inherit"
99+ , fontFeatureSettings:
100+ str
101+ $ intercalate ","
102+ $ show
103+ <$> [ "ss03" -- curved r
104+ , "cv03" -- open six
105+ , "cv04" -- open nine
106+ -- , "cv05" -- lower case l with tail
107+ , "cv07" -- German double-s
108+ , "cv09" -- Flat top three
109+ ]
99110 }
100111 }
101112