@estiva-app/ui 0.49.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/eslint/index.js +26 -0
- package/dist/eslint/index.js.map +2 -2
- package/dist/eslint/no-restyled-part.d.ts.map +1 -1
- package/package.json +1 -1
- package/registry.json +1 -1
- package/src/Form.mdx +6 -0
- package/src/eslint/no-restyled-part.test.ts +16 -0
- package/src/eslint/no-restyled-part.ts +37 -0
package/README.md
CHANGED
|
@@ -79,6 +79,8 @@ instead. There are seven — six block, one warns:
|
|
|
79
79
|
`className` or an inner box's class prop — a colour, a text size, a border, a
|
|
80
80
|
corner, a shadow — and names the part's look props (`PART_LOOK_PROPS`). Only
|
|
81
81
|
placement goes through (`PLACEMENT`), and `EmptyState` takes no padding.
|
|
82
|
+
A `Form` takes no layout of its own, and sits in no spaced box beside other
|
|
83
|
+
things: what comes before its fields goes inside it.
|
|
82
84
|
- `estiva/no-handmade-header` refuses a column's header bar drawn by hand: a
|
|
83
85
|
row first in a column, with its own side padding and a title, where the column
|
|
84
86
|
fills its height or the row has a bar's height or hairline. It reads the
|
package/dist/eslint/index.js
CHANGED
|
@@ -218,6 +218,10 @@ var isFieldsLayout = (token) => {
|
|
|
218
218
|
const { variants, utility } = splitClass(token);
|
|
219
219
|
return !variants.some((variant) => REACHING_VARIANT.test(variant)) && FIELDS_LAYOUT.test(utility);
|
|
220
220
|
};
|
|
221
|
+
var isSpacing = (token) => {
|
|
222
|
+
const { variants, utility } = splitClass(token);
|
|
223
|
+
return !variants.some((variant) => REACHING_VARIANT.test(variant)) && /^(?:gap|gap-x|gap-y|space-x|space-y)-/.test(utility);
|
|
224
|
+
};
|
|
221
225
|
var isPadding = (token) => {
|
|
222
226
|
const { variants, utility } = splitClass(token);
|
|
223
227
|
return !variants.some((variant) => REACHING_VARIANT.test(variant)) && /^p[xytrblse]?-/.test(utility);
|
|
@@ -635,6 +639,7 @@ var noRestyledPart = {
|
|
|
635
639
|
restyledStyle: "{{keys}} in the `style` of {{where}} changes how it looks. A part of @estiva-app/ui is placed from outside, never restyled, by class or by style: only space, size, flex and grid, and position pass in.{{use}} A look for what is around it goes on your own element around it.",
|
|
636
640
|
emptyStatePadding: "{{classes}} pads {{where}}. EmptyState takes no padding (Katerina, 14 September): its room comes from the box its rows live in, so put the padding on that box.",
|
|
637
641
|
formLayout: '{{classes}} lays out the fields of {{where}}. A Form places its own fields, 24px apart (Katerina, 28 September), so every form reads the same: remove it. A form that is not a list of fields (a field and its button, a composer) says `layout="free"` and lays itself out.',
|
|
642
|
+
formSpacedFromOutside: "{{classes}} on the box around `Form` spaces the form from what is beside it, so the gap above its first field is not the form\u2019s 24px. Put what is beside it inside the `Form`, as one block before the fields, and drop the box: the Form puts 24px between them (Katerina, 1 October; MoveDialog in Peek does this).",
|
|
638
643
|
...ESCAPE_MESSAGES
|
|
639
644
|
}
|
|
640
645
|
},
|
|
@@ -688,6 +693,26 @@ var noRestyledPart = {
|
|
|
688
693
|
const where = binding.via && binding.via !== binding.part ? `\`${binding.via}\` (it hands its props to \`${binding.part}\`)` : `\`${binding.part}\``;
|
|
689
694
|
context.report({ loc: at.loc, messageId: "restyledStyle", data: { keys: code([...new Set(keys)]), where, use } });
|
|
690
695
|
};
|
|
696
|
+
const checkSpacedFromOutside = (opening) => {
|
|
697
|
+
const form = opening.parent;
|
|
698
|
+
const box = form?.parent;
|
|
699
|
+
if (form?.type !== "JSXElement" || box?.type !== "JSXElement") return;
|
|
700
|
+
const beside = children(box, "children").filter((node) => {
|
|
701
|
+
if (!node || node === form) return false;
|
|
702
|
+
if (node.type === "JSXText") return String(node.value).trim() !== "";
|
|
703
|
+
if (node.type === "JSXExpressionContainer") return child(node, "expression")?.type !== "JSXEmptyExpression";
|
|
704
|
+
return true;
|
|
705
|
+
});
|
|
706
|
+
if (!beside.length) return;
|
|
707
|
+
const boxOpening = child(box, "openingElement");
|
|
708
|
+
const spacing = children(boxOpening, "attributes").flatMap((attribute3) => {
|
|
709
|
+
if (attribute3?.type !== "JSXAttribute") return [];
|
|
710
|
+
const prop = nameOf(child(attribute3, "name"));
|
|
711
|
+
return prop === "className" || prop === "bodyClassName" ? classesOf(child(attribute3, "value"), scopeOf).filter(isSpacing) : [];
|
|
712
|
+
});
|
|
713
|
+
if (!spacing.length || escaped(opening)) return;
|
|
714
|
+
context.report({ loc: opening.loc, messageId: "formSpacedFromOutside", data: { classes: code([...new Set(spacing)]) } });
|
|
715
|
+
};
|
|
691
716
|
return {
|
|
692
717
|
Program(program) {
|
|
693
718
|
locals = moduleParts(file, program, parser, /* @__PURE__ */ new Set([file])).locals;
|
|
@@ -696,6 +721,7 @@ var noRestyledPart = {
|
|
|
696
721
|
const element = ruleNode;
|
|
697
722
|
const binding = locals && bindingOfTag(child(element, "name"), locals);
|
|
698
723
|
if (!binding) return;
|
|
724
|
+
if (binding.part === "Form" && binding.props === "all" && placesItsFields(element)) checkSpacedFromOutside(element);
|
|
699
725
|
for (const attribute3 of children(element, "attributes")) {
|
|
700
726
|
if (!attribute3) continue;
|
|
701
727
|
if (attribute3.type === "JSXAttribute") {
|