Responsive input component margin - html

I have input component that takes full size based on maxWidth property and can shrink on screen size changes.
Problem is that margin is not consistent with maxWidth in pixels, but ok if input is 100%. Also centering input have it's own padding problems, but i think it's the same problem.
How to limit max-width of input with respect of paddings and save flexibility to shrink?
Codesandbox (you can fork it and change).
import * as React from "react";
import styled from "styled-components";
interface Props extends React.ComponentPropsWithoutRef<"input"> {
maxWidth?: string;
}
const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
return <StyledInput ref={ref} {...props} />;
});
const defPadding = 5;
const StyledInput = styled.input<Props>`
box-sizing: content-box;
margin: 5px;
vertical-align: middle;
padding: ${defPadding}px 0;
box-shadow: inset 0 0 0 1px blue;
border-radius: 5px;
border: none;
outline: none;
font: inherit;
max-width: calc(
${({ maxWidth }): string => maxWidth || "100%"} - ${defPadding * 2}px
);
width: 100%;
text-align: center;
`;
export default function App() {
return (
<div className="App">
<div>
<Input />
<Input maxWidth="1000px" />
</div>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
}}
>
<Input />
<Input maxWidth="1000px" />
</div>
</div>
);
}

If I understand the question right, the issue is not about paddings but those side 5-pixel-margins instead.
You can update the styles slightly so that
<Input maxWidth="1000px" /> extends as much as possible, but not beyond 1000px. The end CSS result should be:
width: 1000px;
max-width: calc(100% - 10px);
In your component styles try:
const StyledInput = styled.input<Props>`
box-sizing: content-box;
margin: 5px;
vertical-align: middle;
padding: ${defPadding}px 0;
box-shadow: inset 0 0 0 1px blue;
border-radius: 5px;
border: none;
outline: none;
font: inherit;
max-width: calc(100% - ${defPadding * 2}px);
width: ${({ maxWidth }): string => maxWidth || "auto"};
text-align: center;
`;
If this is your goal, maybe the margin: 5px should also use the defPadding variable.

Related

Why don't divs respond to width property, computed width doesn't match css in dev tools

I'm trying to make these containers for posts similar to any social media layout where its a card centered one per line and rectangular, but I can't get the post containers to respond to any width css, any idea why? Here are some pictures of the dev tools showing that somehow width is not computed as what the css says. Is it because they don't have any content?
here are the react components being rendered
const PostsContainer = () => {
const dispatch = useDispatch()
const {posts, isLoading, isError} = useSelector(state => state.posts)
useEffect(() => {
dispatch(loadPosts())
}, [])
if(!posts) {
return (
<div>Loading...</div>
)
}
return (
<div className="posts-container">
{posts.map((post) => (
<Post
key={post.id}
post={post}
/>
))}
</div>
)}
const Post = ({post}) => {
const {title} = post
return (
<div className='post-container'>
post
</div>
)}
css
.posts-container {
width: 80%;
height: 100vh;
margin: 10px auto;
display: flex;
justify-content: center;}
.post-container {
background-color: #FFFFFF;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
border-radius: max(0px, min(8px, ((100vw - 4px) - 100%) * 9999)) / 8px;
height: 400px;
width: 300px;
}

How to Make Default Date 2 weeks from the current date in Typescript Date Picker? Vue.js, Typescript

