How do I get rid of the blue shadow around buttons when I click on them?
I am building a web app using Elm and mdgriffith/elmui.
Picture of button before click:
And after click:
Elm code:
module Main exposing (main)
import Browser
import Element as E
import Element.Input as Ei
import Element.Border as Eb
main = E.layout [ E.padding 30 ] <|
Ei.button []
{ onPress = Nothing
, label = E.text "A button"
}
(run it in Ellie)
I don't want to use any CSS, if at all possible.
Edit:
I don't think this is a duplicate, because my question is about how to do this with elm-ui, not with CSS.
The solution I'm going with is to use a bit of CSS, as I can't find a way to do it in elm-ui. This works:
module Main exposing (main)
import Html.Attributes as Hat
import Element as E
import Element.Input as Ei
noOutline = E.htmlAttribute <| Hat.style "box-shadow" "none"
main = E.layout [ E.padding 30 ] <|
Ei.button [ noOutline ]
{ onPress = Nothing
, label = E.text "A button"
}
(Thanks to glennsl's comment.)
To avoid css, consider using layoutWith together with a focusStyle.
Unfortunately this is global and will apply to all Input elements
Edit:
In practice this looks like
Element.layoutWith
{ options =
[ focusStyle
{ borderColor = Nothing
, backgroundColor = Nothing
, shadow = Nothing
}
]
}
listOfattrs
listOfchildren
Related
I'm trying to do CSS animation in Elm, and I just can't get it to work!
Elm has several animation packages. The one I'm attempting to use is mdgriffith/elm-animator. Sadly, like many Elm packages, its documentation is sparse. It appears it provides two ways to render: one by running an Elm event loop to do a DOM update each frame, and one using CSS animation [which I didn't realise even existed]. I'm trying to do the latter.
I've tried to shrink the code down to a minimal example:
module Main exposing (main)
import Time
import Platform.Cmd
import Browser
import Html
import Html.Attributes
import Html.Events
import Color
import Svg
import Svg.Attributes
import Animator
import Animator.Css
main =
Browser.document
{
init = \ () -> ({fill = Animator.init <| Color.rgb 1 0 0}, Platform.Cmd.none),
subscriptions = \ state -> Animator.toSubscription Tick state animator,
view = \ state -> {title = "Animation test", body = view state},
update = \ msg state -> (update msg state, Platform.Cmd.none)
}
type alias State = { fill : Animator.Timeline Color.Color }
animator : Animator.Animator State
animator =
Animator.animator
|> Animator.Css.watching (\ state -> state.fill) (\ c state -> { state | fill = c })
type Msg = Tick Time.Posix | DoSomething
update : Msg -> State -> State
update msg state0 =
case msg of
Tick t -> Animator.update t animator state0
DoSomething -> { state0 | fill = Animator.go Animator.slowly (Color.rgb 1 1 0) state0.fill }
view : State -> List (Html.Html Msg)
view state0 =
[
Html.button [Html.Events.onClick DoSomething] [Html.text "Do something"],
Svg.svg
[
Svg.Attributes.width "100px",
Svg.Attributes.height "100px"
]
[
Animator.Css.node "circle"
state0.fill
[
Animator.Css.color
"fill"
(\ x -> x)
]
[
Svg.Attributes.cx "50",
Svg.Attributes.cy "50",
Svg.Attributes.r "50"
]
[]
]
]
I appreciate that's still pretty big, but I don't see how to easily make it much shorter without obfuscating what it's doing.
When I run this, the SVG fails to render. When I click the button, nothing happens.
Here's the really weird part: If I open the Firefox Inspector window, I can see the SVG <circle> element. If I edit its various properties, nothing happens. However, if I right-click the <circle> and select "Edit as HTML...", then add a single space to the element text and click off it, suddenly the circle appears! Moreover, if I right-click the element again, now it shows as "Edit as SVG...", which is suspicious.
Even more fun: If I load the page, click the button, and then do the above trick, the colour animation runs!
Note that if I edit the HTML and change nothing, it doesn't work. I have to make a trivial change to the text (or else I guess the browser decides it doesn't need to reprocess?)
I was so convinced this was going to end up being a weird Firefox bug... but then I tried it in Chrome and Edge, and it does exactly the same thing!
Does anybody have to vaguest clue why this doesn't work? Have I done something wrong with the Elm code? (I'm really, really struggling to figure out how this library works; I'm basically just guessing how the types fit together. So maybe I've done something dumb.)
This is due to a weird thing going on with namespaces. In an HTML document (i.e. on any webpage), the default namespace is the HTML namespace and if you want to render embedded documents in other formats, you need to ensure the nodes are created in the correct namespace.
Now when you write HTML as a string and the browser parses it from text, it will do this automatically for you:
<div> <!-- HTML Namespace -->
<svg>
<circle /> <!-- SVG Namespace -->
</svg>
<math>
<mrow></mrow> <!-- MathML namespace
(not really relevant, just pointing out different NS) -->
</math>
</div>
However, when you are constructing nodes dynamically (i.e. from JS or Elm), you need to explicitly ask for the namespace. That is in JS you would use Document.createElementNS() instead of just Document.createElement(). If you look at the source of the elm/svg package you will see that it does this:
node : String -> List (Attribute msg) -> List (Svg msg) -> Svg msg
node =
VirtualDom.nodeNS "http://www.w3.org/2000/svg"
If you don't do this, the browser understands you want to create a new HTML element called circle, which the browser doesn't know about. If the browser doesn't know about an element, it just treats basically like a <div>.
Now if you look at the source of the elm-animator package, you'll notice that it asks for an Html.node, so no namespace!
As to how to make it work with elm-animator, I suspect you can't. But perhaps someone else can contribute some solution...
Finally, you might want to consider SMIL style animation, it tends to get the job done without needing any external package.
I've used 2 objects from CustomAction to add 2 buttons to the toolbar : it works fine (with javascript callback), but now, i would like to show / hide the little blue line under those button when the corresponding tool is activated (=adding the style 'bk-active' to the div corresponding to those buttons) : how to do that ? Is it possible to add a html id to the CustomAction ? or how to get an access to the html div on the javascript side through the Bokeh object or cb_obj or this ?
(it's a standalone file, no server)
Thanks
If you have just one Bokeh document you could give your Div a name attribute and use: var div = Bokeh.documents[0].get_model_by_name('div_name') in JS callback. See example below (works for Bokeh 2.1.1)
from bokeh.models import Div, Button, Column, CustomJS
from bokeh.plotting import show
button = Button(label='Toggle Div Visibility')
div = Div(text = 'Bokeh Div', name = "bokeh_div")
# code = "if (div.visible == true) { div.visible = false; } else { div.visible = true; }"
# button.js_on_click(CustomJS(args = {'div': div}, code = code))
code = "var div = Bokeh.documents[0].get_model_by_name('bokeh_div');
if (div.visible == true) { div.visible = false; } else { div.visible = true; }"
button.js_on_click(CustomJS(code = code))
show(Column(button, div))
I've made a map using Bokeh, like the first example on this page, except the user can zoom in/out by scrolling up/down, and can tap circles I've added to the map to select them.
At the moment when the cursor is over the map it's the default arrow. If I click and drag the map the cursor changes to the text cursor for some reason. It doesn't change with any other action.
I'd like to be able to change the cursor appearance so that:
When over the map it's the grab cursor
When dragging the map it's the grabbing cursor
When over a circle it's the pointer cursor
I can achieve (1) with:
.bk { cursor: grab; }
but I'm not sure how to achieve the other two.
Following suggestions from the other post I came with this: (works for Bokeh v1.3.0):
from bokeh.models import CustomJS, HoverTool
from bokeh.plotting import figure, show
p = figure(tools='pan, tap, reset')
p.circle(x=[1,2,3], y=[1,2,3], size=30)
code_pan_start = '''
Bokeh.grabbing = true
var elm = document.getElementsByClassName('bk-canvas-events')[0]
elm.style.cursor = 'grabbing'
'''
code_pan_end = '''
if(Bokeh.grabbing) {
Bokeh.grabbing = false
var elm = document.getElementsByClassName('bk-canvas-events')[0]
elm.style.cursor = 'grab'
}
'''
code_hover = '''
if((Bokeh.grabbing == 'undefined') || !Bokeh.grabbing) {
var elm = document.getElementsByClassName('bk-canvas-events')[0]
if (cb_data.index.indices.length > 0)
elm.style.cursor = 'pointer'
else
elm.style.cursor = 'grab'
}
'''
p.js_on_event('panstart', CustomJS(code = code_pan_start))
p.js_on_event('panend', CustomJS(code = code_pan_end))
p.add_tools(HoverTool(callback = CustomJS(code = code_hover)))
show(p)
You could potentially use the PanStart and PanEnd events to set/reset the cursor on drag operations. I think the hover will be difficult to achieve. Currently there is a callback property on hover tools that can be used trigger JS code when an inspection happens on a point. But it only fires when there is an inspection, there is no corresponding event or hook for "un-inspection" so I am not sure how you would reliably clear the cursor state when the user is no longer hovering over the circle.
I am implementing a simple widget but I am a primer with animations :)
How can I avoid the second "screen" to occupy space while transitioning in?
Here my fiddle: https://codesandbox.io/s/7w4yw5yq4q
As you can see when you click a button on the first "screen" both the first "screen" and the second are in the DOM so the widget doubles its height.
I want that the two occupy the same line so the height of the widget stays the same.
I guess that I need to use absolute positioning but I want to be sure that it is the right way to do this and see an example of the implementation.
Maybe is there a way to do it without losing the height of the parent (that when the children are absolute positioned goes to 0)
Likely a bit late to answer this but may be others looking for the same answer may benefit.
Is this what you were asking to do?
One thing in Mithril is that if you don't want to return an element, you can just return a null. I use that technique a lot like showHeading ? m("h1", "Heading!") : null
The following is the mod of your code and its fiddle to demonstrate. There are other ways of doing it like dynamically changing the class depending on the toggle.
var m = require("mithril");
import "./style.css";
let app = function() {
let toggle = false;
return {
view: vnode => {
return m(".steps", [
m("button", { onclick: () => (toggle = !toggle) }, "toggle"),
m(
".step",
toggle
? null
: [m("h1", "Title 1"), m("p", "jfewlkfjewklfjwelkfjklewjfw")]
),
toggle
? m(".step.slide-in", [
m("h1", "Title 2"),
m("p", "jfewlkfjewklfjwelkfjklewjfw")
])
: "",
m(".step", [m("h1", "Title 3 "), m("p", "jfewlkfjewklfjwelkfjklewjfw")])
]);
}
};
};
m.mount(document.getElementById("app"), app);
I have figured out a way to change the style of tabs at run time with following logic:
var cssStyle:CSSStyleDeclaration = StyleManager.getStyleDeclaration(".MyTabs");
cssStyle.setStyle("borderColor", "red");
But here ".MyTabs" class is applicable to all the tabs between first and last tab. As per getStyleDeclaration javadoc, it only accepts "class selector" and "type selector" not the id selector.
How can I change the individual tab style at run time?
(tabNavigator.getTabAt(index) as Button).setStyle("borderColor", 0xFF0000);
This will solve the issue, you can set your own color as value param.
Another user pointed out a method that I had somehow missed, allowing you to access a Tab as a Buttom and style it from there.
var t:Button = theTabs.getTabAt(index);
Tab extends Button, so there may be some things you would need the below solution for, but for basic styling this should be enough.
#Sebastian's answer works for a TabBar, which I know you don't have, as this is the third identical question you've asked. In order to style the tabs on a TabNavigator, you need to access the internal TabBar.
//this import may not auto-complete for you
import mx.controls.tabBarClasses.Tab;
var t:Tab = theTabs.mx_internal::getTabBar().getChildAt(index);
Now you can feel free to set the styles, as shown in Sebastian's answer.
You can call setStyle on the individual Tab's, which u can get by calling TabBar.getChildAt(x) . Check the following link, which illustrates how to achieve the task you are trying to perform. You can also check out this link
private function tabBar_creationComplete():void {
var colorArr:Array = ["red", "haloOrange", "yellow", "haloGreen", "haloBlue"];
var color:String;
var tab:Tab;
var idx:uint;
var len:uint = tabBar.dataProvider.length;
for (idx = 0; idx < len; idx++) {
var i:int = idx % colorArr.length;
color = colorArr[i];
tab = Tab(tabBar.getChildAt(idx));
tab.setStyle("fillColors", [color, "white"]);
tab.setStyle("fillAlphas", [1.0, 1.0]);
tab.setStyle("backgroundColor", color);
}
}