Repository: streamlit/streamlit
Pull request: Assorted visual tweaks
## Describe your changes

This PR addresses a handful of visual tweaks, namely:
1. Makes library links blue, to make them consistent with the app interface (reported by @jrieke);
2. Fixes the small bottom padding after scrolling in the sidebar (reported by Andreas Braendhaugen);
3. Hides the `-` and `+` buttons for `st.number_input` when its width is smaller than `120px` (reported by @jrieke).

Closes #894

**Before:**

![Screenshot 2023-07-20 at 2 23 48 PM](https://github.com/streamlit/streamlit/assets/103376966/b76e95b5-8f79-4694-a9ef-e6fbf2713749)

<img width="2494" alt="Untitled (1)" src="https://github.com/streamlit/streamlit/assets/103376966/e35a0d3c-dc89-4573-99d7-d0e06863f5ff">

<img width="130" alt="Untitled" src="https://github.com/streamlit/streamlit/assets/103376966/01fab15b-614c-46ed-bb46-03ee933158d8">

**After:**

![Screenshot 2023-07-20 at 2 26 50 PM](https://github.com/streamlit/streamlit/assets/103376966/c374690e-5ba9-4d96-a0d2-ea9e28d00afd)

https://github.com/streamlit/streamlit/assets/103376966/5eede343-f284-4a3e-8130-48a98e6cb351

![Screenshot 2023-07-20 at 2 54 50 PM](https://github.com/streamlit/streamlit/assets/103376966/6a2ef8d6-3690-4937-815a-9190a64a418d)

## Notion links

* https://www.notion.so/snowflake-corp/Change-link-color-in-About-dialog-46201c1b2f0144d2b961d25053f9d006?pvs=4
* https://www.notion.so/Bottom-padding-on-sidebar-disappears-when-content-overflows-9455d42dea104505b749e36f3b36b88b
* https://www.notion.so/snowflake-corp/Papercut-Request-icons-in-st-number_input-c58552f88b1b448eb3857fde197ce058?pvs=4

## Testing Plan

- Explanation of why no additional tests are needed: N/A
- Unit Tests (JS and/or Python): Added
- E2E Tests: Added
- Any manual testing needed? Yes

---

**Contribution License Agreement**

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.


Problem statement:
Remove number_input -/+ step toggles option
Is there an option to remove the -/+ number_input step toggles? If not, I would suggest that for a future release. Thank you! 

Also, is it possible to increase the precision? 

Right now I am just using a text_input and type casting to float to get around this.

---

Community voting on feature requests enables the Streamlit team to understand which features are most important to our users.

**If you'd like the Streamlit team to prioritize this feature request, please use the 👍 (thumbs up emoji) reaction in response to the initial post.**

Hints from issue discussion:
Hi @ajberlier ,

There's no option to remove the +/- toggles at the moment. I'll leave this issue open as a feature request!

You can use the `step` attribute to  modify the precision of the toggles. If you just want to be able to enter floats in general, use a float as the initial value.

`st.number_input("number input", step=0.1, value=1.0)`

The default `step` and `value` are floats already.

`st.number_input("number input")`
@jrhone 

I am not sure how hard it would be to implement, but I think a good way to use this (currently non-existent) feature would be to set step=0.
Hi @RedFrez , I like the idea suggestion :)

Pinging our product team to ensure they have eyes on this @nthmost
One reason to having the ability to remove the buttons, is if the page will be printed out. In "paper" format the buttons have no value, and just add some visual clutter to the page. 

With a live site, if reviewing the data is more than altering it, then you may want to reduce the usability/visibility of the buttons. 

__My idea for implementation:__
- Anyone who cares about altering the steps of the buttons would not be setting them to 0. This also passes my logic test of if you don't want buttons, then you want the steps to nothing, null, or 0. 

- The step could be converted to receive a `null` value, but that would require altering the Proto and more logic in order to process how it should be handled.

- There could be another parameter added to number_input, but this would add overall complexity to the code, which I think is unnecessary. This could also be in the future if desired with minimal impact.

Using the `step=0` option, only adds two additional lines to the number_input widget, not taking into account the lines added for testing. Since it checks `element.step` for conditional rendering of the buttons, it has no impact on how `step` is processed or used for any other aspect of the input.

I thought it was important to still allow for use of the up and down arrows for controlling the input. Since `0` is a Falsy value, it will still generate the default steps based on number type of the input.
@ajberlier : Curious to hear, what is your use case for removing the -/+ number_input step toggles?
For us, we would use as a 'free' number input and not as a "range".
For example:
`st.number_input("How much did it cost?", min_value=0.0, step=0.01)`
We want from the user that write out the number in the specified format (like `12499.99`), where '+' and '-' buttons has no meaning.   
Hi @asaini ,

I thought I would describe a common use-case of mine for removing the step buttons. A lot of my Streamlit apps include some preliminary data manipulation functionality, like inputting various minimum/maximum constraints which then get applied to, say, columns of a dataframe. For one app, I'd like to be able to do this in the sidebar, since it isn't the main functionality of the app, and having it centered would clutter the interface.

I have found that the best way to accomplish this, from a layout perspective, is to use `st.beta_columns` and populate 2 columns with `st.number_input` for the minimum and maximum values. These 2 column "units" are then placed in rows for as many constraints are needed.

However, when these columns are placed in the sidebar, the low sidebar width causes the increment/decrement buttons to occupy more screen space than the actual input field. The user cannot see the entirety of the numbers they are entering, and the layout is cluttered and distracting. I see three workarounds, each problematic in their own way:

1. Use `st.slider`. This works to an extent, but the flaw with using sliders occurs when the slider range is extracted from the range of the data itself. Sometimes, extreme outliers in the data will skew one end of the slider so far to the left or right side that a majority of the data is compressed to within some small % of the slider space. This is frustrating, and often means that in the course of interaction the user has to move the ends of the sliders so close together that the numbers bleed together and obscure each other (the numbers which float above the little draggable circle). Additionally, if there are a sufficient number of digits in the maximum value for slider, then the sidebar gains a horizontal scroll bar (at least in Firefox) since these digits go off the edge of the sidebar.
2. Use `st.text_input`. This removes the visual clutter of the increment/decrement buttons present with `st.number_input`, but is essentially untenable. It requires manually handling numeric input validation, and in addition losing out on the real-time validation and protection that `st.number_input` provides, it also leaves the user without the clean hint regarding the min/max value specification (i.e., the pop-up message saying "Please select a value that is no less/more than *X*" which occurs when you enter an out-of-range value into an `st.number_input`).
3. [Increasing the sidebar width](https://github.com/streamlit/streamlit/issues/2058). This allows the user to see the numbers in each field, but at the expense of the visual experience of the app. It means that the sidebar is no longer "in the background", as it competes with the main space and pushes it further to the right side of the screen. On a larger screen with high DPI, this can look mostly OK, but becomes a problem at lower resolutions or aspect ratios.

In sum, I feel that having an option to just simply not render the increment/decrement buttons on `st.number_input` would allow for more compact side-by-side layouts by taking better advantage of screen estate. I don't have anything to suggest regarding implementation, but this is just my use-case. Anyways--I hope this feels concrete and well motivated. Let me know if you have any questions.
@jrhone @kmcgrady are there any news on this 2 year old much wanted feature? :)
I'm also interested in any updates
Any update on this request? As mentioned, the + and - buttons sometimes occupies a large fraction of the number_input field, making it impossible to read the  number typed.

Commit message: Add modal snapshots

Patch to review:
diff --git a/e2e/scripts/st_number_input.py b/e2e/scripts/st_number_input.py
index c135fe48ed32..0aebaeb7dcfe 100644
--- a/e2e/scripts/st_number_input.py
+++ b/e2e/scripts/st_number_input.py
@@ -47,3 +47,9 @@ def on_change():
     st.number_input("number input 9", key="number_input9", on_change=on_change)
     st.write('value 9: "', st.session_state.number_input9, '"')
     st.write("number input changed:", "number_input_changed" in st.session_state)
+
+[col1, col2, col3, col4, col5, col6] = st.columns(6)
+
+with col1:
+    i10 = st.number_input("number input 10", max_value=10)
+    st.write('value 10: "', i10, '"')
diff --git a/e2e/specs/st_number_input.spec.js b/e2e/specs/st_number_input.spec.js
index fa378afed8de..768d318b109f 100644
--- a/e2e/specs/st_number_input.spec.js
+++ b/e2e/specs/st_number_input.spec.js
@@ -22,7 +22,7 @@ describe("st.number_input", () => {
   });
 
   it("shows widget correctly", () => {
-    cy.get(".stNumberInput").should("have.length", 9);
+    cy.get(".stNumberInput").should("have.length", 10);
 
     cy.get(".stNumberInput").each((el, idx) => {
       // @ts-expect-error
@@ -42,7 +42,8 @@ describe("st.number_input", () => {
         'value 7: " 0.0 "' +
         'value 8: " 0.0 "' +
         'value 9: " 0.0 "' +
-        "number input changed: False"
+        "number input changed: False" +
+        'value 10: " 0 "'
     );
   });
 
@@ -76,7 +77,8 @@ describe("st.number_input", () => {
         'value 7: " 0.0 "' +
         'value 8: " 0.0 "' +
         'value 9: " 0.0 "' +
-        "number input changed: False"
+        "number input changed: False" +
+        'value 10: " 0 "'
     );
   });
 
@@ -98,7 +100,8 @@ describe("st.number_input", () => {
         'value 7: " 0.0 "' +
         'value 8: " 0.0 "' +
         'value 9: " 0.0 "' +
-        "number input changed: False"
+        "number input changed: False" +
+        'value 10: " 0 "'
     );
   });
 
@@ -126,7 +129,8 @@ describe("st.number_input", () => {
         'value 7: " 0.01 "' +
         'value 8: " 0.01 "' +
         'value 9: " 0.01 "' +
-        "number input changed: True"
+        "number input changed: True" +
+        'value 10: " 0 "'
     );
   });
 
@@ -146,7 +150,8 @@ describe("st.number_input", () => {
         'value 7: " 0.0 "' +
         'value 8: " 0.0 "' +
         'value 9: " 0.0 "' +
-        "number input changed: False"
+        "number input changed: False" +
+        'value 10: " 0 "'
     );
   });
 });