Greetings all and pardon my novice for I am just a beginner. I am looking to add a default date to my date picker box, but I have no clue as where to even begin. If any advice could be spared it would be greatly appreciated. As of now the date box displays absolutely nothing unless clicked and fed an input. I do not know how to set a default to the date and I am using Vue3 datepicker, typescript, sass, and html. I'm assuming it could be something along the lines of let d = new Date(); this.date = d + 14; or something. Again, I am completely lost so any advice would greatly help
Here is the code that will pertain to this problem ,
<template>
<RouterItem>
<div id="content">
<span id="header">The Basics</span>
<div style="grid-area: name;" class="body">
<input type="text" placeholder="Name" />
</div>
<div style="grid-area: jobNumber;" class="body">
<input type="text" placeholder="Job Number" />
</div>
<div id="dueDateBox">
<label for="dueDateBox">Due Date</label>
<Datepicker
autoApply
:enableTimePicker="false"
inputClassName="dp-custom-input-date-section"
:clearable="false"
style="grid-area: dueDate;"
></Datepicker>
</div>
</div>
</RouterItem>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Datepicker from 'vue3-date-time-picker';
import contenteditable from "vue-contenteditable";
import RouterItem from "../components/RouterItem.vue";
import { mapStores } from 'pinia';
import { useDisplayStore } from '../stores/display-store';
export default defineComponent({
name: "OrderBasic",
emits: ["update:modelValue"],
components: {
RouterItem,
Datepicker,
contenteditable,
},
computed: {
...mapStores(useDisplayStore),
},
methods: {
},
async mounted() {
this.displayStore.nextButtonText = "Next"
this.displayStore.nextDisabled = false
},
data() {
return {
format: (date: Date) => {
const day = date.getDate();
const month = date.getMonth() + 1;
const year = date.getFullYear();
return `${month}/${day}/${year}`;
}
}
},
});
</script>
<style scoped>
#content {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto auto auto;
grid-template-areas:
"header header"
"name name"
"jobNumber jobNumber"
"dueDate dueDate";
}
</style>
<style lang="sass" scoped>
#content
position: relative
justify-items: center
border-radius: 1rem
gap: 2rem
padding: 2rem 0
#header
display: flex
flex-direction: row
font-size: 1.6rem
grid-area: header
text-decoration: underline
text-decoration-color: #D3D3D3
.body
background-color: white
color: $primary-text-color
font-size: 1rem
border: 1px solid transparentize($primary-text-color, .7)
border-radius: .25rem
width: 15rem
min-height: 1rem
padding: .375rem .75rem
transform: scale(130%, 130%)
#dueDateBox
grid-area: dueDate
text-align: center
background-color: #fff
color: $secondary-text-color
font-size: 1rem
border: 1px solid transparentize($primary-text-color, .7)
border-radius: .25rem
width: 15rem
min-height: 1rem
padding: .375rem .75rem
transform: scale(130%, 130%)
transition: 150ms ease-in-out
transition-property: border-color, box-shadow
text-size: 1rem
&:focus
border-color: transparentize($secondary-color, .75)
box-shadow: 0 0 0 .25rem transparentize($secondary-color, .75)
</style>

How can I disable my submit button when a text area is left blank?

