@kaliber/build 0.0.135 → 0.0.136

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.135",
2
+ "version": "0.0.136",
3
3
  "name": "@kaliber/build",
4
4
  "description": "Zero configuration, opinionated webpack / react build setup",
5
5
  "scripts": {
@@ -1,6 +1,7 @@
1
1
  const {
2
2
  findDecls,
3
3
  parseSelector,
4
+ withRootRules,
4
5
  withNestedRules,
5
6
  isRoot, declMatches,
6
7
  getRootRules,
@@ -32,6 +33,9 @@ const messages = {
32
33
  `\`${prop}\` can only be used when the containing root rule has \`display: flex;\` or \`display: grid;\` - ` +
33
34
  `add \`display: flex;\` or \`display: grid;\` to the containing root rule or, if this is caused by a media query ` +
34
35
  `that overrides \`display: flex;\` or \`display: grid;\`, use \`${prop}: unset\``,
36
+ 'layoutClassname - must be nested in a parent selector':
37
+ `layoutClassNames (classes ending with the \`Layout\` suffix) can only be targetted by a parent selector, using the direct child selector. ` +
38
+ `Consequentially, you can only use layout related properties in layoutClassNames.`,
35
39
  'invalid pointer events':
36
40
  `Incorrect pointer events combination\n` +
37
41
  `you can only set pointer events in a child if the parent disables pointer events - ` +
@@ -40,10 +44,6 @@ const messages = {
40
44
  'Missing `position: relative;` in parent\n' +
41
45
  '`position: static` is only allowed when the containing root rule is set to `position: relative` - ' +
42
46
  'add `position-relative` to the containing root rule',
43
- 'missing relativeToParent className':
44
- 'Missing `.relativeToParent` className\n' +
45
- '`position: static` can only be used when selecting on `.relativeToParent` - ' +
46
- 'add the `.relativeToParent` className',
47
47
  }
48
48
 
49
49
  // TODO: move errors into the different relations (would allows us to simplify the actual checks)
@@ -123,6 +123,7 @@ module.exports = {
123
123
  requireDisplayFlexOrGridInParent({ root: modifiedRoot, report })
124
124
  validPointerEvents({ root: modifiedRoot, report })
125
125
  relativeToParent({ root: modifiedRoot, report })
126
+ requireLayoutClassNameToBeDirectChild({ root: modifiedRoot, report })
126
127
  }
127
128
  }
128
129
  }
@@ -192,14 +193,17 @@ function relativeToParent({ root, report }) {
192
193
  result.forEach(({ result, prop, triggerDecl, rootDecl, value, expectedValue }) => {
193
194
  report(triggerDecl, messages['missing position relative'])
194
195
  })
195
- const triggerDecls = findDecls(rule, childParentRelations.relativeToParent.nestedHasOneOf)
196
- triggerDecls.forEach(decl => {
197
- const selectors = parseSelector(rule)
198
- const hasValidSelectors = selectors.every(selector =>
199
- selector.some(x => x.type === 'class' && x.value === 'relativeToParent')
200
- )
201
- if (hasValidSelectors) return
202
- report(decl, messages['missing relativeToParent className'])
196
+ })
197
+ }
198
+
199
+ function requireLayoutClassNameToBeDirectChild({ root, report }) {
200
+ withRootRules(root, rule => {
201
+ if (!rule.selector.includes('Layout')) return
202
+ parseSelector(rule).nodes.forEach(node => {
203
+ const className = node.nodes.find(x => x.type === 'class')
204
+ if (className && className.toString().endsWith('Layout')) {
205
+ report(rule, messages['layoutClassname - must be nested in a parent selector'])
206
+ }
203
207
  })
204
208
  })
205
209
  }
@@ -6,9 +6,9 @@ This rule helps you to correctly create these parent / child relationships.
6
6
 
7
7
  - [Stacking context](#stacking-context)
8
8
  - [Position absolute](#position-absolute)
9
+ - [Escape stacking context with absolute children](#escape-stacking-context-with-absolute-children)
9
10
  - [Flex and Grid](#flex-and-grid)
10
11
  - [Pointer events](#pointer-events)
11
- - [Relative to parent](#relative-to-parent)
12
12
 
13
13
  ## Stacking context
14
14
 
@@ -68,9 +68,51 @@ When you given an element `position: absolute` the CSS engine will traverse its
68
68
 
69
69
  This rule forces you set `position: relative` on the parent element in order to prevent the element from escaping a known context. It ensures we stay true to the black-box principle.
70
70
 
71
- ## Relative to parent
71
+ ### Examples
72
+
73
+ Examples of *correct* code for this rule:
74
+
75
+ ```css
76
+ .parent {
77
+ position: relative;
78
+
79
+ & > .child {
80
+ position: absolute;
81
+ }
82
+ }
83
+ ```
84
+
85
+ ```css
86
+ .parent {
87
+ position: relative;
88
+
89
+ &::after {
90
+ position: absolute;
91
+ }
92
+ }
93
+ ```
94
+
95
+ Examples of *incorrect* code for this rule:
96
+
97
+ ```css
98
+ .parent {
99
+ & > .child {
100
+ position: absolute;
101
+ }
102
+ }
103
+ ```
104
+
105
+ ```css
106
+ .parent {
107
+ &::after {
108
+ position: absolute;
109
+ }
110
+ }
111
+ ```
112
+
113
+ ## Escape stacking context with absolute children
72
114
 
73
- In some case you need to allow a child element to escape from it's parents context. An example:
115
+ In some case you may need a child element to be relative to an element different from its parent: you want it to escape its parent's stacking context. An example:
74
116
 
75
117
  ```html
76
118
  <ul class='menu'>
@@ -108,15 +150,18 @@ In some case you need to allow a child element to escape from it's parents conte
108
150
  }
109
151
  ```
110
152
 
111
- The `position: absolute` property is marked as a problem because it escapes its parent. This means we need to add a `position: relative`.
153
+ The `position: absolute` property is marked as a problem because it escapes its parent's stacking context. This means we need to add a `position: relative`.
112
154
 
113
155
  ```css
114
156
  .menu-item {
115
157
  position: relative;
158
+
116
159
  &.is-open {
117
160
  & > .menu-submenu {
118
161
  position: absolute;
119
- ...
162
+ left: 0;
163
+ }
164
+ }
120
165
  ```
121
166
 
122
167
  While this solves the linting problem, we do not get the effect we wish to achieve: `submenu` rendered on the left of the `menu` while maintaining semantically correct html.
@@ -128,92 +173,49 @@ In order for this to work we need to transform the CSS:
128
173
  display: flex;
129
174
  position: relative;
130
175
 
131
- & > .menu-item.relativeToParent {
176
+ & > .menu-item {
132
177
  position: static;
133
178
  }
134
179
  }
135
180
 
136
181
  .menu-item {
137
182
  position: relative;
138
- ...
139
- }
140
- ```
141
-
142
- Note that we set `position: static` from the parent. You can also see we included the marker class `.relativeToParent`. If you would not use this exact name you would get another linting error. The reason we require this class is to make sure that the receiver of `position: static` is aware of this breach of containment. We would not want to accidentally break any behavior. As a bonus, you could use it in `menu-item` to toggle (enable / disable) this behavior:
143
183
 
144
- ```css
145
- .menu-item {
146
- &:not(.is-open) {
184
+ &.is-open {
147
185
  & > .menu-submenu {
148
- display: none;
149
- }
150
- }
151
-
152
- &.relativeToParent {
153
- position: relative;
154
-
155
- &.is-open {
156
- & > .menu-submenu {
157
- position: absolute;
158
- left: 0;
159
- }
186
+ position: absolute;
187
+ left: 0;
160
188
  }
161
189
  }
162
190
  }
163
191
  ```
164
192
 
165
- Note that this also works for removing a stacking context:
193
+ Note that we reset the relative element to `position: static` from its parent. This way we explicitly allow the absolute child to escape this context, one level up to this parent. In order to allow this, you need to add `position: relative` to the parent, creating a _new_ stacking context. If you need the absolute element to escape further, you have to repeat this process:
166
194
 
167
195
  ```css
168
- .menu {
196
+ .a {
169
197
  position: relative;
170
- z-index: 0;
171
198
 
172
- & > .item.relativeToParent {
199
+ & > .b {
173
200
  position: static;
174
- z-index: auto;
175
201
  }
176
202
  }
177
- ```
178
-
179
- ### Examples
180
-
181
- Examples of *correct* code for this rule:
182
203
 
183
- ```css
184
- .parent {
204
+ .b {
185
205
  position: relative;
186
206
 
187
- & > .child {
188
- position: absolute;
207
+ & > .c {
208
+ position: static;
189
209
  }
190
210
  }
191
- ```
192
211
 
193
- ```css
194
- .parent {
212
+ .c {
195
213
  position: relative;
196
214
 
197
215
  &::after {
216
+ content: '';
198
217
  position: absolute;
199
- }
200
- }
201
- ```
202
-
203
- Examples of *incorrect* code for this rule:
204
-
205
- ```css
206
- .parent {
207
- & > .child {
208
- position: absolute;
209
- }
210
- }
211
- ```
212
-
213
- ```css
214
- .parent {
215
- &::after {
216
- position: absolute;
218
+ inset: 0;
217
219
  }
218
220
  }
219
221
  ```
@@ -61,24 +61,11 @@ test('parent-child-policy', {
61
61
  `
62
62
  },
63
63
  {
64
- title: 'allow position: static 1',
65
- code: `
66
- .test {
67
- position: relative;
68
-
69
- & > .relativeToParent {
70
- position: static;
71
- }
72
- }
73
- `
74
- },
75
- {
76
- title: 'allow position: static 2',
77
64
  code: `
78
65
  .parent {
79
66
  position: relative;
80
67
 
81
- & > .child.relativeToParent {
68
+ & > .child {
82
69
  position: static;
83
70
  }
84
71
  }
@@ -122,6 +109,16 @@ test('parent-child-policy', {
122
109
  }
123
110
  `,
124
111
  },
112
+ {
113
+ title: 'allow layoutClassName when targetted with the direct child selector',
114
+ code: `
115
+ .parent {
116
+ & > .childLayout {
117
+ margin: 0;
118
+ }
119
+ }
120
+ `,
121
+ }
125
122
  ],
126
123
  invalid: [
127
124
  {
@@ -152,17 +149,8 @@ test('parent-child-policy', {
152
149
  code: '.bad { & > .test { position: static; } }',
153
150
  warnings: [
154
151
  messages['missing position relative'],
155
- messages['missing relativeToParent className'],
156
152
  ]
157
153
  },
158
- {
159
- code: '.bad { & > .test.relativeToParent { position: static; } }',
160
- warnings: [messages['missing position relative']]
161
- },
162
- {
163
- code: '.bad { position: relative; & > .test { position: static; } }',
164
- warnings: [messages['missing relativeToParent className']]
165
- },
166
154
  {
167
155
  title: '└─ take @media into account',
168
156
  code: '.bad { & > .test { @media x { position: absolute; } } }',
@@ -314,6 +302,21 @@ test('parent-child-policy', {
314
302
  'order'
315
303
  ])
316
304
  },
305
+ {
306
+ title: 'layoutClassName - must be nested in a parent selector',
307
+ code: `.badLayout { padding: 0; }`,
308
+ warnings: [messages['layoutClassname - must be nested in a parent selector']]
309
+ },
310
+ {
311
+ title: 'layoutClassName - must be nested in a parent selector',
312
+ code: `.badLayout:not(:empty) { padding: 0; }`,
313
+ warnings: [messages['layoutClassname - must be nested in a parent selector']]
314
+ },
315
+ {
316
+ title: 'layoutClassName - must be nested in a parent selector',
317
+ code: `.badLayout > .test { margin: 0; }`,
318
+ warnings: [messages['layoutClassname - must be nested in a parent selector']]
319
+ },
317
320
  ]
318
321
  },
319
322
  'layout-related-properties': {
@@ -322,12 +325,11 @@ test('parent-child-policy', {
322
325
  { code: `.good { pointer-events: none; & > * { pointer-events: auto; } }` },
323
326
  { code: `.good { &::after { pointer-events: none; } }` },
324
327
  {
325
- title: 'allow position: static',
326
328
  code: `
327
- .test {
329
+ .parent {
328
330
  position: relative;
329
331
 
330
- & > .relativeToParent {
332
+ & > .child {
331
333
  position: static;
332
334
  }
333
335
  }