diff --git a/frontend/app/src/components/Sidebar/styled-components.ts b/frontend/app/src/components/Sidebar/styled-components.ts
index 6f6cd63ae742..4a8ece81fe12 100644
--- a/frontend/app/src/components/Sidebar/styled-components.ts
+++ b/frontend/app/src/components/Sidebar/styled-components.ts
@@ -243,7 +243,7 @@ export const StyledSidebarUserContent =
     paddingTop: hasPageNavAbove
       ? theme.spacing.lg
       : theme.sizes.sidebarTopSpace,
-    paddingBottom: theme.spacing.twoXL,
+    paddingBottom: theme.sizes.sidebarTopSpace,
     paddingLeft: theme.spacing.lg,
     paddingRight: theme.spacing.lg,
 
diff --git a/frontend/cypress/snapshots/linux/2x/modals.spec.js/about-dark.snap.png b/frontend/cypress/snapshots/linux/2x/modals.spec.js/about-dark.snap.png
index ca546193101a..e27f66955617 100644
Binary files a/frontend/cypress/snapshots/linux/2x/modals.spec.js/about-dark.snap.png and b/frontend/cypress/snapshots/linux/2x/modals.spec.js/about-dark.snap.png differ
diff --git a/frontend/cypress/snapshots/linux/2x/modals.spec.js/about.snap.png b/frontend/cypress/snapshots/linux/2x/modals.spec.js/about.snap.png
index 51d93644053e..3aeffb72c315 100644
Binary files a/frontend/cypress/snapshots/linux/2x/modals.spec.js/about.snap.png and b/frontend/cypress/snapshots/linux/2x/modals.spec.js/about.snap.png differ
diff --git a/frontend/cypress/snapshots/linux/2x/st_number_input.spec.js/number_input9-dark.snap.png b/frontend/cypress/snapshots/linux/2x/st_number_input.spec.js/number_input9-dark.snap.png
new file mode 100644
index 000000000000..70a08d77135d
Binary files /dev/null and b/frontend/cypress/snapshots/linux/2x/st_number_input.spec.js/number_input9-dark.snap.png differ
diff --git a/frontend/cypress/snapshots/linux/2x/st_number_input.spec.js/number_input9.snap.png b/frontend/cypress/snapshots/linux/2x/st_number_input.spec.js/number_input9.snap.png
new file mode 100644
index 000000000000..c190b16f269e
Binary files /dev/null and b/frontend/cypress/snapshots/linux/2x/st_number_input.spec.js/number_input9.snap.png differ
diff --git a/frontend/lib/src/components/widgets/NumberInput/NumberInput.test.tsx b/frontend/lib/src/components/widgets/NumberInput/NumberInput.test.tsx
index 4c6bff9ba4a3..39549adab768 100644
--- a/frontend/lib/src/components/widgets/NumberInput/NumberInput.test.tsx
+++ b/frontend/lib/src/components/widgets/NumberInput/NumberInput.test.tsx
@@ -33,7 +33,7 @@ const getProps = (elementProps: Partial<NumberInputProto> = {}): Props => ({
     hasMax: false,
     ...elementProps,
   }),
