dowel-ui 0.8.0 → 0.9.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 CHANGED
@@ -11,7 +11,7 @@ A dowel is the hidden peg that joins two boards so the seam does not show. That
11
11
  **[Documentation](https://lacodda.github.io/dowel/)** — what everything is and why it is that way.
12
12
  **[The stand](https://lacodda.github.io/dowel/stand/)** — every component, live, in either theme and in the accent of any product of the line.
13
13
 
14
- **Status:** v0.8.0 - the theme, the scales, an accent per product, sixteen components including the overlays, and the gates each one passes: axe, the keyboard, a dependency budget and a picture in both themes. The first product of the line lives on it. See the [roadmap](#roadmap).
14
+ **Status:** v0.9.0 - the theme, the scales, an accent per product, twenty components including the overlays and the menus, and the gates each one passes: axe, the keyboard, a dependency budget and a picture in both themes. The first product of the line lives on it. See the [roadmap](#roadmap).
15
15
 
16
16
  ## The theme
17
17
 
@@ -83,9 +83,17 @@ your code:
83
83
  npx shadcn@latest add https://lacodda.github.io/dowel/r/button.json
84
84
  ```
85
85
 
86
- Sixteen of them so far. The everyday ones - Button, Input, Textarea, Panel,
87
- Badge, Chip, Kbd, Spinner, Truncate and Copyable - and the six that float above
88
- the page: Dialog, ConfirmDialog, Drawer, Popover, PreviewCard and Tooltip.
86
+ Twenty of them so far. The everyday ones - Button, Input, Textarea, Panel,
87
+ Badge, Chip, Kbd, Spinner, Truncate and Copyable; the six that float above the
88
+ page - Dialog, ConfirmDialog, Drawer, Popover, PreviewCard and Tooltip; and
89
+ four for choosing something: Menu, ContextMenu, Select and Combobox.
90
+
91
+ `Select` is the one the line's oldest rule is about. It renders
92
+ `<button role="combobox">` and no native `<select>` at all - the browser draws
93
+ that popup in the operating system's own chrome, where no stylesheet reaches
94
+ it, and on a screen of the product's own controls it reads as a foreign object.
95
+ `multiple` is a prop on Select and on Combobox rather than a component of its
96
+ own.
89
97
 
90
98
  The overlays are built on [Base UI](https://base-ui.com), which supplies the
91
99
  part that is genuinely hard and invisible when it works: the focus trap, the
@@ -106,8 +114,10 @@ import dowel from 'dowel-ui/eslint'
106
114
  export default [...dowel.configs.recommended]
107
115
  ```
108
116
 
109
- It reports a hex, an `rgb()`, a stock Tailwind colour, `bg-white`, and any
110
- `dark:` utility, in the file that wrote one - see [the guide](https://lacodda.github.io/dowel/guides/linting/).
117
+ Two rules come with it. One reports a hex, an `rgb()`, a stock Tailwind colour,
118
+ `bg-white` and any `dark:` utility, in the file that wrote one. The other
119
+ forbids the native `<select>`, whose popup the browser draws in the operating
120
+ system's own chrome where no CSS reaches it - see [the guide](https://lacodda.github.io/dowel/guides/linting/).
111
121
 
112
122
  Every primitive also runs a gate of its own before it ships: axe over the
113
123
  rendered DOM in every variant, the keyboard over every interactive one, a
@@ -134,7 +144,7 @@ Development goes in versions; each one is a single coherent theme, and ends in a
134
144
  ## Documentation
135
145
 
136
146
  - [The stand](https://lacodda.github.io/dowel/stand/) - every component, live
137
- - [Getting started](https://lacodda.github.io/dowel/getting-started/) and [the lint rule](https://lacodda.github.io/dowel/guides/linting/)
147
+ - [Getting started](https://lacodda.github.io/dowel/getting-started/), [the lint rules](https://lacodda.github.io/dowel/guides/linting/) and [what a component has to pass](https://lacodda.github.io/dowel/guides/gates/)
138
148
  - [Components](https://lacodda.github.io/dowel/components/button/)
139
149
  - [Tokens](https://lacodda.github.io/dowel/reference/tokens/), [scales](https://lacodda.github.io/dowel/reference/scales/) and [accents](https://lacodda.github.io/dowel/reference/accents/)
140
150
 
@@ -9,4 +9,5 @@ declare const dowel: ESLint.Plugin & {
9
9
  };
10
10
  export default dowel;
11
11
  export { noRawColor, findRawColor } from './no-raw-color.js';
12
+ export { noNativeSelect } from './no-native-select.js';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAoC5C;;+EAE+E;AAC/E,QAAA,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG;IAAE,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;KAAE,CAAA;CAEtE,CAAA;AAEF,eAAe,KAAK,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAyC5C;;+EAE+E;AAC/E,QAAA,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG;IAAE,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;KAAE,CAAA;CAEtE,CAAA;AAEF,eAAe,KAAK,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA"}
@@ -1,9 +1,11 @@
1
+ import { noNativeSelect } from './no-native-select.js';
1
2
  import { noRawColor } from './no-raw-color.js';
2
3
  /*
3
4
  * The dowel ESLint plugin.
4
5
  *
5
- * One rule, and it enforces the convention the whole system rests on: a
6
- * component names colours from the vocabulary and never writes one down.
6
+ * Two rules, and both enforce a convention the system rests on: a component
7
+ * names colours from the vocabulary and never writes one down, and no screen
8
+ * uses a native `<select>`, which the browser draws in its own chrome.
7
9
  *
8
10
  * It ships from the package rather than the registry because it is not a
9
11
  * component - it is not copied into a product and edited there, it is a check
@@ -18,15 +20,18 @@ import { noRawColor } from './no-raw-color.js';
18
20
  */
19
21
  const plugin = {
20
22
  meta: { name: 'dowel' },
21
- rules: { 'no-raw-color': noRawColor },
23
+ rules: { 'no-raw-color': noRawColor, 'no-native-select': noNativeSelect },
22
24
  };
23
- /** The rule, applied where components live. Scoped to TypeScript sources: the
24
- * theme is CSS and the build tools are Node, and neither is a component. */
25
+ /** The rules, applied where components live. Scoped to TypeScript sources:
26
+ * the theme is CSS and the build tools are Node, and neither is a component. */
25
27
  const recommended = [
26
28
  {
27
29
  files: ['**/*.{ts,tsx}'],
28
30
  plugins: { dowel: plugin },
29
- rules: { 'dowel/no-raw-color': 'error' },
31
+ rules: {
32
+ 'dowel/no-raw-color': 'error',
33
+ 'dowel/no-native-select': 'error',
34
+ },
30
35
  },
31
36
  ];
32
37
  /** The plugin, with its config bundled on - the shape flat config expects
@@ -37,4 +42,5 @@ const dowel = Object.assign(plugin, {
37
42
  });
38
43
  export default dowel;
39
44
  export { noRawColor, findRawColor } from './no-raw-color.js';
45
+ export { noNativeSelect } from './no-native-select.js';
40
46
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;IACvB,KAAK,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE;CACd,CAAA;AAEzB;4EAC4E;AAC5E,MAAM,WAAW,GAAoB;IACnC;QACE,KAAK,EAAE,CAAC,eAAe,CAAC;QACxB,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;QAC1B,KAAK,EAAE,EAAE,oBAAoB,EAAE,OAAO,EAAE;KACzC;CACF,CAAA;AAED;;+EAE+E;AAC/E,MAAM,KAAK,GAAkE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE;IACjG,OAAO,EAAE,EAAE,WAAW,EAAE;CACzB,CAAC,CAAA;AAEF,eAAe,KAAK,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;IACvB,KAAK,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,cAAc,EAAE;CAClD,CAAA;AAEzB;gFACgF;AAChF,MAAM,WAAW,GAAoB;IACnC;QACE,KAAK,EAAE,CAAC,eAAe,CAAC;QACxB,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;QAC1B,KAAK,EAAE;YACL,oBAAoB,EAAE,OAAO;YAC7B,wBAAwB,EAAE,OAAO;SAClC;KACF;CACF,CAAA;AAED;;+EAE+E;AAC/E,MAAM,KAAK,GAAkE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE;IACjG,OAAO,EAAE,EAAE,WAAW,EAAE;CACzB,CAAC,CAAA;AAEF,eAAe,KAAK,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from 'eslint';
2
+ export declare const noNativeSelect: Rule.RuleModule;
3
+ //# sourceMappingURL=no-native-select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-native-select.d.ts","sourceRoot":"","sources":["../../src/eslint/no-native-select.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AA4BlC,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,UA2BjC,CAAA"}
@@ -0,0 +1,51 @@
1
+ /*
2
+ * `no-native-select` - the oldest convention in the line, from atlas.
3
+ *
4
+ * A `<select>` cannot be made to look like the rest of an application. The
5
+ * browser draws its popup itself, in the operating system's chrome, with the
6
+ * operating system's fonts and spacing - and no amount of CSS reaches inside
7
+ * it. On a screen where every other control is the product's own, the one
8
+ * native dropdown reads as a foreign object, and on Windows it reads as a
9
+ * foreign object from 1998.
10
+ *
11
+ * So the rule is about the element, not about a name: `Select` from this set
12
+ * renders `<button role="combobox">` and no `<select>` at all, which is what
13
+ * the convention was always asking for.
14
+ *
15
+ * `<option>` and `<optgroup>` are reported too. They exist only inside a
16
+ * `<select>`, so one appearing on its own is either a `<select>` being
17
+ * assembled somewhere else or a misunderstanding - both worth saying out loud.
18
+ */
19
+ const NATIVE = new Set(['select', 'option', 'optgroup']);
20
+ const MESSAGE = 'A native `<{{name}}>` cannot be styled to match the rest of the application - ' +
21
+ 'the browser draws its popup in the operating system chrome. Use the Select or ' +
22
+ 'Combobox component instead.';
23
+ export const noNativeSelect = {
24
+ meta: {
25
+ type: 'problem',
26
+ docs: {
27
+ description: 'Forbid the native `<select>` element, which cannot be styled to match the product.',
28
+ url: 'https://lacodda.github.io/dowel/guides/linting/',
29
+ },
30
+ schema: [],
31
+ messages: { native: MESSAGE },
32
+ },
33
+ create(context) {
34
+ return {
35
+ // `JSXOpeningElement` is not in ESLint's own AST types - the JSX nodes
36
+ // come from the TypeScript parser - so the visitor is declared by name
37
+ // and the node is read structurally.
38
+ JSXOpeningElement(node) {
39
+ const name = node.name;
40
+ // A lower-case identifier is an HTML tag; `<Select>` is a component,
41
+ // and a member expression like `<Base.Select>` is somebody's namespace.
42
+ if (name?.type !== 'JSXIdentifier' || typeof name.name !== 'string')
43
+ return;
44
+ if (!NATIVE.has(name.name))
45
+ return;
46
+ context.report({ node, messageId: 'native', data: { name: name.name } });
47
+ },
48
+ };
49
+ },
50
+ };
51
+ //# sourceMappingURL=no-native-select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-native-select.js","sourceRoot":"","sources":["../../src/eslint/no-native-select.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;AAExD,MAAM,OAAO,GACX,gFAAgF;IAChF,gFAAgF;IAChF,6BAA6B,CAAA;AAE/B,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC7C,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,oFAAoF;YACtF,GAAG,EAAE,iDAAiD;SACvD;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;KAC9B;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,uEAAuE;YACvE,uEAAuE;YACvE,qCAAqC;YACrC,iBAAiB,CAAC,IAAe;gBAC/B,MAAM,IAAI,GAAI,IAA+D,CAAC,IAAI,CAAA;gBAClF,qEAAqE;gBACrE,wEAAwE;gBACxE,IAAI,IAAI,EAAE,IAAI,KAAK,eAAe,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;oBAAE,OAAM;gBAC3E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,OAAM;gBAElC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;YAC1E,CAAC;SACmB,CAAA;IACxB,CAAC;CACF,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dowel-ui",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "The lacodda line design system: theme tokens and React primitives, distributed as a shadcn-compatible registry.",
5
5
  "license": "MIT",
6
6
  "type": "module",