Array of one element in Stylus - stylus

When I define new component, I need to specify how much this component must retire from other components (by other words, define margin-top; mixin WhenItJustAfter do it), and how much other components must retire from new component (mixin RulesForTargetThatGoingJustAfterIt do it):
WhenItJustAfter(targetElementSelector)
/{targetElementSelector} + {selector()}
{block}
RulesForTargetThatGoingJustAfterIt(targetElementSelector)
/{selector()} + {targetElementSelector}
{block}
provideBlockquoteComponent(
CSS_Namespace = "Blockquote",
positionalRelationshipWithOtherComponents = null
)
.Blockquote
// ...
if positionalRelationshipWithOtherComponents
for component in positionalRelationshipWithOtherComponents
+WhenItJustAfter("." + component.CSS_Class)
margin-top: component.whenJustBeforeIt
+RulesForTargetThatGoingJustAfterIt("." + component.CSS_Class)
margin-top: component.whenItJustAfter
Now we can define positional relationship between components as (sorry for long line, I did not explore yet how elegantly to break it in Stylus):
provideBlockquoteComponent(
positionalRelationshipWithOtherComponents: ({ CSS_Class: "AlertBox", whenJustBeforeIt: 6px, whenItJustAfter: 12px } { CSS_Class: "Image", whenJustBeforeIt: 12px, whenItJustAfter: 22px })
)
It will work for arrays of two and more elements; debug output will be:
inspect: {"CSS_Class":"(\"AlertBox\")","whenJustBeforeIt":"(12px)","whenItJustAfter":"(22px)"}
inspect: {"CSS_Class":"(\"Image\")","whenJustBeforeIt":"(12px)","whenItJustAfter":"(22px)"}
But what if positionalRelationshipWithOtherComponents will contain just one element?
provideBlockquoteComponent(
positionalRelationshipWithOtherComponents: ({ CSS_Class: "AlertBox", whenJustBeforeIt: 6px, whenItJustAfter: 12px })
)
We get:
inspect: 'CSS_Class'
inspect: 'whenJustBeforeIt'
inspect: 'whenItJustAfter'
Thereby positionalRelationshipWithOtherComponents is not array for Stylus anymore; Stylus iterated the properties keys instead of array elements.
I did not found the array literal for Stylus. If it exists, please teach me this literal, otherwise please suggest the workaround.

Related

concat strings to Reference react fc prop by constructed name from inside the component

I have a series of commonly named properties, and I'd like to have the un-common part of the name used in other places. I know that wording is a little convoluted, but perhaps an example will help. What I want is something like:
const MyComponent = ({lgProp, xlProp, mdProp, smProp, defaultProp}) => {
let current = defaultProp;
let myString = 'foo';
['sm', 'md', 'lg', 'xl'].forEach(size => {
const newValue = // somehow get the value of the property ${size}Prop
if (current !== newValue) {
myString += ` ${size}: ${newValue}`;
current = newValue;
}
});
}
The canonical answer to this type of question seems to be here, but all of the answers there either refer to dynamically referencing keys in objects, or dynamically referencing variables in pure JS in the Window or this scope. I can't seem to make any of them work for referencing property names.
There are also several sections on dynamically creating property names for components, but that's the wrong direction for me.
Things I've tried:
newValue = `${size}Prop`; // string
newValue = [`${size}Prop`]; // string
newValue = [${size} + 'Prop']; // string
newValue = this[${size} + 'Prop'] // TypeError
I mean, there are only so many props, so I could just write a bunch of if statements, but that seems so inelegant. Is there an attractive/elegant way to variably reference the prop names?

Unable to spread an array inside a template literal

I have the following component where I am trying to pass in values
meant to be used for linear gradient values in my styling.
colors is an array thus expecting it to be spreadable as follows.
...gradientProps.colors
But this doesn't work with following error:
TS2349: This expression is not callable.   Type 'Element' has no call
signatures.
New to typescript and googling around shows spread operator works over an array.
What am I doing wrong here?
interface GradientProps {
angle?: string;
colors?: string[];
}
interface Props {
// 10 other props
gradientProps?: GradientProps;
}
const MyComponent = ({
// 10 other props
gradientProps,
}: Props): React.ReactElement => {
return (
<div
style={{
// Error is with ${...gradientProps.colors}
backgroundImage: `url('www.aaa.com/some.png') linear-gradient(${gradientProps.angle}, ${...gradientProps.colors})`,
}}
>
{(<div>{''}</div>)}
</div>
);
};
With the props filled up after spreading, expecting the backgroundImage's value to look as follows:
background-image: linear-gradient(45deg, red, yellow, blue);
The spread syntax is not a standalone construct. It can only be used in certain places. I'm rather partial to MDN's documentation on it:
Spread syntax (...) allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.
For this case, getting a comma-delimited list out of an array, is taken care of by good old join, which by default, uses comma as a delimiter.
backgroundImage: `url('www.aaa.com/some.png') linear-gradient(${gradientProps.angle}, ${gradientProps.colors.join()})`,

NGRX - can't set the state tree as I would like it to be

