@camtomlabs/malix-design-system 0.1.7 → 0.3.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 +105 -0
- package/dist/index.cjs +499 -217
- package/dist/index.d.cts +180 -80
- package/dist/index.d.ts +180 -80
- package/dist/index.js +496 -218
- package/eslint-plugin.cjs +128 -0
- package/package.json +21 -10
- package/src/reset.css +212 -0
- package/src/styles.css +231 -55
- package/src/tokens.css +80 -14
- package/src/tokens.registry.json +34 -0
- package/stylelint.config.cjs +56 -0
- package/tailwind.preset.js +173 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @camtomlabs/malix-design-system/eslint-plugin
|
|
3
|
+
*
|
|
4
|
+
* Custom ESLint rules that enforce usage of canonical Malix components
|
|
5
|
+
* instead of raw HTML elements.
|
|
6
|
+
*
|
|
7
|
+
* Usage in consuming repo:
|
|
8
|
+
*
|
|
9
|
+
* // .eslintrc.cjs
|
|
10
|
+
* module.exports = {
|
|
11
|
+
* plugins: ['@camtomlabs/malix'],
|
|
12
|
+
* rules: {
|
|
13
|
+
* '@camtomlabs/malix/no-raw-button': 'warn',
|
|
14
|
+
* '@camtomlabs/malix/no-raw-input': 'warn',
|
|
15
|
+
* },
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* Both rules allow an escape hatch via the disable comment:
|
|
19
|
+
* // eslint-disable-next-line @camtomlabs/malix/no-raw-button
|
|
20
|
+
* <button type="submit" form="external-form-id" />
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
'use strict';
|
|
24
|
+
|
|
25
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
26
|
+
const noRawButton = {
|
|
27
|
+
meta: {
|
|
28
|
+
type: 'suggestion',
|
|
29
|
+
docs: {
|
|
30
|
+
description:
|
|
31
|
+
'Disallow raw <button> elements. Use <Button> from @camtomlabs/malix-design-system instead.',
|
|
32
|
+
},
|
|
33
|
+
schema: [
|
|
34
|
+
{
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
allow: {
|
|
38
|
+
type: 'array',
|
|
39
|
+
items: { type: 'string' },
|
|
40
|
+
description: 'JSX element names that are allowed (e.g. ["Button", "MenuButton"])',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
additionalProperties: false,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
messages: {
|
|
47
|
+
rawButton:
|
|
48
|
+
'Do not use raw <button>. Import Button from "@camtomlabs/malix-design-system" and use <Button hierarchy="primary">.',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
create(context) {
|
|
52
|
+
return {
|
|
53
|
+
JSXOpeningElement(node) {
|
|
54
|
+
if (node.name.type !== 'JSXIdentifier') return;
|
|
55
|
+
if (node.name.name !== 'button') return;
|
|
56
|
+
context.report({ node, messageId: 'rawButton' });
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
63
|
+
const noRawInput = {
|
|
64
|
+
meta: {
|
|
65
|
+
type: 'suggestion',
|
|
66
|
+
docs: {
|
|
67
|
+
description:
|
|
68
|
+
'Disallow raw <input> elements (except type="hidden"). Use <Input> from @camtomlabs/malix-design-system instead.',
|
|
69
|
+
},
|
|
70
|
+
schema: [
|
|
71
|
+
{
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
allowTypes: {
|
|
75
|
+
type: 'array',
|
|
76
|
+
items: { type: 'string' },
|
|
77
|
+
default: ['hidden', 'file'],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
messages: {
|
|
84
|
+
rawInput:
|
|
85
|
+
'Do not use raw <input>. Import Input from "@camtomlabs/malix-design-system" and use <Input>.',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
create(context) {
|
|
89
|
+
const options = context.options[0] || {};
|
|
90
|
+
const allowTypes = options.allowTypes || ['hidden', 'file'];
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
JSXOpeningElement(node) {
|
|
94
|
+
if (node.name.type !== 'JSXIdentifier') return;
|
|
95
|
+
if (node.name.name !== 'input') return;
|
|
96
|
+
|
|
97
|
+
// Allow inputs whose type attribute is in allowTypes (e.g. hidden, file)
|
|
98
|
+
const typeAttr = node.attributes.find(
|
|
99
|
+
(attr) =>
|
|
100
|
+
attr.type === 'JSXAttribute' &&
|
|
101
|
+
attr.name &&
|
|
102
|
+
attr.name.name === 'type' &&
|
|
103
|
+
attr.value &&
|
|
104
|
+
attr.value.type === 'Literal',
|
|
105
|
+
);
|
|
106
|
+
if (typeAttr && allowTypes.includes(typeAttr.value.value)) return;
|
|
107
|
+
|
|
108
|
+
context.report({ node, messageId: 'rawInput' });
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
module.exports = {
|
|
115
|
+
rules: {
|
|
116
|
+
'no-raw-button': noRawButton,
|
|
117
|
+
'no-raw-input': noRawInput,
|
|
118
|
+
},
|
|
119
|
+
configs: {
|
|
120
|
+
recommended: {
|
|
121
|
+
plugins: ['@camtomlabs/malix'],
|
|
122
|
+
rules: {
|
|
123
|
+
'@camtomlabs/malix/no-raw-button': 'warn',
|
|
124
|
+
'@camtomlabs/malix/no-raw-input': 'warn',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camtomlabs/malix-design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Malix Design System combined package with components, tokens, and bundled styles.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -8,13 +8,18 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"sideEffects": [
|
|
10
10
|
"./src/styles.css",
|
|
11
|
-
"./src/tokens.css"
|
|
11
|
+
"./src/tokens.css",
|
|
12
|
+
"./src/reset.css"
|
|
12
13
|
],
|
|
13
14
|
"files": [
|
|
14
15
|
"dist",
|
|
15
16
|
"src/styles.css",
|
|
16
17
|
"src/tokens.css",
|
|
17
|
-
"src/
|
|
18
|
+
"src/reset.css",
|
|
19
|
+
"src/tokens.registry.json",
|
|
20
|
+
"tailwind.preset.js",
|
|
21
|
+
"stylelint.config.cjs",
|
|
22
|
+
"eslint-plugin.cjs"
|
|
18
23
|
],
|
|
19
24
|
"repository": {
|
|
20
25
|
"type": "git",
|
|
@@ -39,9 +44,14 @@
|
|
|
39
44
|
"import": "./dist/index.js",
|
|
40
45
|
"require": "./dist/index.cjs"
|
|
41
46
|
},
|
|
47
|
+
"./css": "./src/styles.css",
|
|
42
48
|
"./styles.css": "./src/styles.css",
|
|
43
49
|
"./tokens.css": "./src/tokens.css",
|
|
44
|
-
"./
|
|
50
|
+
"./reset.css": "./src/reset.css",
|
|
51
|
+
"./tokens.registry.json": "./src/tokens.registry.json",
|
|
52
|
+
"./tailwind.preset": "./tailwind.preset.js",
|
|
53
|
+
"./stylelint.config": "./stylelint.config.cjs",
|
|
54
|
+
"./eslint-plugin": "./eslint-plugin.cjs"
|
|
45
55
|
},
|
|
46
56
|
"peerDependencies": {
|
|
47
57
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -50,13 +60,14 @@
|
|
|
50
60
|
"publishConfig": {
|
|
51
61
|
"access": "public"
|
|
52
62
|
},
|
|
53
|
-
"devDependencies": {
|
|
54
|
-
"@types/react": "^19.0.0",
|
|
55
|
-
"@types/react-dom": "^19.0.0",
|
|
56
|
-
"tsup": "^8.5.1"
|
|
57
|
-
},
|
|
58
63
|
"scripts": {
|
|
59
64
|
"build": "tsup",
|
|
60
65
|
"lint": "eslint src"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@types/react": "^19.0.0",
|
|
69
|
+
"@types/react-dom": "^19.0.0",
|
|
70
|
+
"tsup": "^8.5.1",
|
|
71
|
+
"typescript": "^5.6.2"
|
|
61
72
|
}
|
|
62
|
-
}
|
|
73
|
+
}
|
package/src/reset.css
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/* ═══════════════════════════════════════════════
|
|
2
|
+
MALIX RESET — Opt-in CSS reset scoped to @layer
|
|
3
|
+
|
|
4
|
+
Ships inside the `malix-reset` layer so any style
|
|
5
|
+
defined outside this layer (or in a later layer)
|
|
6
|
+
will win regardless of selector specificity.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
import '@camtomlabs/malix-design-system/reset.css';
|
|
10
|
+
|
|
11
|
+
This file defines the cascade order. Import it
|
|
12
|
+
ONCE, before any other Malix stylesheet:
|
|
13
|
+
|
|
14
|
+
1. malix-reset (this file)
|
|
15
|
+
2. malix-tokens (CSS custom properties)
|
|
16
|
+
3. malix-components (component styles)
|
|
17
|
+
4. app (your own styles)
|
|
18
|
+
|
|
19
|
+
Any CSS you write outside these layers will
|
|
20
|
+
automatically beat the reset — no :not() hacks,
|
|
21
|
+
no specificity wars.
|
|
22
|
+
═══════════════════════════════════════════════ */
|
|
23
|
+
|
|
24
|
+
@layer malix-reset, malix-tokens, malix-components, app;
|
|
25
|
+
|
|
26
|
+
@layer malix-reset {
|
|
27
|
+
*,
|
|
28
|
+
*::before,
|
|
29
|
+
*::after {
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
html {
|
|
34
|
+
-webkit-text-size-adjust: 100%;
|
|
35
|
+
-moz-tab-size: 4;
|
|
36
|
+
tab-size: 4;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
body {
|
|
40
|
+
margin: 0;
|
|
41
|
+
line-height: 1.5;
|
|
42
|
+
-webkit-font-smoothing: antialiased;
|
|
43
|
+
-moz-osx-font-smoothing: grayscale;
|
|
44
|
+
font-family: var(--malix-font-body, system-ui, sans-serif);
|
|
45
|
+
color: var(--malix-foreground, #111827);
|
|
46
|
+
background-color: var(--malix-background-main, #ffffff);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
hr {
|
|
50
|
+
height: 0;
|
|
51
|
+
color: inherit;
|
|
52
|
+
border-top-width: 1px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
h1, h2, h3, h4, h5, h6 {
|
|
56
|
+
font-size: inherit;
|
|
57
|
+
font-weight: inherit;
|
|
58
|
+
margin: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
p, blockquote, dl, dd {
|
|
62
|
+
margin: 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
ul, ol {
|
|
66
|
+
margin: 0;
|
|
67
|
+
padding: 0;
|
|
68
|
+
list-style: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
a {
|
|
72
|
+
color: inherit;
|
|
73
|
+
text-decoration: inherit;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
b, strong {
|
|
77
|
+
font-weight: bolder;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
code, kbd, samp, pre {
|
|
81
|
+
font-family:
|
|
82
|
+
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
83
|
+
"Liberation Mono", "Courier New", monospace;
|
|
84
|
+
font-size: 1em;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
small {
|
|
88
|
+
font-size: 80%;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
sub, sup {
|
|
92
|
+
font-size: 75%;
|
|
93
|
+
line-height: 0;
|
|
94
|
+
position: relative;
|
|
95
|
+
vertical-align: baseline;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
sub { bottom: -0.25em; }
|
|
99
|
+
sup { top: -0.5em; }
|
|
100
|
+
|
|
101
|
+
table {
|
|
102
|
+
border-collapse: collapse;
|
|
103
|
+
border-color: inherit;
|
|
104
|
+
text-indent: 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
button,
|
|
108
|
+
input,
|
|
109
|
+
optgroup,
|
|
110
|
+
select,
|
|
111
|
+
textarea {
|
|
112
|
+
font-family: inherit;
|
|
113
|
+
font-size: 100%;
|
|
114
|
+
font-weight: inherit;
|
|
115
|
+
line-height: inherit;
|
|
116
|
+
color: inherit;
|
|
117
|
+
margin: 0;
|
|
118
|
+
padding: 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
button,
|
|
122
|
+
select {
|
|
123
|
+
text-transform: none;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* IMPORTANT: intentionally NOT resetting button background-color.
|
|
127
|
+
Components or CSS Modules must be able to set their own background
|
|
128
|
+
without fighting a global reset. */
|
|
129
|
+
button,
|
|
130
|
+
[type='button'],
|
|
131
|
+
[type='reset'],
|
|
132
|
+
[type='submit'] {
|
|
133
|
+
-webkit-appearance: button;
|
|
134
|
+
background-color: transparent;
|
|
135
|
+
background-image: none;
|
|
136
|
+
border: 0;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
:-moz-focusring {
|
|
141
|
+
outline: auto;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
:-moz-ui-invalid {
|
|
145
|
+
box-shadow: none;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
progress {
|
|
149
|
+
vertical-align: baseline;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
::-webkit-inner-spin-button,
|
|
153
|
+
::-webkit-outer-spin-button {
|
|
154
|
+
height: auto;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
[type='search'] {
|
|
158
|
+
-webkit-appearance: textfield;
|
|
159
|
+
outline-offset: -2px;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
::-webkit-search-decoration {
|
|
163
|
+
-webkit-appearance: none;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
::-webkit-file-upload-button {
|
|
167
|
+
-webkit-appearance: button;
|
|
168
|
+
font: inherit;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
summary {
|
|
172
|
+
display: list-item;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
fieldset {
|
|
176
|
+
margin: 0;
|
|
177
|
+
padding: 0;
|
|
178
|
+
border: 0;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
legend {
|
|
182
|
+
padding: 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
textarea {
|
|
186
|
+
resize: vertical;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
input::placeholder,
|
|
190
|
+
textarea::placeholder {
|
|
191
|
+
opacity: 1;
|
|
192
|
+
color: var(--malix-placeholder, #9ca3af);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
[role="button"] {
|
|
196
|
+
cursor: pointer;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
:disabled {
|
|
200
|
+
cursor: default;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
img, svg, video, canvas, audio, iframe, embed, object {
|
|
204
|
+
display: block;
|
|
205
|
+
vertical-align: middle;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
img, video {
|
|
209
|
+
max-width: 100%;
|
|
210
|
+
height: auto;
|
|
211
|
+
}
|
|
212
|
+
}
|