-  width: 0,
+  width: 300,
   disabled: false,
   widgetMgr: new WidgetStateManager({
     sendRerunBackMsg: jest.fn(),
@@ -452,5 +452,12 @@ describe("NumberInput widget", () => {
       expect(wrapper.state("value")).toBe(2)
       expect(stepUpButton(wrapper).prop("disabled")).toBe(true)
     })
+
+    it("hides stepUp and stepDown buttons when width is smaller than 120px", () => {
+      const props = getIntProps({ default: 1, step: 1, max: 2, hasMax: true })
+      const wrapper = shallow(<NumberInput {...props} width={100} />)
+
+      expect(wrapper.find("button").exists()).toBe(false)
+    })
   })
 })
diff --git a/frontend/lib/src/components/widgets/NumberInput/NumberInput.tsx b/frontend/lib/src/components/widgets/NumberInput/NumberInput.tsx
index ca991b455e76..712b6816c74f 100644
--- a/frontend/lib/src/components/widgets/NumberInput/NumberInput.tsx
+++ b/frontend/lib/src/components/widgets/NumberInput/NumberInput.tsx
@@ -410,30 +410,32 @@ class NumberInput extends React.PureComponent<Props, State> {
               },
             }}
           />
-          <StyledInputControls>
-            <StyledInputControl
-              className="step-down"
-              onClick={this.modifyValueUsingStep("decrement")}
-              disabled={disableDecrement}
-            >
-              <Icon
-                content={Minus}
-                size="xs"
-                color={this.canDecrement ? "inherit" : "disabled"}
-              />
-            </StyledInputControl>
-            <StyledInputControl
-              className="step-up"
-              onClick={this.modifyValueUsingStep("increment")}
-              disabled={disableIncrement}
-            >
-              <Icon
-                content={Plus}
-                size="xs"
-                color={this.canIncrement ? "inherit" : "disabled"}
-              />
-            </StyledInputControl>
-          </StyledInputControls>
+          {width > 120 && (
+            <StyledInputControls>
+              <StyledInputControl
+                className="step-down"
+                onClick={this.modifyValueUsingStep("decrement")}
+                disabled={disableDecrement}
+              >
+                <Icon
+                  content={Minus}
+                  size="xs"
+                  color={this.canDecrement ? "inherit" : "disabled"}
+                />
+              </StyledInputControl>
+              <StyledInputControl
+                className="step-up"
+                onClick={this.modifyValueUsingStep("increment")}
+                disabled={disableIncrement}
+              >
+                <Icon
+                  content={Plus}
+                  size="xs"
+                  color={this.canIncrement ? "inherit" : "disabled"}
+                />
+              </StyledInputControl>
+            </StyledInputControls>
+          )}
         </StyledInputContainer>
         <StyledInstructionsContainer>
           <InputInstructions