So I'm using ngrx for managing the state in my application. I tried to add a new property (selected shifts) which should look like this:
state: {
shifts: {
selectedShifts: [
[employeeId]: [
[shiftId]: shift
]
]
}
}
at the moment, my state looks like this:
state: {
selectedShifts: {
[employeeId]: {
[shiftId]: shift
}
}
}
so as you can see, my "selected shift" is a property, not an array - which makes it diffictult to add/remove/query the state.
How do I compose the state to look like I want it?
This is what I tried in the reducer:
return {
...state,
selectedShifts: {
...state.selectedShifts,
[action.payload.employeeId]: {
...state.selectedShifts[action.payload.employeeId],
[action.payload.shiftId]: action.payload[shift.shiftId]
}
}
};
Now when I try to return the state in the way I'd like to, this is the result:
state: {
selectedShifts: {
[action.payload.employeeId]:
[0]: {[action.payload.shiftId]: { shift }}
}
}
What am I missing here? When I try to replace the {} items which should be [] this error comes up: "," expected.
Oh yea, I would like the index of the array to be the id of the specific shift and not [0], [1]...
Is this possible at all?
Would it be a bad idea to change the index from numerics to the actual shift's id?
Array length kind of miss behaves when you add data at numeric index points. This might get you into problems with array methods using length join, slice, indexOf etc. & array methods altering length push, splice, etc.
var fruits = [];
fruits.push('banana', 'apple', 'peach');
console.log(fruits.length); // 3
When setting a property on a JavaScript array when the property is a valid array index and that index is outside the current bounds of the array, the engine will update the array's length property accordingly:
fruits[5] = 'mango';
console.log(fruits[5]); // 'mango'
console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
console.log(fruits.length); // 6
There is no problem selecting / updating state from object, it's just a bit different from what you're probably used to. With straight hashmap { objectId: Object } finding the required object to update / remove is the fastest possible if changes are defined for object id.
I know your problem is related to NGRX but reading Redux immutable patterns is going to definitely help you out here for add / update / remove objects from the state. https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns
Generally you don't want to have arrays in state ( at least large arrays ) object hashmaps are a lot better.
To get array of your selected user shifts for views you could do something like. Note this is not a shift indexed array just array of shifts under userId property. From original state form following state.
state: {
selectedShifts: {
[employeeId]: {
[shiftId]: shift
}
}
}
const getSelectedShiftsAsArray = this.store.select( getSelectedShifts() )
.map(
userShifts => {
// get array of object ids
const userIds = Object.keys( userShifts );
const ret = {};
for( const userId of userIds ) {
const collectedShifts = [];
// convert Dictionary<Shift> into a Shift[]
// get array of shift ids
const shiftIds = Object.keys( userShifts[userId] );
// map array of shift ids into shift object array
collectedShifts = shiftIds.map( shiftId => userShifts[shiftId] );
// return value for a userId
ret[userId] = collectedShifts;
}
return ret;
});
Code is completely untested and just for a reference one level up from pseudocode. You could easily convert that into a NGRX selector though. The state is there just for the storage, how you model it for use in components is upto selector functions & components themselves.
If you really really need it you could add.
ret[userId].shiftIds = shiftIds;
ret[userId].shifts = collectedShifts;
But it really depends on how you plan to use these.
From my personal experience I would separate shift entities from selectedShifts but how you organise your state is completely up to you.
state: {
shifts: {
// contains shift entities as object property map id: entity
entities: Dictionary<Shift>,
selectedShifts: [
[employeeId]: number[] // contains ids for shifts
]
}
}
Now updating / removing and adding a shift would just be setting updated data into path shifts.entities[entityId]
Also selectedShifts for employeeId would be about checking if id is already in there and appending it into an array if it wasn't. ( If these arrays are humongous I'd go with object hash here too for fast access. <employeeId>: {shiftId:shiftId} ).
Check also:
redux: state as array of objects vs object keyed by id

Angular 2 / Typescript - how to check an array of objects to see if a property has the same value?

This question does it in Javascript, but I would have thought in Typescript I could do some kind of map/filter operation to do the same thing.
I have an array of objects called Room. Each Room has a property called Width (which is actually a string, eg '4m', '5m', '6.5m').
I need to check the entire array to see if all the widths are the same.
Based on that question I have this, but I was wondering if TypeScript has something better:
let areWidthsTheSame = true;
this.qp.rooms.forEach(function(room, index, rooms) {
if (rooms[index] != rooms[index+1]) areWidthsTheSame = false;
});
Any ideas?
FYI the linked question has a comment that links to these performance tests, which are interesting in the context of this question:
This can be done in the following way:
const widthArr = rooms.map(r => r.width);
const isSameWidth = widthArr.length === 0 ? true :
widthArr.every(val => val === widthArr[0]);
We first convert the rooms array to an array of widths and then we check if all values in widths arrays are equal.

stylus mixin with &:nth-of-type

I would like something like this
number(x)
&:nth-of-type(x)
Mostly just for readability - and for a basic example of when I might need to use the & in a mixin...
li //
number(1)
color: red
number(2)
color: blue
To yield...
li //
&:nth-of-type(1)
color: red
&:nth-of-type(2)
color: blue
Is this possible? Escaping ... ? ? ?
for my break-points... i use a variable --- but can't here
#media break-point-1 etc...
I'm afraid you can create shortcut like that
But you can use this mixin
setColors(colorList)
for col, index in colorList
&:nth-child({index})
color: col;
setColors(red blue);
This is a very old question and I am sure you found a solution a long time ago but there isn´t an accepted answer and maybe is useful for other users.
To use variables in selectors, they must be enclosed in braces (interpolation). To get the content in the mixin, use the block mixin feature:
Stylus
number(x)
&:nth-of-type({x})
{block}
li
+number(1)
color red
+number(2)
color blue
CSS:
li:nth-of-type(1) {
color: #f00;
}
li:nth-of-type(2) {
color: #00f;
}

Resources