@pacer-ui/tailwind-preset 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 PT Pertamina (Persero)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # @pertamina/tailwind-preset
2
+
3
+ Shared Tailwind CSS preset untuk PACER (Pertamina Patra Niaga Components & Experience Resources).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @pertamina/tailwind-preset
9
+ # or
10
+ pnpm add @pertamina/tailwind-preset
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Basic Setup
16
+
17
+ ```js
18
+ // tailwind.config.js
19
+ module.exports = {
20
+ presets: [require('@pertamina/tailwind-preset')],
21
+ content: [
22
+ './src/**/*.{js,jsx,ts,tsx}',
23
+ './pages/**/*.{js,jsx,ts,tsx}',
24
+ ],
25
+ }
26
+ ```
27
+
28
+ ### With Custom Overrides
29
+
30
+ ```js
31
+ // tailwind.config.js
32
+ module.exports = {
33
+ presets: [require('@pertamina/tailwind-preset')],
34
+ content: [
35
+ './src/**/*.{js,jsx,ts,tsx}',
36
+ ],
37
+ theme: {
38
+ extend: {
39
+ // Override atau tambah custom values
40
+ colors: {
41
+ custom: '#123456',
42
+ },
43
+ },
44
+ },
45
+ }
46
+ ```
47
+
48
+ ## What's Included
49
+
50
+ Preset ini mengintegrasikan semua design tokens:
51
+
52
+ ### Colors
53
+ ```jsx
54
+ <div className="bg-brand-primary-500 text-neutral-0">
55
+ Pertamina Primary
56
+ </div>
57
+ ```
58
+
59
+ ### Spacing
60
+ ```jsx
61
+ <div className="p-4 m-6 gap-3">
62
+ 4px-based spacing
63
+ </div>
64
+ ```
65
+
66
+ ### Typography
67
+ ```jsx
68
+ <p className="font-sans text-base font-medium leading-normal">
69
+ Typography tokens
70
+ </p>
71
+ ```
72
+
73
+ ### Border Radius
74
+ ```jsx
75
+ <div className="rounded-lg">
76
+ Border radius tokens
77
+ </div>
78
+ ```
79
+
80
+ ### Shadows
81
+ ```jsx
82
+ <div className="shadow-lg">
83
+ Shadow tokens
84
+ </div>
85
+ ```
86
+
87
+ ### Animations
88
+ ```jsx
89
+ <div className="transition-all duration-fast ease-easeInOut">
90
+ Motion tokens
91
+ </div>
92
+ ```
93
+
94
+ ## Component Classes
95
+
96
+ Preset juga menyediakan base component classes:
97
+
98
+ ### Button
99
+ ```jsx
100
+ <button className="btn bg-brand-primary-500 text-neutral-0">
101
+ Button
102
+ </button>
103
+ ```
104
+
105
+ ### Input
106
+ ```jsx
107
+ <input className="input" type="text" />
108
+ ```
109
+
110
+ ### Card
111
+ ```jsx
112
+ <div className="card">
113
+ Card content
114
+ </div>
115
+ ```
116
+
117
+ ## Dark Mode
118
+
119
+ Dark mode menggunakan class strategy:
120
+
121
+ ```jsx
122
+ // Tambah class 'dark' di root element
123
+ <html className="dark">
124
+ <body>
125
+ <div className="bg-neutral-0 dark:bg-neutral-900">
126
+ Content
127
+ </div>
128
+ </body>
129
+ </html>
130
+ ```
131
+
132
+ ## Blazor Integration
133
+
134
+ Untuk Blazor, compile Tailwind CSS ke static file:
135
+
136
+ ```bash
137
+ # package.json
138
+ {
139
+ "scripts": {
140
+ "build:css": "tailwindcss -i ./src/styles.css -o ./wwwroot/css/styles.css --minify"
141
+ }
142
+ }
143
+ ```
144
+
145
+ ```css
146
+ /* src/styles.css */
147
+ @tailwind base;
148
+ @tailwind components;
149
+ @tailwind utilities;
150
+ ```
151
+
152
+ ## Philosophy
153
+
154
+ 1. **Token-based** - Semua value dari design tokens
155
+ 2. **Consistent** - Sama di React, Vue, dan Blazor
156
+ 3. **Extensible** - Dapat di-override sesuai kebutuhan
157
+ 4. **Type-safe** - Full TypeScript support
158
+ 5. **Tree-shakeable** - Hanya CSS yang dipakai akan di-bundle
159
+
160
+ ## Updating
161
+
162
+ Ketika design tokens di-update, rebuild preset:
163
+
164
+ ```bash
165
+ pnpm build
166
+ ```
167
+
168
+ Semua library yang depend ke preset ini akan otomatis menggunakan tokens terbaru.
@@ -0,0 +1,20 @@
1
+ import { Config } from 'tailwindcss';
2
+
3
+ /**
4
+ * PACER - Tailwind CSS Preset
5
+ *
6
+ * Preset ini mengintegrasikan design tokens ke dalam Tailwind CSS.
7
+ * Semua library (React, Vue, Blazor) menggunakan preset ini.
8
+ *
9
+ * Usage:
10
+ * ```js
11
+ * // tailwind.config.js
12
+ * module.exports = {
13
+ * presets: [require('@pertamina/tailwind-preset')],
14
+ * content: ['./src/**\/*.{js,jsx,ts,tsx}'],
15
+ * }
16
+ * ```
17
+ */
18
+ declare const preset: Partial<Config>;
19
+
20
+ export { preset as default };
@@ -0,0 +1,20 @@
1
+ import { Config } from 'tailwindcss';
2
+
3
+ /**
4
+ * PACER - Tailwind CSS Preset
5
+ *
6
+ * Preset ini mengintegrasikan design tokens ke dalam Tailwind CSS.
7
+ * Semua library (React, Vue, Blazor) menggunakan preset ini.
8
+ *
9
+ * Usage:
10
+ * ```js
11
+ * // tailwind.config.js
12
+ * module.exports = {
13
+ * presets: [require('@pertamina/tailwind-preset')],
14
+ * content: ['./src/**\/*.{js,jsx,ts,tsx}'],
15
+ * }
16
+ * ```
17
+ */
18
+ declare const preset: Partial<Config>;
19
+
20
+ export { preset as default };
package/dist/index.js ADDED
@@ -0,0 +1,314 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ default: () => index_default
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+ var import_tokens = require("@pacer-ui/tokens");
27
+ var preset = {
28
+ content: [],
29
+ darkMode: "class",
30
+ /**
31
+ * Safelist untuk mengatasi false positive pada SAST/DAST tools.
32
+ * Semua arbitrary values yang digunakan di komponen harus ada di sini
33
+ * agar Tailwind selalu generate classes tersebut dan tidak di-flag sebagai dynamic code injection.
34
+ */
35
+ safelist: [
36
+ // Badge component colors & utilities (generated dynamically in C# code)
37
+ "bg-slate-900",
38
+ "bg-slate-100",
39
+ "text-slate-900",
40
+ "text-slate-50",
41
+ "text-slate-950",
42
+ "bg-yellow-500",
43
+ "bg-yellow-50",
44
+ "text-yellow-500",
45
+ "text-yellow-700",
46
+ "bg-green-600",
47
+ "bg-green-50",
48
+ "bg-green-100",
49
+ "text-green-600",
50
+ "bg-purple-600",
51
+ "bg-purple-50",
52
+ "text-purple-600",
53
+ "bg-pink-600",
54
+ "bg-pink-50",
55
+ "text-pink-600",
56
+ "bg-orange-600",
57
+ "bg-orange-50",
58
+ "text-orange-600",
59
+ "bg-red-50",
60
+ "text-red-600",
61
+ "bg-red-100",
62
+ "rounded-full",
63
+ "rounded-md",
64
+ "px-2.5",
65
+ "py-0.5",
66
+ "px-2",
67
+ "py-1",
68
+ "border-slate-300",
69
+ "border-yellow-500",
70
+ "border-green-600",
71
+ "border-purple-600",
72
+ "border-pink-600",
73
+ "border-orange-600",
74
+ "inline-flex",
75
+ "items-center",
76
+ "justify-center",
77
+ "gap-0.5",
78
+ "text-xs",
79
+ "font-semibold",
80
+ // Border radius arbitrary values
81
+ "rounded-[6px]",
82
+ "rounded-[4px]",
83
+ // Spacing arbitrary values
84
+ "mt-[2.5px]",
85
+ // Min width arbitrary values
86
+ "min-w-[64px]",
87
+ "min-w-[80px]",
88
+ // Border utilities - diperlukan untuk button variants (secondary, outline, danger)
89
+ "border",
90
+ "border-1",
91
+ "border-brand-300",
92
+ "border-red-600",
93
+ // Complex shadow values (focus rings) - ini yang paling sering di-flag
94
+ "focus-visible:shadow-[0_0_0_2px_white,0_0_0_4px_rgb(1_107_248)]",
95
+ "focus-visible:shadow-[0_0_0_2px_white,0_0_0_4px_rgb(226_232_240)]",
96
+ "focus-visible:shadow-[0_0_0_2px_white,0_0_0_4px_rgb(254_202_202)]",
97
+ // Information component – Figma PACER (node 40000837-1003)
98
+ "mt-[4.5px]",
99
+ "rounded-lg",
100
+ "bg-brand-50",
101
+ "bg-slate-100",
102
+ "bg-green-100",
103
+ "bg-amber-100",
104
+ "bg-red-100",
105
+ "text-brand-300",
106
+ "text-brand-400",
107
+ "text-brand-600",
108
+ "text-slate-500",
109
+ "text-slate-600",
110
+ "text-slate-950",
111
+ "text-green-600",
112
+ "text-amber-600",
113
+ "text-red-600",
114
+ "text-xs",
115
+ "text-sm",
116
+ "text-base",
117
+ "font-medium",
118
+ "font-normal",
119
+ "leading-none",
120
+ "leading-5",
121
+ "leading-6"
122
+ ],
123
+ theme: {
124
+ // Extend default Tailwind theme
125
+ extend: {
126
+ // Colors
127
+ colors: {
128
+ // Brand colors
129
+ brand: import_tokens.tokens.colors.brand,
130
+ // Base colors
131
+ base: import_tokens.tokens.colors.base,
132
+ // Color scales
133
+ slate: import_tokens.tokens.colors.slate,
134
+ gray: import_tokens.tokens.colors.gray,
135
+ zinc: import_tokens.tokens.colors.zinc,
136
+ neutral: import_tokens.tokens.colors.neutral,
137
+ stone: import_tokens.tokens.colors.stone,
138
+ // Semantic colors
139
+ red: import_tokens.tokens.colors.red,
140
+ green: import_tokens.tokens.colors.green,
141
+ yellow: import_tokens.tokens.colors.yellow,
142
+ blue: import_tokens.tokens.colors.blue,
143
+ // Semantic aliases
144
+ success: import_tokens.tokens.colors.success,
145
+ warning: import_tokens.tokens.colors.warning,
146
+ error: import_tokens.tokens.colors.error,
147
+ info: import_tokens.tokens.colors.info,
148
+ // Pertamina official colors
149
+ pertamina: import_tokens.tokens.colors.pertamina
150
+ },
151
+ // Spacing (4px base) - extended dengan icon offset
152
+ spacing: {
153
+ ...import_tokens.tokens.spacing,
154
+ "icon-offset": "2.5px"
155
+ // untuk mt-[2.5px] - icon vertical alignment
156
+ },
157
+ // Typography
158
+ fontFamily: {
159
+ sans: import_tokens.tokens.typography.fontFamily.sans.split(", ").map((f) => f.replace(/"/g, "")),
160
+ serif: import_tokens.tokens.typography.fontFamily.serif.split(", ").map((f) => f.replace(/"/g, "")),
161
+ mono: import_tokens.tokens.typography.fontFamily.mono.split(", ").map((f) => f.replace(/"/g, ""))
162
+ },
163
+ fontSize: import_tokens.tokens.typography.fontSize,
164
+ fontWeight: import_tokens.tokens.typography.fontWeight,
165
+ lineHeight: import_tokens.tokens.typography.lineHeight,
166
+ letterSpacing: import_tokens.tokens.typography.letterSpacing,
167
+ // Border Radius - extended dengan semantic values untuk komponen
168
+ borderRadius: {
169
+ ...import_tokens.tokens.borderRadius,
170
+ // Semantic values untuk komponen (menggantikan arbitrary values)
171
+ button: "6px",
172
+ // untuk rounded-[6px] - button standard radius
173
+ "badge-square": "4px"
174
+ // untuk rounded-[4px] - badge square variant
175
+ },
176
+ // Border Width - ensure border utilities are available
177
+ borderWidth: {
178
+ DEFAULT: "1px",
179
+ "0": "0",
180
+ "1": "1px",
181
+ "2": "2px",
182
+ "4": "4px",
183
+ "8": "8px"
184
+ },
185
+ // Min Width - untuk button sizes (sesuai Figma PACER: sm, md only)
186
+ minWidth: {
187
+ "button-sm": "64px",
188
+ // sm: 36px height
189
+ "button-md": "80px"
190
+ // md: 40px height
191
+ },
192
+ // Opacity
193
+ opacity: import_tokens.tokens.opacity,
194
+ // Max Width
195
+ maxWidth: import_tokens.tokens.maxWidth,
196
+ // Box Shadow - extended dengan focus ring utilities
197
+ boxShadow: {
198
+ ...import_tokens.tokens.shadows,
199
+ // Focus ring shadows untuk accessibility (menggantikan arbitrary shadow values)
200
+ "focus-ring-primary": "0 0 0 2px white, 0 0 0 4px rgb(1 107 248)",
201
+ // brand-300 focus
202
+ "focus-ring-slate": "0 0 0 2px white, 0 0 0 4px rgb(226 232 240)",
203
+ // slate-200 focus
204
+ "focus-ring-danger": "0 0 0 2px white, 0 0 0 4px rgb(254 202 202)",
205
+ // red-200 focus
206
+ "focus-ring-success": "0 0 0 2px white, 0 0 0 4px rgb(187 247 208)",
207
+ // green-200 focus
208
+ "focus-ring-warning": "0 0 0 2px white, 0 0 0 4px rgb(253 230 138)"
209
+ // amber-200 focus (sesuai Figma PACER warning)
210
+ },
211
+ // Animation Duration
212
+ transitionDuration: import_tokens.tokens.motion.duration,
213
+ // Animation Easing
214
+ transitionTimingFunction: import_tokens.tokens.motion.easing,
215
+ // Breakpoints
216
+ screens: import_tokens.tokens.breakpoints,
217
+ // Z-Index
218
+ zIndex: import_tokens.tokens.zIndex
219
+ }
220
+ },
221
+ plugins: [
222
+ // Plugin untuk utility classes (focus rings)
223
+ function({ addUtilities, theme }) {
224
+ addUtilities({
225
+ // Focus ring utilities - untuk menggantikan arbitrary shadow values
226
+ // Menggunakan theme values agar tidak di-flag sebagai dynamic code
227
+ ".focus-ring-primary": {
228
+ "&:focus-visible": {
229
+ outline: "none",
230
+ boxShadow: theme("boxShadow.focus-ring-primary")
231
+ }
232
+ },
233
+ ".focus-ring-slate": {
234
+ "&:focus-visible": {
235
+ outline: "none",
236
+ boxShadow: theme("boxShadow.focus-ring-slate")
237
+ }
238
+ },
239
+ ".focus-ring-danger": {
240
+ "&:focus-visible": {
241
+ outline: "none",
242
+ boxShadow: theme("boxShadow.focus-ring-danger")
243
+ }
244
+ },
245
+ ".focus-ring-success": {
246
+ "&:focus-visible": {
247
+ outline: "none",
248
+ boxShadow: theme("boxShadow.focus-ring-success")
249
+ }
250
+ },
251
+ ".focus-ring-warning": {
252
+ "&:focus-visible": {
253
+ outline: "none",
254
+ boxShadow: theme("boxShadow.focus-ring-warning")
255
+ }
256
+ }
257
+ });
258
+ },
259
+ // Plugin untuk component classes
260
+ function({ addComponents, theme }) {
261
+ addComponents({
262
+ // Button base styles
263
+ ".btn": {
264
+ display: "inline-flex",
265
+ alignItems: "center",
266
+ justifyContent: "center",
267
+ padding: `${theme("spacing.2")} ${theme("spacing.4")}`,
268
+ fontSize: theme("fontSize.base"),
269
+ fontWeight: theme("fontWeight.medium"),
270
+ lineHeight: theme("lineHeight.normal"),
271
+ borderRadius: theme("borderRadius.DEFAULT"),
272
+ transition: `all ${theme("transitionDuration.fast")} ${theme("transitionTimingFunction.easeInOut")}`,
273
+ cursor: "pointer",
274
+ userSelect: "none",
275
+ "&:disabled": {
276
+ cursor: "not-allowed",
277
+ opacity: "0.5"
278
+ }
279
+ },
280
+ // Input base styles
281
+ ".input": {
282
+ display: "block",
283
+ width: "100%",
284
+ padding: `${theme("spacing.2")} ${theme("spacing.3")}`,
285
+ fontSize: theme("fontSize.base"),
286
+ lineHeight: theme("lineHeight.normal"),
287
+ color: theme("colors.neutral.900"),
288
+ backgroundColor: theme("colors.base.white"),
289
+ border: `1px solid ${theme("colors.neutral.300")}`,
290
+ borderRadius: theme("borderRadius.DEFAULT"),
291
+ transition: `border-color ${theme("transitionDuration.fast")} ${theme("transitionTimingFunction.easeInOut")}`,
292
+ "&:focus": {
293
+ outline: "none",
294
+ borderColor: theme("colors.brand.500"),
295
+ boxShadow: `0 0 0 3px ${theme("colors.brand.100")}`
296
+ },
297
+ "&:disabled": {
298
+ cursor: "not-allowed",
299
+ backgroundColor: theme("colors.neutral.100"),
300
+ color: theme("colors.neutral.500")
301
+ }
302
+ },
303
+ // Card base styles
304
+ ".card": {
305
+ backgroundColor: theme("colors.base.white"),
306
+ borderRadius: theme("borderRadius.lg"),
307
+ boxShadow: theme("boxShadow.DEFAULT"),
308
+ padding: theme("spacing.6")
309
+ }
310
+ });
311
+ }
312
+ ]
313
+ };
314
+ var index_default = preset;
package/dist/index.mjs ADDED
@@ -0,0 +1,293 @@
1
+ // src/index.ts
2
+ import { tokens } from "@pacer-ui/tokens";
3
+ var preset = {
4
+ content: [],
5
+ darkMode: "class",
6
+ /**
7
+ * Safelist untuk mengatasi false positive pada SAST/DAST tools.
8
+ * Semua arbitrary values yang digunakan di komponen harus ada di sini
9
+ * agar Tailwind selalu generate classes tersebut dan tidak di-flag sebagai dynamic code injection.
10
+ */
11
+ safelist: [
12
+ // Badge component colors & utilities (generated dynamically in C# code)
13
+ "bg-slate-900",
14
+ "bg-slate-100",
15
+ "text-slate-900",
16
+ "text-slate-50",
17
+ "text-slate-950",
18
+ "bg-yellow-500",
19
+ "bg-yellow-50",
20
+ "text-yellow-500",
21
+ "text-yellow-700",
22
+ "bg-green-600",
23
+ "bg-green-50",
24
+ "bg-green-100",
25
+ "text-green-600",
26
+ "bg-purple-600",
27
+ "bg-purple-50",
28
+ "text-purple-600",
29
+ "bg-pink-600",
30
+ "bg-pink-50",
31
+ "text-pink-600",
32
+ "bg-orange-600",
33
+ "bg-orange-50",
34
+ "text-orange-600",
35
+ "bg-red-50",
36
+ "text-red-600",
37
+ "bg-red-100",
38
+ "rounded-full",
39
+ "rounded-md",
40
+ "px-2.5",
41
+ "py-0.5",
42
+ "px-2",
43
+ "py-1",
44
+ "border-slate-300",
45
+ "border-yellow-500",
46
+ "border-green-600",
47
+ "border-purple-600",
48
+ "border-pink-600",
49
+ "border-orange-600",
50
+ "inline-flex",
51
+ "items-center",
52
+ "justify-center",
53
+ "gap-0.5",
54
+ "text-xs",
55
+ "font-semibold",
56
+ // Border radius arbitrary values
57
+ "rounded-[6px]",
58
+ "rounded-[4px]",
59
+ // Spacing arbitrary values
60
+ "mt-[2.5px]",
61
+ // Min width arbitrary values
62
+ "min-w-[64px]",
63
+ "min-w-[80px]",
64
+ // Border utilities - diperlukan untuk button variants (secondary, outline, danger)
65
+ "border",
66
+ "border-1",
67
+ "border-brand-300",
68
+ "border-red-600",
69
+ // Complex shadow values (focus rings) - ini yang paling sering di-flag
70
+ "focus-visible:shadow-[0_0_0_2px_white,0_0_0_4px_rgb(1_107_248)]",
71
+ "focus-visible:shadow-[0_0_0_2px_white,0_0_0_4px_rgb(226_232_240)]",
72
+ "focus-visible:shadow-[0_0_0_2px_white,0_0_0_4px_rgb(254_202_202)]",
73
+ // Information component – Figma PACER (node 40000837-1003)
74
+ "mt-[4.5px]",
75
+ "rounded-lg",
76
+ "bg-brand-50",
77
+ "bg-slate-100",
78
+ "bg-green-100",
79
+ "bg-amber-100",
80
+ "bg-red-100",
81
+ "text-brand-300",
82
+ "text-brand-400",
83
+ "text-brand-600",
84
+ "text-slate-500",
85
+ "text-slate-600",
86
+ "text-slate-950",
87
+ "text-green-600",
88
+ "text-amber-600",
89
+ "text-red-600",
90
+ "text-xs",
91
+ "text-sm",
92
+ "text-base",
93
+ "font-medium",
94
+ "font-normal",
95
+ "leading-none",
96
+ "leading-5",
97
+ "leading-6"
98
+ ],
99
+ theme: {
100
+ // Extend default Tailwind theme
101
+ extend: {
102
+ // Colors
103
+ colors: {
104
+ // Brand colors
105
+ brand: tokens.colors.brand,
106
+ // Base colors
107
+ base: tokens.colors.base,
108
+ // Color scales
109
+ slate: tokens.colors.slate,
110
+ gray: tokens.colors.gray,
111
+ zinc: tokens.colors.zinc,
112
+ neutral: tokens.colors.neutral,
113
+ stone: tokens.colors.stone,
114
+ // Semantic colors
115
+ red: tokens.colors.red,
116
+ green: tokens.colors.green,
117
+ yellow: tokens.colors.yellow,
118
+ blue: tokens.colors.blue,
119
+ // Semantic aliases
120
+ success: tokens.colors.success,
121
+ warning: tokens.colors.warning,
122
+ error: tokens.colors.error,
123
+ info: tokens.colors.info,
124
+ // Pertamina official colors
125
+ pertamina: tokens.colors.pertamina
126
+ },
127
+ // Spacing (4px base) - extended dengan icon offset
128
+ spacing: {
129
+ ...tokens.spacing,
130
+ "icon-offset": "2.5px"
131
+ // untuk mt-[2.5px] - icon vertical alignment
132
+ },
133
+ // Typography
134
+ fontFamily: {
135
+ sans: tokens.typography.fontFamily.sans.split(", ").map((f) => f.replace(/"/g, "")),
136
+ serif: tokens.typography.fontFamily.serif.split(", ").map((f) => f.replace(/"/g, "")),
137
+ mono: tokens.typography.fontFamily.mono.split(", ").map((f) => f.replace(/"/g, ""))
138
+ },
139
+ fontSize: tokens.typography.fontSize,
140
+ fontWeight: tokens.typography.fontWeight,
141
+ lineHeight: tokens.typography.lineHeight,
142
+ letterSpacing: tokens.typography.letterSpacing,
143
+ // Border Radius - extended dengan semantic values untuk komponen
144
+ borderRadius: {
145
+ ...tokens.borderRadius,
146
+ // Semantic values untuk komponen (menggantikan arbitrary values)
147
+ button: "6px",
148
+ // untuk rounded-[6px] - button standard radius
149
+ "badge-square": "4px"
150
+ // untuk rounded-[4px] - badge square variant
151
+ },
152
+ // Border Width - ensure border utilities are available
153
+ borderWidth: {
154
+ DEFAULT: "1px",
155
+ "0": "0",
156
+ "1": "1px",
157
+ "2": "2px",
158
+ "4": "4px",
159
+ "8": "8px"
160
+ },
161
+ // Min Width - untuk button sizes (sesuai Figma PACER: sm, md only)
162
+ minWidth: {
163
+ "button-sm": "64px",
164
+ // sm: 36px height
165
+ "button-md": "80px"
166
+ // md: 40px height
167
+ },
168
+ // Opacity
169
+ opacity: tokens.opacity,
170
+ // Max Width
171
+ maxWidth: tokens.maxWidth,
172
+ // Box Shadow - extended dengan focus ring utilities
173
+ boxShadow: {
174
+ ...tokens.shadows,
175
+ // Focus ring shadows untuk accessibility (menggantikan arbitrary shadow values)
176
+ "focus-ring-primary": "0 0 0 2px white, 0 0 0 4px rgb(1 107 248)",
177
+ // brand-300 focus
178
+ "focus-ring-slate": "0 0 0 2px white, 0 0 0 4px rgb(226 232 240)",
179
+ // slate-200 focus
180
+ "focus-ring-danger": "0 0 0 2px white, 0 0 0 4px rgb(254 202 202)",
181
+ // red-200 focus
182
+ "focus-ring-success": "0 0 0 2px white, 0 0 0 4px rgb(187 247 208)",
183
+ // green-200 focus
184
+ "focus-ring-warning": "0 0 0 2px white, 0 0 0 4px rgb(253 230 138)"
185
+ // amber-200 focus (sesuai Figma PACER warning)
186
+ },
187
+ // Animation Duration
188
+ transitionDuration: tokens.motion.duration,
189
+ // Animation Easing
190
+ transitionTimingFunction: tokens.motion.easing,
191
+ // Breakpoints
192
+ screens: tokens.breakpoints,
193
+ // Z-Index
194
+ zIndex: tokens.zIndex
195
+ }
196
+ },
197
+ plugins: [
198
+ // Plugin untuk utility classes (focus rings)
199
+ function({ addUtilities, theme }) {
200
+ addUtilities({
201
+ // Focus ring utilities - untuk menggantikan arbitrary shadow values
202
+ // Menggunakan theme values agar tidak di-flag sebagai dynamic code
203
+ ".focus-ring-primary": {
204
+ "&:focus-visible": {
205
+ outline: "none",
206
+ boxShadow: theme("boxShadow.focus-ring-primary")
207
+ }
208
+ },
209
+ ".focus-ring-slate": {
210
+ "&:focus-visible": {
211
+ outline: "none",
212
+ boxShadow: theme("boxShadow.focus-ring-slate")
213
+ }
214
+ },
215
+ ".focus-ring-danger": {
216
+ "&:focus-visible": {
217
+ outline: "none",
218
+ boxShadow: theme("boxShadow.focus-ring-danger")
219
+ }
220
+ },
221
+ ".focus-ring-success": {
222
+ "&:focus-visible": {
223
+ outline: "none",
224
+ boxShadow: theme("boxShadow.focus-ring-success")
225
+ }
226
+ },
227
+ ".focus-ring-warning": {
228
+ "&:focus-visible": {
229
+ outline: "none",
230
+ boxShadow: theme("boxShadow.focus-ring-warning")
231
+ }
232
+ }
233
+ });
234
+ },
235
+ // Plugin untuk component classes
236
+ function({ addComponents, theme }) {
237
+ addComponents({
238
+ // Button base styles
239
+ ".btn": {
240
+ display: "inline-flex",
241
+ alignItems: "center",
242
+ justifyContent: "center",
243
+ padding: `${theme("spacing.2")} ${theme("spacing.4")}`,
244
+ fontSize: theme("fontSize.base"),
245
+ fontWeight: theme("fontWeight.medium"),
246
+ lineHeight: theme("lineHeight.normal"),
247
+ borderRadius: theme("borderRadius.DEFAULT"),
248
+ transition: `all ${theme("transitionDuration.fast")} ${theme("transitionTimingFunction.easeInOut")}`,
249
+ cursor: "pointer",
250
+ userSelect: "none",
251
+ "&:disabled": {
252
+ cursor: "not-allowed",
253
+ opacity: "0.5"
254
+ }
255
+ },
256
+ // Input base styles
257
+ ".input": {
258
+ display: "block",
259
+ width: "100%",
260
+ padding: `${theme("spacing.2")} ${theme("spacing.3")}`,
261
+ fontSize: theme("fontSize.base"),
262
+ lineHeight: theme("lineHeight.normal"),
263
+ color: theme("colors.neutral.900"),
264
+ backgroundColor: theme("colors.base.white"),
265
+ border: `1px solid ${theme("colors.neutral.300")}`,
266
+ borderRadius: theme("borderRadius.DEFAULT"),
267
+ transition: `border-color ${theme("transitionDuration.fast")} ${theme("transitionTimingFunction.easeInOut")}`,
268
+ "&:focus": {
269
+ outline: "none",
270
+ borderColor: theme("colors.brand.500"),
271
+ boxShadow: `0 0 0 3px ${theme("colors.brand.100")}`
272
+ },
273
+ "&:disabled": {
274
+ cursor: "not-allowed",
275
+ backgroundColor: theme("colors.neutral.100"),
276
+ color: theme("colors.neutral.500")
277
+ }
278
+ },
279
+ // Card base styles
280
+ ".card": {
281
+ backgroundColor: theme("colors.base.white"),
282
+ borderRadius: theme("borderRadius.lg"),
283
+ boxShadow: theme("boxShadow.DEFAULT"),
284
+ padding: theme("spacing.6")
285
+ }
286
+ });
287
+ }
288
+ ]
289
+ };
290
+ var index_default = preset;
291
+ export {
292
+ index_default as default
293
+ };
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@pacer-ui/tailwind-preset",
3
+ "version": "1.0.1",
4
+ "description": "",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "require": "./dist/index.js",
11
+ "import": "./dist/index.mjs"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "keywords": [
18
+ "tailwindcss",
19
+ "preset",
20
+ "design-system",
21
+ "pertamina"
22
+ ],
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "@pacer-ui/tokens": "1.0.1"
26
+ },
27
+ "peerDependencies": {
28
+ "tailwindcss": "^3.4.0"
29
+ },
30
+ "devDependencies": {
31
+ "tailwindcss": "^3.4.0",
32
+ "tsup": "^8.0.1",
33
+ "typescript": "^5.3.3"
34
+ },
35
+ "scripts": {
36
+ "build": "tsup src/index.ts --format esm,cjs --dts",
37
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
38
+ "clean": "rm -rf dist"
39
+ }
40
+ }