diff --git a/frontend/lib/src/theme/globalStyles.ts b/frontend/lib/src/theme/globalStyles.ts
index 363cb98d0968..58e55e6b2742 100644
--- a/frontend/lib/src/theme/globalStyles.ts
+++ b/frontend/lib/src/theme/globalStyles.ts
@@ -21,7 +21,7 @@ import { EmotionTheme } from "@streamlit/lib/src/theme"
 export const globalStyles = (theme: EmotionTheme): SerializedStyles => css`
   a,
   a:visited {
-    color: ${theme.colors.primary};
+    color: ${theme.colors.linkText};
   }
 
   // Override the base font-size value here.
@@ -32,7 +32,7 @@ export const globalStyles = (theme: EmotionTheme): SerializedStyles => css`
 
   a:hover,
   a:active {
-    color: ${theme.colors.primary};
+    color: ${theme.colors.linkText};
     text-decoration: underline;
   }
 
@@ -337,11 +337,11 @@ export const globalStyles = (theme: EmotionTheme): SerializedStyles => css`
   // Links
 
   a {
-    color: ${theme.colors.primary};
+    color: ${theme.colors.linkText};
     text-decoration: underline;
 
     &:hover {
-      color: ${darken(theme.colors.primary, 0.15)};
+      color: ${darken(theme.colors.linkText, 0.15)};
     }
   }
 


Code review comments:
diff_hunk: @@ -410,30 +410,32 @@ class NumberInput extends React.PureComponent<Props, State> {
               },
             }}
           />
-          <StyledInputControls>
-            <StyledInputControl
-              className="step-down"
-              onClick={this.modifyValueUsingStep("decrement")}
-              disabled={disableDecrement}
-            >
-              <Icon
-                content={Minus}
-                size="xs"
-                color={this.canDecrement ? "inherit" : "disabled"}
-              />
-            </StyledInputControl>
-            <StyledInputControl
-              className="step-up"
-              onClick={this.modifyValueUsingStep("increment")}
-              disabled={disableIncrement}
-            >
-              <Icon
-                content={Plus}
-                size="xs"
-                color={this.canIncrement ? "inherit" : "disabled"}
-              />
-            </StyledInputControl>
-          </StyledInputControls>
+          {width > 120 && (
path: frontend/lib/src/components/widgets/NumberInput/NumberInput.tsx
text: @user1:
Is there a reasonable place to put this breakpoint in theme where it is easily accessible here? Maybe `frontend/lib/src/theme/primitives/breakpoints.ts`? Also please add a note there as to what its used for, perhaps why 120px.

Also think we should make this a variable above the render with explanatory comment above it, something along the lines of:
```
// We only want to show the increment/decrement controls when there is sufficient room
// to display the value & these controls
const showControls = theme.breakpoints.numberInput > 120
```

@author:
Sorry for the poor job at explaining how this works: Updated in [95b0381](https://github.com/streamlit/streamlit/pull/7050/commits/95b038195ea6e4b474252fa5dc83bd102bcd26b1)

diff_hunk: @@ -21,7 +21,7 @@ import { EmotionTheme } from "@streamlit/lib/src/theme"
 export const globalStyles = (theme: EmotionTheme): SerializedStyles => css`
   a,
   a:visited {
-    color: ${theme.colors.primary};
+    color: ${theme.colors.linkText};
path: frontend/lib/src/theme/globalStyles.ts
text: @user1:
global style changes always going to make me a little nervous, but it is our intent to change all links right?

@author:
Yeah, I definitively feel the same way... The request mentions the link color in the about dialog only, but it also mentions `it should be the normal blue that we use everywhere else`, which makes me think we want all links to be the same color as the actual app links. @user2 maybe you can shed a bit more light as to what was your thinking for this request?

@user2:
Oh sorry for the confusion. Just change the dialog, we don't need to change anything else. (I thought we already use the same color for links everywhere else). 

@author:
Makes sense! Reverted and fixed on [c30d2b4](https://github.com/streamlit/streamlit/pull/7050/commits/c30d2b4f567657dcd8b526b9dcf6ce2c16716410)