I am trying to make a submit button that is disabled when a text area is left blank, but alas I am not seeing results. If any advice could be spared it would be greatly appreciated. Here is the code that pertains to this problem. This submit button works as if it were not disabled, so I'm guessing there must be something wrong in my typescript or the way that I am constructing the disable in the first place, but I am getting to the point where I am running out of Ideas. If anyone has any questions feel free to ask.
<template>
<div id="editEntryDiv">
<div id="mainContent" v-if="loaded">
<PartsForm v-model="localPartEntry" />
</div>
<Teleport to="#mainContent">
<div class="actionBar">
<!-- Empty Div Required for formatting -->
<div>
<button id="deleteButton" #click="deleteItem(parseInt(id))">
<i class="fas fa-trash"></i>
<span>Delete</span>
</button>
</div>
<!-- Empty Div Required for formatting -->
<div>
<button
id="submitButton"
:class="{ disabled: localPartEntry.partNumber == undefined }"
:disabled="localPartEntry.partNumber == undefined"
#click="submitItem"
>
<i class="fas fa-paper-plane"></i>
<span>Submit</span>
</button>
</div>
</div>
</Teleport>
</div>
</template>
here is the typescript:
<script lang="ts">
import { defineComponent } from "vue";
import { usePartStore } from "../stores/part-store";
import PartsForm from "../components/PartsForm.vue";
import { PartDefinition } from "../types/PartDefinition";
import { mapStores } from 'pinia'
export default defineComponent({
components: {
PartsForm,
},
data() {
return {
loaded: false,
localPartEntry: {} as PartDefinition,
};
},
watch: {
localPartEntry: {
handler() {
if (!this.loaded) return
sessionStorage.setItem("unsavedPart", JSON.stringify(this.localPartEntry))
},
deep: true
}
},
computed: {
...mapStores(usePartStore),
id(): string {
return this.$route.params.id.toString();
},
},
methods: {
async submitItem(): Promise<void> {
this.localPartEntry.id = parseInt(this.id);
if (await this.partStore.editPartDefinition(this.localPartEntry))
if (await this.partStore.getParts())
this.$router.push({
path: `/`,
});
},
async deleteItem(id: number) {
if (confirm("Are you sure you want to delete this entry?"))
if (await this.partStore.deletePartDefinition(id))
if (await this.partStore.getParts())
this.$router.push({
path: `/`,
});
},
},
mounted() {
for (let element of this.partStore.partEntries as PartDefinition[]) {
if (element.id == parseInt(this.$route.params.id.toString())) {
this.localPartEntry.id = element.id;
this.localPartEntry.partNumber = element.partNumber;
this.localPartEntry.variant = element.variant;
this.localPartEntry.revision = element.revision;
this.localPartEntry.description = element.description;
this.localPartEntry.supplier = element.supplier;
this.localPartEntry.previewImagePath = element.previewImagePath;
this.localPartEntry.previewImageDateTime = element.previewImageDateTime;
this.localPartEntry.obsolete = element.obsolete;
this.localPartEntry.internalOnly = element.internalOnly;
this.loaded = true;
break;
}
}
},
});
</script>
And finally, the css:
<style lang="sass" scoped>
#editEntryDiv
width: 100%
height: 100%
background: $primary-background
display: flex
flex-direction: column
overflow-y: auto
-ms-overflow-style: none // for Internet Explorer, Edge */
scrollbar-width: none // for Firefox */
&::-webkit-scrollbar
display: none // for Chrome, Safari, and Opera */
#mainContent
margin-top: 1rem
margin-bottom: 5rem
flex-grow: 1
#submitButton
border: 1px solid $primary-accent-color
font-size: 1.5rem
border-radius: .25rem
cursor: pointer
padding: .25rem .75rem
transition: background .3s, color .3s
color: $primary-accent-color
background: transparent
display: flex
flex-direction: row
justify-content: center
align-items: center
gap: .5rem
&:hover
color: $tertiary-background
background: $primary-accent-color
.disabled
background: grey !important
#deleteButton
border: 1px solid $primary-accent-color
font-size: 1.5rem
border-radius: .25rem
cursor: pointer
padding: .25rem .75rem
transition: background .3s, color .3s
color: $primary-accent-color
background: transparent
display: flex
flex-direction: row
justify-content: center
align-items: center
gap: .5rem
&:hover
color: $tertiary-background
background: $primary-accent-color
.actionBar
width: 100%
min-height: 4rem !important
background: $secondary-background
display: flex
justify-content: space-between
position: fixed
bottom: 0px
right: 0px
&>div
display: flex
flex-direction: row
align-items: center
gap: 1rem
margin: 0 1rem
</style>
You can just check with Logical NOT (!) operator which takes truth to falsity and vice versa. Hence, If there will be no value in the textarea it will return false else true.
Working Demo :
new Vue({
el: '#app',
data: {
content: ''
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
Textarea content: {{ content }}
<br><br>
<textarea v-model="content"></textarea>
<button id="submitButton" :disabled="!content.trim()">
<span>Submit</span>
</button>
</div>
I just added an example to show you how to achieve. You can made the changes in your original code.

Flexbox spacing items in nav bar

I'm trying to space items within a nav bar where I have tags and search bar. I tried space-between, but not show how to properly position the search bar to get it to be slightly larger. Is this some combo of flex-end?
Attempt
Mock-Up
The box on the right should be slightly larger.
Code
Container
const TagsContainer = styled.div`
display: flex;
width: 100%;
margin-top: 15px;
`
export default function Tags() {
return (
<TagsContainer>
<Tag>Algorithms</Tag>
<Tag>Videos</Tag>
<Tag>Books</Tag>
<Tag>Tutorials</Tag>
<Tag>Health</Tag>
<Tag>Finance</Tag>
<Tag>Rants</Tag>
<Tag>Stream</Tag>
<Tag>Music</Tag>
<Search />
</TagsContainer>
)
}
Tag
const TagContainer = styled.div`
height: 100%;
max-height: 40px;
opacity: .8;
text-align: center;
`
const TagStyle = styled.span`
font-family: 'Lora';
min-width: 80px;
color: white;
padding: 10px;
border: 1px solid white;
font-size: 15px;
`
export default function Tag({ children }) {
return (
<>
<TagContainer>
<TagStyle>
{ children }
</TagStyle>
</TagContainer>
</>
)
}
Search
const SearchContainer = styled.div`
color: white;
border: 1px solid black;
flex-grow: 2;
min-height: 40px;
height: 100%;
`
export default function Search() {
return (
<>
<SearchContainer>
This is a search box
</SearchContainer>
</>
)
}
Add flex-grow: 1; to TagContainer to allow all flex items to grow

the table border-bottom disappear?

I try to implement a table with large size of data. then due to the performance issue, I just want to render the data in the body window.
But the new render element border disappear.
HTML:
<script src="//unpkg.com/vue#2.5.15/dist/vue.js"></script>
<script type="text/x-template" id="list-template">
<div class='table-body' ref="body" #scroll="handleScroll">
<div class="list-view">
<div
class="list-view-phantom"
:style="{
height: contentHeight
}">
</div>
<div class="list-view-colgroup">
<div class="list-view-item-col-g" v-for='count in 5'>
</div>
</div>
<div
ref="content"
class="list-view-content">
<ul
class="list-view-item"
:style="{
height: itemHeight + 'px'
}"
v-for="item in visibleData" :key='item.value'>
<li class="list-view-item-col" v-for='count in 5'>
{{item.value+count}}
</li>
</ul>
</div>
</div>
</div>
</script>
<div id="app">
<template>
<list-view :data="data"></list-view>
</template>
</div>
JS:
const ListView = {
name: 'ListView',
template: '#list-template',
props: {
data: {
type: Array,
required: true
},
itemHeight: {
type: Number,
default: 30
}
},
computed: {
contentHeight() {
return this.data.length * this.itemHeight + 'px';
}
},
mounted() {
this.updateVisibleData();
},
data() {
return {
visibleData: []
};
},
methods: {
updateVisibleData(scrollTop) {
scrollTop = scrollTop || 0;
const visibleCount = Math.ceil(this.$el.clientHeight / this.itemHeight);
const start = Math.floor(scrollTop / this.itemHeight);
const end = start + visibleCount;
this.visibleData = this.data.slice(start, end);
this.$refs.content.style.transform = `translate3d(0, ${ start * this.itemHeight }px, 0)`;
},
handleScroll() {
const scrollTop = this.$refs.body.scrollTop;
this.updateVisibleData(scrollTop);
}
}
};
new Vue({
components: {
ListView
},
data() {
const data = [];
for (let i = 0; i < 1000; i++) {
data.push({ value: i });
}
return {
data
};
}
}).$mount('#app')
code example:
https://jsfiddle.net/441701328/hq1ej6bx/6/
you can see only the data render in the first time can have border.
could anyone help?
thanks all!!!
table-row-group does not work with divs you can change the whole layout and use tables or instead you can do it like this.
.list-view-item {
padding: 5px;
color: #666;
display: table;
line-height: 30px;
box-sizing: border-box;
border-bottom: 1px solid red;
min-width: 100vw;
}
.list-view-item-col {
display: table-cell;
min-width: 50px;
}
jsfiddle for table-row-group
Hope it helps.
Use display :flex for list-view-item class, Try with following code.Hope it will work fine for you.
.list-view-item {
padding: 5px;
color: #666;
display: flex;
flex-basis: 100%;
flex-direction: row;
line-height: 30px;
box-sizing: border-box;
border-bottom: 1px solid red;
}
Try with this CSS. I hope it will works for you.
.list-view-item {
padding: 5px;
color: #666;
display:table;
line-height: 30px;
box-sizing: border-box;
border-bottom: 1px solid green;
}
I try to change the js code :
this.$refs.content.style.transform = `translateY(0, ${ start * this.itemHeight }px, 0)`;
to :
this.$refs.content.style.transform = `translateY(${ start * this.itemHeight }px)`;
and add a css to div class is list-view:
transform:translateY(0)px;
then the border showed.
don't understand why this action work!
.list-view-item {
padding: 5px;
color: #666;
display: flex;
flex-basis: 100%;
flex-direction: row;
line-height: 30px;
box-sizing: border-box;
border-bottom: 1px solid red;
}