I am teaching myself to React. I have created a little project to familiarise myself with React. I basically want the slider to adjust the grid size below. However, when changing the slider, it re-renders completely incorrectly. What it should do is create a square grid, with the dimensions equal to the slider value. The grid should always be square, and as the slider value changes, so should the height and width of the square.
The right-hand side column should have 1 column, but as many rows as the square on the left. Right now it does not grow or shrink with the slider. Any changes to the slider value just create 2 squares, with no relation to the slider value.
Before:
After:
Here is what the code looks like (simply paste into App.js after running NPX-create-react-app). If someone could explain how I can get this to work as intended it would be appreciated:
import React, { useState } from "react";
import "./App.css";
class Matrix {
constructor(rows, cols) {
this.rows = rows;
this.cols = cols;
this.size = rows * cols;
this.values = new Array(this.size).fill("");
}
}
function Cell(props) {
return (
<input
className="matrix-component"
id={props.id}
value={props.value}
onChange={(e) => props.onChange(props.id, e.target.value)}
></input>
);
}
function App() {
let [dim, setDim] = useState(3);
let [matrix, setMatrix] = useState(new Matrix(dim, dim));
let [rhs, setRHS] = useState(new Matrix(dim, 1));
function updateMatrix(i, value) {
let new_values = matrix.values.slice();
let new_matrix = new Matrix(matrix.rows, matrix.cols);
new_values[i] = value;
new_matrix.values = new_values;
setMatrix(new_matrix);
}
function updateRHS(i, value) {
let index = i.replace(/\D/g, "");
let new_values = rhs.values.slice();
let new_matrix = new Matrix(matrix.rows, 1);
new_values[index] = value;
new_matrix.values = new_values;
setRHS(new_matrix);
}
function updateSlider(value) {
setDim(value);
}
function handleClick() {
console.log(matrix.values);
console.log(rhs.values);
}
return (
<div className="App">
<div className="content">
<div className="matrix">
<div>
{Array.apply(null, Array(dim)).map(function (x, i) {
const col = Array.apply(null, Array(dim)).map(function (y, j) {
return (
<Cell
key={i * dim + j}
id={i * dim + j}
value={matrix.values[i * dim + j]}
onChange={updateMatrix}
/>
);
});
return <div key={i}>{col}</div>;
})}
</div>
<div>
<div className="rhs">
{Array.apply(null, Array(dim)).map(function (x, i) {
return (
<Cell
key={"rhs" + i}
id={"rhs" + i}
value={rhs.values[i]}
onChange={updateRHS}
/>
);
})}
</div>
</div>
</div>
<button onClick={handleClick}>Solve</button>
</div>
<input
type="range"
min="3"
max="10"
value={dim}
onChange={(event) => updateSlider(event.target.value)}
></input>
</div>
);
}
export default App;
.App {
text-align: center;
width: 500px;
margin: auto;
/* background: grey; */
}
.matrix {
/* float: left; */
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(1, 1fr);
grid-column-gap: 0px;
grid-row-gap: 0px;
padding: 10px;
margin: 10px;
}
.matrix-component {
border-width: thin;
border-style: solid;
border-color: black;
width: 50px;
height: 50px;
}
.rhs {
margin-left: 40px;
display: grid;
}
function updateSlider(value) {
setDim(value);
}
The event.target.value is a string, so you switch dim from an integer to a string. If you convert value into an integer it'll work correctly.
function updateSlider(value) {
setDim(parseInt(value, 10));
}
Related
I am trying to show blur hash on my images in my angular application before they fully load. But I'm getting the canvas context as undefined inside my function. I can't figure out where the problem is occurring.
I am using the blurhash package.
My code is as follows:
#ViewChild('imageCanvas', {static: false}) imageCanvas: ElementRef<HTMLCanvasElement>;
private context: CanvasRenderingContext2D;
ngAfterViewInit() {
this.getLatestClubPosts()
}
getLatestClubPosts() {
let tempPosts = [];
this._postService
.getClubPosts("Club", 0, 15).pipe(takeUntil(this.destroy$))
.subscribe((res: ApiResponse<any>) => {
res.data.map((singleClubPost: Post, idx, self) => {
this._postService
.getPostCommentsAndReactions(singleClubPost.id, 0, 4)
.subscribe((reactionsAndComments: ApiResponse<any>) => {
singleClubPost.reactionCount =
reactionsAndComments.data.count.reactionCount;
singleClubPost.commentsCount =
reactionsAndComments.data.count.commentsCount;
singleClubPost.reactions = reactionsAndComments.data.reaction;
if(singleClubPost.captureFileURL !== '') {
singleClubPost.media.forEach((image, i) => {
const validRes = isBlurhashValid(image.blurHash);
if(validRes.result == true) {
this.cf.detectChanges();
const blurhashPixels = decode(image.blurHash, 200, 200);
this.context = this.imageCanvas?.nativeElement?.getContext("2d"); //where the error occurs
const imageData = this.context?.createImageData(200, 200);
if (!imageData) {
this.toast.error('Could not prepare Blurhash canvas', 'Error');
}
else {
imageData?.data.set(blurhashPixels)
}
}
})
}
tempPosts.push(singleClubPost);
if (idx == self.length - 1) {
tempPosts.sort(function compare(a, b) {
const dateA = new Date(a.postedDate) as any;
const dateB = new Date(b.postedDate) as any;
return dateB - dateA;
});
this.recentClubPosts = tempPosts;
console.log(this.recentClubPosts)
this.cf.detectChanges();
}
});
});
});
}
My HTML is as follows:
<ng-container *ngFor="let media of post.media; let i = index;">
<img *ngIf="media.blurHash === undefined" [src]="media.captureFileURL"
style="
flex-grow: 1;
flex-direction: row;
flex-wrap: wrap;
display: block;
padding: 0.2em;
box-sizing: border-box;
width: 50%;
height: 400px;
object-fit: cover;
border-radius: 12px;
" />
<canvas #imageCanvas *ngIf="media.blurHash !== undefined" style="
flex-grow: 1;
flex-direction: row;
flex-wrap: wrap;
display: block;
padding: 0.2em;
box-sizing: border-box;
width: 50%;
height: 400px;
object-fit: cover;
border-radius: 12px;">
</canvas>
</ng-container>
Even when I am calling this function inside AfterViewInit it still gives the same error: this.context is undefined. I am really stuck and any help is greatly appreciated. Thanks!
This page can have three or two columns, depending on the content. When there are three columns, it should display all three columns for desktop then stack to one column on tablet and mobile. When there are two columns, it should display all two columns for desktop then stack to one column on tablet and mobile. But, I can't get it to do that. Instead, when there are three columns, at about 1200px, the third column wraps. So it ends up looking like this:
[1][2]
[3]
HTML
<div class="offers-wrap">
{% for offer in offers %}
<div class="offer justify-evenly"></div>
{% endfor %}
</div>
CSS
.offers-wrap {
display: grid;
grid-gap: 2rem;
gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(auto, 350px));
justify-content: center;
}
.offer {
max-width: 28rem;
margin-left: auto;
margin-right: auto;
width: 100%;
}
You need to add a media-query to your css that changes the width of your grid-columns to 100%. Like this:
<style>
.offers-wrap {
display: grid;
grid-gap: 2rem;
gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(auto, 350px));
justify-content: center;
}
.offer {
max-width: 28rem;
margin-left: auto;
margin-right: auto;
width: 100%;
}
#media (max-width: 1129px) {
.offers-wrap {
grid-template-columns: repeat(auto-fit, minmax(auto, 100%));
}
}
</style>
<div class="offers-wrap">
<div class="offer justify-evenly">
test
</div>
<div class="offer justify-evenly">
test
</div>
<div class="offer justify-evenly">
test
</div>
</div>
I ended up expanding a little on what Yannick H has
.offers-wrap {
display: grid;
grid-gap: 2rem;
gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(auto, 100%));
justify-content: center;
}
#media (min-width: 1024px) {
.offers-wrap {
grid-template-columns: repeat(auto-fit, minmax(auto, 275px));
}
}
#media (min-width: 1280px) {
.offers-wrap {
grid-template-columns: repeat(auto-fit, minmax(auto, 375px));
}
}
Here's one way to do what you ask:
//<![CDATA[
/* js/external.js */
let get, post, doc, htm, bod, nav, M, I, mobile, beacon, S, Q, hC, aC, rC, tC, inArray, shuffle, isNum, isInt, rand;
addEventListener('load', ()=>{
get = (url, func, responseType = 'json', context = null)=>{
const x = new XMLHttpRequest;
const c = context || x;
x.open('GET', url); x.responseType = responseType;
x.onload = ()=>{
if(func)func.call(c, x.response);
}
x.onerror = e=>{
if(func)func.call(c, {xhrErrorEvent:e});
}
x.send();
return x;
}
post = function(url, send, func, responseType ='json', context = null){
const x = new XMLHttpRequest;
if(typeof send === 'object' && send && !(send instanceof Array)){
const c = context || x;
x.open('POST', url); x.responseType = responseType;
x.onload = ()=>{
if(func)func.call(c, x.response);
}
x.onerror = e=>{
if(func)func.call(c, {xhrErrorEvent:e});
}
let d;
if(send instanceof FormData){
d = send;
}
else{
let s;
d = new FormData;
for(let k in send){
s = send[k];
if(typeof s === 'object' && s)s = JSON.stringify(s);
d.append(k, s);
}
}
x.send(d);
}
else{
throw new Error('send argument must be an Object');
}
return x;
}
doc = document; htm = doc.documentElement; bod = doc.body; nav = navigator; M = tag=>doc.createElement(tag); I = id=>doc.getElementById(id);
mobile = nav.userAgent.match(/Mobi/i) ? true : false;
beacon = function(url, send){
let r = false;
if(typeof send === 'object' && send && !(send instanceof Array)){
let d;
if(send instanceof FormData){
d = send;
}
else{
let s;
d = new FormData;
for(let k in send){
s = send[k];
if(typeof s === 'object' && s)s = JSON.stringify(s);
d.append(k, s);
}
}
r = nav.sendBeacon(url, d);
}
else{
throw new Error('send argument must be an Object');
}
return r;
}
S = (selector, within)=>{
var w = within || doc;
return w.querySelector(selector);
}
Q = (selector, within)=>{
var w = within || doc;
return w.querySelectorAll(selector);
}
hC = function(node, className){
return node.classList.contains(className);
}
aC = function(){
const a = [...arguments];
a.shift().classList.add(...a);
return aC;
}
rC = function(){
const a = [...arguments];
a.shift().classList.remove(...a);
return rC;
}
tC = function(){
const a = [...arguments];
a.shift().classList.toggle(...a);
return tC;
}
inArray = (mixed, array)=>{
if(array.indexOf(mixed) === -1){
return false;
}
return true;
}
shuffle = array=>{
let a = array.slice(), i = a.length, n, h;
while(i){
n = Math.floor(Math.random()*i--); h = a[i]; a[i] = a[n]; a[n] = h;
}
return a;
}
isNum = mixed=>typeof mixed === 'number' && !isNaN(mixed); isInt = mixed=>Number.isInteger(mixed);
rand = (min, max)=>{
let mn = min, mx = max;
if(mx === undefined){
mx = mn; mn = 0;
}
return mn+Math.floor(Math.random()*(mx-mn+1));
}
// above is a library for you to learn - below is mobile test
const wrap = I('wrap');
if(mobile){
aC(wrap, 'mobile');
}
}); // end load
/* css/external.css */
*{
box-sizing:border-box;
}
html,body{
background:#ccc; margin:0;
}
#wrap{
display:grid; grid-template-columns:repeat(3, 1fr); grid-auto-rows:auto; height:100vh;
}
#wrap.mobile{
grid-template-columns:repeat(2, 1fr);
}
#wrap>div{
display:flex; justify-content:center; align-items:center; height:100%; background:#fff;
}
#wrap>div:nth-child(odd){
background:#000; color:#fff;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1, user-scalable=no' />
<title>Title Here</title>
<link type='text/css' rel='stylesheet' href='css/external.css' />
<script src='js/external.js'></script>
</head>
<body>
<div id='wrap'>
<div><div>one</div></div>
<div><div>two</div></div>
<div><div>three</div></div>
<div><div>four</div></div>
<div><div>five</div></div>
<div><div>six</div></div>
<div><div>seven</div></div>
</div>
</body>
</html>
Note that I put a small JavaScript library in there so you can see how to reduce code. The library also does a simple mobile test, as well. Also, notice that I had to add another <div> within your content <div>s, so I could align the text too. You'll notice that the actual JavaScript to accomplish the adding of an HTML class with aC is under the // above is a library for you to learn - below is mobile test comment.
New to Grid in CSS and, of course, starting with a more convoluted need.
Think an airport Arrivals/Departures display. No keyboard, no mouse, no human interaction. This callout app used to be just one big long scrolling list. I am turning it into a little more organized layout. Depending on what screen it finally shows up on it may have room for 2 columns, 3 columns maybe even 5 columns - where each column is the same width and there is a minimum width.
1st row: header / full width / 3 lines of text
2nd row: should be equal to the remaining height, full width and is a container
In the container:
2 rows (title row, contents row)
N columns (where column has min-width) --> also a view panel for text in a marquee (vert
scrolling via js)
#model wsGT4.Models.DictionaryResultSet<string, List<wsGT4.Models.Callout>>
#{
ViewBag.Title = "Callout";
Layout = "~/Views/Shared/_EmptyLayout.cshtml";
}
<section class="header">
<H1>TOMORROW'S CALLOUTS WILL DISPLAY STARTING AT 5PM</H1>
<H2>BRING DOCS TO CALLOUTS</H2>
#if (Model.Success == false)
{
foreach (var msg in Model.Messages)
{
<h2>#msg</h2>
}
}
else
{
if (DateTime.Now.AddHours(Model.TimezoneOffset).Hour >= 17)
{
<h2>CALLOUTS FOR <span style="color:red; background-color: yellow;">TOMORROW</span> - #DateTime.Now.AddDays(1).ToString("MMM dd") <span style="font-size:.6em">(#DateTime.Now.AddHours(Model.TimezoneOffset).ToString("HH:mm"))</span></h2>
}
else
{
<h2>CALLOUTS FOR TODAY - #DateTime.Now.ToString("MMM dd") <span style="font-size:.6em">(#DateTime.Now.AddHours(Model.TimezoneOffset).ToString("HH:mm"))</span></h2>
}
}
</section>
<section class="container">
#foreach (var kvp in Model.ResultList.OrderBy(a => a.Key))
{
<div class="timeDisplay">
>>> #kvp.Key
</div>
<div class="viewPort">
<div class="textList">
#foreach (var subject in kvp.Value.OrderBy(a => a.LastName).ThenBy(a => a.SubjectId))
{
<span>#subject.LastName</span>
<span>##subject.SubjectId</span>
<span>#subject.EventTitle</span>
}
</div>
</div>
}
</section>
CSS (which I am royally screwing up)
.header {
padding: 5px;
border: groove;
border-bottom-color: black;
border-width: 2px;
/* Grid styles */
display: grid;
align-items: center;
/*grid-template-columns: 1fr;*/
grid-template-rows: repeat(3, 1fr);
}
.container {
max-height: 100vh;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 30px auto-fill;
grid-gap: 5px;
}
.timeDisplay{
max-height: 30px;
}
.viewPort {
height: 100%;
overflow: hidden;
}
.textList {
height: 100%;
font-size: 125%;
display: grid;
grid-template-columns: 3fr 2fr 5fr;
}
Since the model collection coming back can have an unknown number of time/list sets I am trying to let automation do some of the work. The idea being that if I have more columns than what can fit then they are either (A) not displayed or (B) wrap below the bottom of the screen, effectively being hidden.
So I changed my approach a little bit after diving into flex vs grid in CSS. The container got rewritten this way:
<section class="wrapper">
<ul class="colList">
#foreach (var kvp in Model.ResultList.OrderBy(a => a.Key))
{
<li class="columnItem">
<div class="columnTitle--wrapper">
<h2>>>> #kvp.Key</h2>
</div>
<div class="cardViewer">
<div class="cardList">
<ul class="cardList--ul">
#foreach (var subject in kvp.Value.OrderBy(a => a.EventTitle).ThenBy(a => a.LastName).ThenBy(a => a.SubjectId))
{
<li class="cardItem">
<h3>#subject.EventTitle.ToUpper()</h3>
<h3>#subject.LastName.ToUpper()</h3>
<h3>##subject.SubjectId.ToUpper()</h3>
</li>
}
</ul>
</div>
</div>
</li>
}
</ul>
</section>
and the CSS turned into:
/* column styles */
.wrapper {
}
.colList {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
grid-gap: .5rem;
align-items: start;
top: 500vh;
}
.columnItem {
border-radius: .2rem;
padding: .5rem;
}
.columnTitle--wrapper {
}
.columnTitle--wrapper h2 {
font-weight: 700;
}
/* card styles */
.cardViewer {
overflow: hidden;
height: 80vh;
max-height: 80vh;
}
.cardList {
position: relative;
}
.cardList--ul {
display: grid;
grid-template-rows: auto;
grid-gap: .5rem;
margin: .5rem 0;
}
.cardItem {
background-color: white;
border: 1px solid #BBB;
border-radius: .25rem;
box-shadow: 0 1px 0 rgba(9,45,66,.25);
padding: .5rem;
display: grid;
grid-template-columns: 5fr 7fr 2fr;
}
And I added JS to handle multiple marquees when needed (list was too long for the viewport):
class marqueeInfo {
constructor(viewer, cardList) {
this.viewer = viewer;
this.cardList = cardList;
if (this.isScrollable) {
this.cardList.style.top = parseInt(this.viewerHeight()) + "px"
}
else {
this.cardList.style.top = "0px"
}
}
viewer() { return this.viewer; }
cardList() { return this.cardList; }
viewerHeight() { return this.viewer.offsetHeight; }
cardListHeight() { return this.cardList.offsetHeight; }
isScrollable() { return this.cardList.offsetHeight > this.viewer.offsetHeight; }
}
var marqueeArray = [];
var marqueeSpeed = 4 //Specify marquee scroll speed (larger is faster 1-10)
var delayb4scroll = 100 //Specify initial delay before marquee starts to scroll on page (2000=2 seconds)
var lastRefresh;
var isRefreshing = false;
var refreshMinutes = 1;
// may be overkill here...
if (window.addEventListener)
window.addEventListener("load", initializeMarqueeHandler, false)
else if (window.attachEvent)
window.attachEvent("onload", initializeMarqueeHandler)
else if (document.getElementById)
window.onload = initializeMarqueeHandler
function initializeMarqueeHandler() {
lastRefresh = new Date();
isRefreshing = false;
var viewers = document.getElementsByClassName("cardViewer");
var cards;
var i;
for (i = 0; i < viewers.length; i++) {
cards = viewers[i].getElementsByClassName("cardList");
if (cards.length != 1)
return;
marqueeArray.push(new marqueeInfo(viewers[i], cards[0]));
}
setTimeout('lefttime=setInterval("scrollMarquees()",30)', delayb4scroll)
}
function scrollMarquees() {
marqueeArray.forEach(function (marquee, index, array) {
if (marquee.isScrollable()) {
var cardHeight = marquee.cardListHeight();
var viewerHeight = marquee.viewerHeight();
var cardTop = parseInt(marquee.cardList.style.top);
var targetTop = 0 - cardHeight;
if (cardTop > targetTop) // are we thru the list?
marquee.cardList.style.top = cardTop - marqueeSpeed + "px" //scroll
else
marquee.cardList.style.top = viewerHeight + 25 + "px";
}
else {
marquee.cardList.style.top = "0px";
}
})
var milliseconds = (new Date()).getTime() - lastRefresh.getTime();
if (milliseconds > (refreshMinutes * 60 * 1000) && !isRefreshing) {
lastRefresh = new Date();
isRefreshing = true;
window.location.reload(true);
}
}
Everything is working as expected - finally.
I just started working with grid, making table component on React . Passing head titles and data as a props. I set repeat(auto-fit, minmax(10px, 1fr)); to my fit all head titles in one row . Now when I rendering data it does not goes to the next line , all in one line. How to fix that problem? You can check here https://codesandbox.io/s/goofy-easley-w5rrg
const TableWrapperUI = styled.div`
display: grid;
box-sizing: border-box;
width: 100%;
border: 1px solid black;
grid-template-columns: repeat(auto-fit, minmax(10px, 1fr));
justify-items: center;
grid-gap: 5px;
padding: 5px;
`;
const Table = ({ columns, children, titles,data }) => {
const [collapseElements, setCollapse] = useState({});
const displayData=(data)=>{
for (let i = 0; i < data.length; i++) {
return Object.keys(data[i]).map((value,ids)=>{
return <span key={ids}>{data[i][value]} </span>
})
}
}
const displayTitles = titles => {
return titles.map((title, idx) => {
return <span key={idx}>{title}</span>;
});
};
return (
<TableWrapperUI columns={columns}>{displayTitles(titles)} {displayData(data)}</TableWrapperUI>
);
};
You can use table tag to format data properly.
import React, { Fragment, useState } from "react";
import styled, { css } from "styled-components";
const TableWrapperUI = styled.div`
display: grid;
box-sizing: border-box;
width: 100%;
border: 1px solid black;
grid-template-columns: repeat(auto-fit, minmax(10px, 1fr));
justify-items: center;
grid-gap: 5px;
padding: 5px;
`;
const Table = ({ columns, children, titles, data }) => {
const [collapseElements, setCollapse] = useState({});
const displayData = data => {
for (let i = 0; i < data.length; i++) {
return Object.keys(data[i]).map((value, ids) => {
return <td key={ids}>{data[i][value]} </td>;
});
}
};
const displayTitles = titles => {
return titles.map((title, idx) => {
return <th key={idx}>{title}</th>;
});
};
return (
<>
<TableWrapperUI columns={columns}>
<table>
<thead>
<tr>{displayTitles(titles)}</tr>
</thead>
<tbody>
<tr>{displayData(data)}</tr>
</tbody>
</table>
</TableWrapperUI>
</>
);
};
export default Table;
Supposed to look like the below (does in Edge & Chrome):
But looks like this in Safari 10:
I've read a few SO questions that have not help resolve the issue. Most recently this one:
Flexbox not working on button or fieldset elements
The answers are not resolving my issue.
How do I get a new button to wrap to a new line instead of overflowing the container?
Here is the Sass and ReactJS component I have. Also, I am using Bootstrap 4.
class BasicQueryCuts extends Component {
constructor(props) {
super(props);
this.state = {
cuts: {}
}
this.clearSelection = this.clearSelection.bind(this);
this.selectAll = this.selectAll.bind(this);
}
clearSelection() {
this.setState({
cuts: {}
})
this.props.clearCuts();
}
// pieces together the cuts that are selected
onCutSelect(cut, str) {
// want to make sure it stays a number
// so that it matches the server data
// tends to convert to string if not specific
cut = Number(cut);
this.setState(
({cuts: prevCuts}) => (
this.state.cuts[cut] && str !== 'all'
?
{cuts: {...prevCuts, [cut]: undefined }}
:
{cuts: {...prevCuts, [cut]: cut }}
),
() => this.props.basicQueryResults(this.state.cuts)
)
}
selectAll() {
const { country } = this.props;
let { query_data } = this.props;
if (query_data) {
if (query_data[0].Country && country) {
var data = _.filter(query_data, {'Country': country});
} else {
var data = query_data;
}
}
_.map(
data, c => {
this.onCutSelect(c.SortOrder, 'all');
}
)
}
// These buttons will allow selecting everything, or clearing the selection
renderAllNothingButtons() {
let { query_data } = this.props;
// generate the list of cuts
if (query_data) {
return (
<Row>
<Col>
<Button color='primary' key='all' className='cuts-btn' onClick={this.selectAll}>
Select All
</Button>
</Col>
<Col>
<Button color='danger' key='cancel' className='cuts-btn' onClick={this.clearSelection}>
Clear All
</Button>
</Col>
</Row>
)
}
}
// renders the cut multi-list, by first ordering what comes from
// the server and then depending on the survey
// setting up the option and value keys
renderCutsButtons() {
const { country } = this.props;
let { query_data } = this.props;
if (query_data) {
if (query_data[0].Country && country) {
var data = _.filter(query_data, {'Country': country});
} else {
var data = query_data;
}
}
// generate the list of cuts
return (
<Row>
{_.map(data, c => {
var cut = c.RptCutCat + ': ' + c.RptCut
return (
<Col key={c.SortOrder}>
<Button
className={this.state.cuts[c.SortOrder] ? 'cuts-btn-active' : 'cuts-btn'}
key={c.SortOrder}
value={c.SortOrder}
onClick={event => this.onCutSelect(event.target.value, 'single')}
>
<span>{cut}</span>
</Button>
</Col>
)}
)}
</Row>
)
}
render() {
const { query_data } = this.props;
return (
<div className='results-bq-cuts'>
{this.renderCutsButtons()}
{query_data
?
<hr />
:
null
}
{this.renderAllNothingButtons()}
{query_data
?
<hr />
:
null
}
</div>
)
}
}
.results-modal {
#media all and (max-width: 1250px) {
max-width: 95%;
}
max-width: 1200px;
.modal-content {
.modal-body {
// padding: 0;
margin-left: 13px;
margin-right: 13px;
.results-bq-cuts {
.col {
padding:2px;
}
.cuts-btn {
font-size: 11px;
padding: 3px;
width: 100%;
box-shadow: none;
}
.cuts-btn-active {
font-size: 11px;
padding: 3px;
width: 100%;
background-color: $croner-blue;
box-shadow: none;
}
h5 {
text-align: left;
}
hr {
margin-top: 5px;
margin-bottom: 5px;
}
}
}
}
}
Compiled HTML here:
Turns out it was an issue with Safari 10.0.0. Upgraded the VM I have macOS running in which upgraded Safari and now the issue is gone. Saw some responses that seemed to indicate the issue was addressed in Safari 10.1.