lkd-web-kit 0.10.2 → 0.10.3
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/.agents/skills/mantine-combobox/SKILL.md +73 -0
- package/.agents/skills/mantine-combobox/references/api.md +199 -0
- package/.agents/skills/mantine-combobox/references/patterns.md +279 -0
- package/.agents/skills/mantine-custom-components/SKILL.md +112 -0
- package/.agents/skills/mantine-custom-components/references/api.md +407 -0
- package/.agents/skills/mantine-custom-components/references/patterns.md +431 -0
- package/.agents/skills/publish-lkd-web-kit/SKILL.md +172 -0
- package/.agents/skills/publish-lkd-web-kit/agents/openai.yaml +4 -0
- package/.agents/skills/publish-lkd-web-kit/references/npm-trusted-publishing.md +82 -0
- package/.agents/skills/update-lkd-dependencies/SKILL.md +88 -0
- package/.agents/skills/update-lkd-dependencies/agents/openai.yaml +4 -0
- package/.agents/skills/update-lkd-dependencies/scripts/collect-npm-metadata.mjs +73 -0
- package/dist/index.cjs +2 -0
- package/dist/index.js +2 -1
- package/dist/mantine/breakpoints-with-px.cjs +3 -2
- package/dist/mantine/breakpoints-with-px.d.ts +2 -1
- package/dist/mantine/breakpoints-with-px.d.ts.map +1 -1
- package/dist/mantine/breakpoints-with-px.js +3 -2
- package/dist/mantine/create-lkd-theme.cjs +7 -0
- package/dist/mantine/create-lkd-theme.d.ts +3 -0
- package/dist/mantine/create-lkd-theme.d.ts.map +1 -0
- package/dist/mantine/create-lkd-theme.js +6 -0
- package/dist/mantine/index.d.ts +1 -0
- package/dist/mantine/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/scripts/{install-codex-skills.mjs → install-agent-skills.mjs} +1 -1
- package/codex/skills/create-modal-component/SKILL.md +0 -168
- package/codex/skills/create-modal-component/agents/openai.yaml +0 -4
- package/codex/skills/create-svg-icon/SKILL.md +0 -41
- package/codex/skills/create-svg-icon/agents/openai.yaml +0 -3
- package/codex/skills/create-table-component/SKILL.md +0 -189
- package/codex/skills/create-table-component/agents/openai.yaml +0 -3
- package/codex/skills/rhf-lkd-forms/SKILL.md +0 -186
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
# Custom Component Patterns
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
- [Minimal component (no styles API)](#minimal-component-no-styles-api)
|
|
5
|
+
- [Component with CSS variables](#component-with-css-variables)
|
|
6
|
+
- [Compound component with context](#compound-component-with-context)
|
|
7
|
+
- [Polymorphic component](#polymorphic-component)
|
|
8
|
+
- [Generic component](#generic-component)
|
|
9
|
+
- [Theme integration](#theme-integration)
|
|
10
|
+
- [Namespace exports](#namespace-exports)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Minimal component (no styles API)
|
|
15
|
+
|
|
16
|
+
When you don't need theming/Styles API support — just Box + useProps.
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { Box, BoxProps, ElementProps, factory, Factory, useProps } from '@mantine/core';
|
|
20
|
+
|
|
21
|
+
export interface MinimalProps extends BoxProps, ElementProps<'div'> {
|
|
22
|
+
label?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type MinimalFactory = Factory<{
|
|
26
|
+
props: MinimalProps;
|
|
27
|
+
ref: HTMLDivElement;
|
|
28
|
+
}>;
|
|
29
|
+
|
|
30
|
+
const defaultProps = {} satisfies Partial<MinimalProps>;
|
|
31
|
+
|
|
32
|
+
export const Minimal = factory<MinimalFactory>((_props) => {
|
|
33
|
+
const props = useProps('Minimal', defaultProps, _props);
|
|
34
|
+
const { label, children, ...others } = props;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Box {...others}>
|
|
38
|
+
{label && <span>{label}</span>}
|
|
39
|
+
{children}
|
|
40
|
+
</Box>
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
Minimal.displayName = '@mantine/core/Minimal';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Component with CSS variables
|
|
50
|
+
|
|
51
|
+
Full example with Styles API, CSS variables, and theme integration.
|
|
52
|
+
|
|
53
|
+
**MyComponent.module.css:**
|
|
54
|
+
```css
|
|
55
|
+
.root {
|
|
56
|
+
border-radius: var(--my-radius);
|
|
57
|
+
padding: var(--my-padding);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.inner {
|
|
61
|
+
font-size: var(--my-fz);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**MyComponent.tsx:**
|
|
66
|
+
```tsx
|
|
67
|
+
import {
|
|
68
|
+
Box, BoxProps, createVarsResolver, ElementProps, factory, Factory,
|
|
69
|
+
getFontSize, getRadius, getSpacing, MantineFontSize, MantineRadius,
|
|
70
|
+
MantineSpacing, StylesApiProps, useProps, useStyles,
|
|
71
|
+
} from '@mantine/core';
|
|
72
|
+
import classes from './MyComponent.module.css';
|
|
73
|
+
|
|
74
|
+
export type MyComponentStylesNames = 'root' | 'inner';
|
|
75
|
+
export type MyComponentVariant = 'filled' | 'outline';
|
|
76
|
+
export type MyComponentCssVariables = {
|
|
77
|
+
root: '--my-radius' | '--my-padding';
|
|
78
|
+
inner: '--my-fz';
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export interface MyComponentProps
|
|
82
|
+
extends BoxProps, StylesApiProps<MyComponentFactory>, ElementProps<'div'> {
|
|
83
|
+
radius?: MantineRadius;
|
|
84
|
+
padding?: MantineSpacing;
|
|
85
|
+
size?: MantineFontSize;
|
|
86
|
+
variant?: MyComponentVariant;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type MyComponentFactory = Factory<{
|
|
90
|
+
props: MyComponentProps;
|
|
91
|
+
ref: HTMLDivElement;
|
|
92
|
+
stylesNames: MyComponentStylesNames;
|
|
93
|
+
vars: MyComponentCssVariables;
|
|
94
|
+
variant: MyComponentVariant;
|
|
95
|
+
}>;
|
|
96
|
+
|
|
97
|
+
const defaultProps = {
|
|
98
|
+
radius: 'sm',
|
|
99
|
+
padding: 'md',
|
|
100
|
+
size: 'md',
|
|
101
|
+
} satisfies Partial<MyComponentProps>;
|
|
102
|
+
|
|
103
|
+
const varsResolver = createVarsResolver<MyComponentFactory>((_theme, { radius, padding, size }) => ({
|
|
104
|
+
root: {
|
|
105
|
+
'--my-radius': getRadius(radius),
|
|
106
|
+
'--my-padding': getSpacing(padding),
|
|
107
|
+
},
|
|
108
|
+
inner: {
|
|
109
|
+
'--my-fz': getFontSize(size),
|
|
110
|
+
},
|
|
111
|
+
}));
|
|
112
|
+
|
|
113
|
+
export const MyComponent = factory<MyComponentFactory>((_props) => {
|
|
114
|
+
const props = useProps('MyComponent', defaultProps, _props);
|
|
115
|
+
const {
|
|
116
|
+
classNames, className, style, styles, unstyled, vars, attributes,
|
|
117
|
+
radius, padding, size,
|
|
118
|
+
children,
|
|
119
|
+
...others
|
|
120
|
+
} = props;
|
|
121
|
+
|
|
122
|
+
const getStyles = useStyles<MyComponentFactory>({
|
|
123
|
+
name: 'MyComponent',
|
|
124
|
+
classes,
|
|
125
|
+
props,
|
|
126
|
+
className,
|
|
127
|
+
style,
|
|
128
|
+
classNames,
|
|
129
|
+
styles,
|
|
130
|
+
unstyled,
|
|
131
|
+
vars,
|
|
132
|
+
attributes,
|
|
133
|
+
varsResolver,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<Box {...getStyles('root')} {...others}>
|
|
138
|
+
<div {...getStyles('inner')}>{children}</div>
|
|
139
|
+
</Box>
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
MyComponent.displayName = '@mantine/core/MyComponent';
|
|
144
|
+
MyComponent.classes = classes;
|
|
145
|
+
MyComponent.varsResolver = varsResolver;
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Compound component with context
|
|
151
|
+
|
|
152
|
+
Pattern for components with typed sub-components (e.g. `Card.Section`, `Tabs.Tab`).
|
|
153
|
+
|
|
154
|
+
**MyCard.context.ts:**
|
|
155
|
+
```ts
|
|
156
|
+
import { createSafeContext, GetStylesApi } from '@mantine/core';
|
|
157
|
+
import type { MyCardFactory } from './MyCard';
|
|
158
|
+
|
|
159
|
+
interface MyCardContextValue {
|
|
160
|
+
getStyles: GetStylesApi<MyCardFactory>;
|
|
161
|
+
orientation: 'horizontal' | 'vertical';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const [MyCardProvider, useMyCardContext] = createSafeContext<MyCardContextValue>(
|
|
165
|
+
'MyCard component was not found in tree'
|
|
166
|
+
);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**MyCardSection.tsx** (sub-component):
|
|
170
|
+
```tsx
|
|
171
|
+
import {
|
|
172
|
+
Box, BoxProps, CompoundStylesApiProps, ElementProps,
|
|
173
|
+
factory, Factory, useProps, useStyles,
|
|
174
|
+
} from '@mantine/core';
|
|
175
|
+
import { useMyCardContext } from './MyCard.context';
|
|
176
|
+
import classes from './MyCard.module.css';
|
|
177
|
+
|
|
178
|
+
export type MyCardSectionStylesNames = 'section';
|
|
179
|
+
|
|
180
|
+
export interface MyCardSectionProps
|
|
181
|
+
extends BoxProps, CompoundStylesApiProps<MyCardSectionFactory>, ElementProps<'div'> {
|
|
182
|
+
withBorder?: boolean;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export type MyCardSectionFactory = Factory<{
|
|
186
|
+
props: MyCardSectionProps;
|
|
187
|
+
ref: HTMLDivElement;
|
|
188
|
+
stylesNames: MyCardSectionStylesNames;
|
|
189
|
+
compound: true; // marks as a compound sub-component
|
|
190
|
+
}>;
|
|
191
|
+
|
|
192
|
+
const defaultProps = {} satisfies Partial<MyCardSectionProps>;
|
|
193
|
+
|
|
194
|
+
export const MyCardSection = factory<MyCardSectionFactory>((_props) => {
|
|
195
|
+
const props = useProps('MyCardSection', defaultProps, _props);
|
|
196
|
+
const { className, style, classNames, styles, withBorder, children, ...others } = props;
|
|
197
|
+
|
|
198
|
+
// Access styles from parent context
|
|
199
|
+
const { getStyles } = useMyCardContext();
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<Box
|
|
203
|
+
{...getStyles('section', { className, style, classNames, styles })}
|
|
204
|
+
data-with-border={withBorder || undefined}
|
|
205
|
+
{...others}
|
|
206
|
+
>
|
|
207
|
+
{children}
|
|
208
|
+
</Box>
|
|
209
|
+
);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
MyCardSection.displayName = '@mantine/core/MyCardSection';
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**MyCard.tsx** (root component):
|
|
216
|
+
```tsx
|
|
217
|
+
import { MyCardProvider } from './MyCard.context';
|
|
218
|
+
|
|
219
|
+
// ... (same Styles API setup as above)
|
|
220
|
+
|
|
221
|
+
export type MyCardFactory = Factory<{
|
|
222
|
+
props: MyCardProps;
|
|
223
|
+
ref: HTMLDivElement;
|
|
224
|
+
stylesNames: 'root' | 'section'; // include sub-component selectors too
|
|
225
|
+
staticComponents: {
|
|
226
|
+
Section: typeof MyCardSection;
|
|
227
|
+
};
|
|
228
|
+
}>;
|
|
229
|
+
|
|
230
|
+
export const MyCard = factory<MyCardFactory>((_props) => {
|
|
231
|
+
const props = useProps('MyCard', defaultProps, _props);
|
|
232
|
+
const {
|
|
233
|
+
classNames, className, style, styles, unstyled, vars, attributes,
|
|
234
|
+
orientation, children, ...others
|
|
235
|
+
} = props;
|
|
236
|
+
|
|
237
|
+
const getStyles = useStyles<MyCardFactory>({ ... });
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<MyCardProvider value={{ getStyles, orientation: orientation ?? 'vertical' }}>
|
|
241
|
+
<Box {...getStyles('root')} {...others}>{children}</Box>
|
|
242
|
+
</MyCardProvider>
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
MyCard.displayName = '@mantine/core/MyCard';
|
|
247
|
+
MyCard.classes = classes;
|
|
248
|
+
MyCard.Section = MyCardSection; // attach sub-component
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Polymorphic component
|
|
254
|
+
|
|
255
|
+
Supports `component` prop to render as any element or React component.
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
import {
|
|
259
|
+
Box, BoxProps, polymorphicFactory, PolymorphicFactory,
|
|
260
|
+
StylesApiProps, useProps, useStyles,
|
|
261
|
+
} from '@mantine/core';
|
|
262
|
+
|
|
263
|
+
export type MyLinkStylesNames = 'root';
|
|
264
|
+
|
|
265
|
+
export interface MyLinkProps extends BoxProps, StylesApiProps<MyLinkFactory> {
|
|
266
|
+
active?: boolean;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export type MyLinkFactory = PolymorphicFactory<{
|
|
270
|
+
props: MyLinkProps;
|
|
271
|
+
defaultRef: HTMLAnchorElement;
|
|
272
|
+
defaultComponent: 'a'; // renders as <a> unless component prop is provided
|
|
273
|
+
stylesNames: MyLinkStylesNames;
|
|
274
|
+
}>;
|
|
275
|
+
|
|
276
|
+
const defaultProps = {} satisfies Partial<MyLinkProps>;
|
|
277
|
+
|
|
278
|
+
export const MyLink = polymorphicFactory<MyLinkFactory>((_props) => {
|
|
279
|
+
const props = useProps('MyLink', defaultProps, _props);
|
|
280
|
+
const {
|
|
281
|
+
classNames, className, style, styles, unstyled, vars, attributes,
|
|
282
|
+
active, ...others
|
|
283
|
+
} = props;
|
|
284
|
+
|
|
285
|
+
const getStyles = useStyles<MyLinkFactory>({
|
|
286
|
+
name: 'MyLink', classes, props, className, style,
|
|
287
|
+
classNames, styles, unstyled, vars, attributes,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
<Box
|
|
292
|
+
component="a" // default element
|
|
293
|
+
data-active={active || undefined}
|
|
294
|
+
{...getStyles('root')}
|
|
295
|
+
{...others}
|
|
296
|
+
/>
|
|
297
|
+
);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
MyLink.displayName = '@mantine/core/MyLink';
|
|
301
|
+
MyLink.classes = classes;
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Usage:**
|
|
305
|
+
```tsx
|
|
306
|
+
<MyLink href="/about">Link</MyLink>
|
|
307
|
+
<MyLink component="button" onClick={fn}>As button</MyLink>
|
|
308
|
+
<MyLink component={RouterLink} to="/about">Router link</MyLink>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Generic component
|
|
314
|
+
|
|
315
|
+
For components where prop types depend on a generic parameter.
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import { factory, Factory, genericFactory, useProps } from '@mantine/core';
|
|
319
|
+
|
|
320
|
+
type SelectValue<M extends boolean> = M extends true ? string[] : string | null;
|
|
321
|
+
|
|
322
|
+
export interface MySelectProps<M extends boolean = false>
|
|
323
|
+
extends BoxProps, StylesApiProps<MySelectFactory> {
|
|
324
|
+
multiple?: M;
|
|
325
|
+
value?: SelectValue<M>;
|
|
326
|
+
defaultValue?: SelectValue<M>;
|
|
327
|
+
onChange?: (value: SelectValue<M>) => void;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export type MySelectFactory = Factory<{
|
|
331
|
+
props: MySelectProps;
|
|
332
|
+
ref: HTMLDivElement;
|
|
333
|
+
signature: <M extends boolean = false>(props: MySelectProps<M>) => React.JSX.Element;
|
|
334
|
+
stylesNames: 'root';
|
|
335
|
+
}>;
|
|
336
|
+
|
|
337
|
+
const defaultProps = { multiple: false } satisfies Partial<MySelectProps>;
|
|
338
|
+
|
|
339
|
+
export const MySelect = genericFactory<MySelectFactory>((_props) => {
|
|
340
|
+
const props = useProps('MySelect', defaultProps as any, _props);
|
|
341
|
+
const { multiple, value, onChange, ...others } = props;
|
|
342
|
+
// ...
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
MySelect.displayName = '@mantine/core/MySelect';
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Usage:**
|
|
349
|
+
```tsx
|
|
350
|
+
// TypeScript infers value as string | null
|
|
351
|
+
<MySelect value={val} onChange={(v) => setVal(v)} />
|
|
352
|
+
|
|
353
|
+
// TypeScript infers value as string[]
|
|
354
|
+
<MySelect multiple value={vals} onChange={(v) => setVals(v)} />
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Theme integration
|
|
360
|
+
|
|
361
|
+
Components built with `factory()` automatically get `.extend()` and `.withProps()`.
|
|
362
|
+
|
|
363
|
+
**`.extend()`** — for theme-level configuration in `createTheme`:
|
|
364
|
+
```tsx
|
|
365
|
+
const theme = createTheme({
|
|
366
|
+
components: {
|
|
367
|
+
MyComponent: MyComponent.extend({
|
|
368
|
+
// Override default props
|
|
369
|
+
defaultProps: {
|
|
370
|
+
radius: 'xl',
|
|
371
|
+
size: 'lg',
|
|
372
|
+
},
|
|
373
|
+
// Add classes to selectors
|
|
374
|
+
classNames: {
|
|
375
|
+
root: 'my-root-class',
|
|
376
|
+
inner: 'my-inner-class',
|
|
377
|
+
},
|
|
378
|
+
// Add inline styles to selectors
|
|
379
|
+
styles: {
|
|
380
|
+
root: { border: '1px solid red' },
|
|
381
|
+
},
|
|
382
|
+
// Or use a callback for theme-aware styles
|
|
383
|
+
styles: (theme) => ({
|
|
384
|
+
root: { background: theme.colors.blue[0] },
|
|
385
|
+
}),
|
|
386
|
+
// Override CSS variables
|
|
387
|
+
vars: (_theme, props) => ({
|
|
388
|
+
root: { '--my-radius': props.radius ? getRadius(props.radius) : undefined },
|
|
389
|
+
}),
|
|
390
|
+
}),
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**`.withProps()`** — create a pre-configured variant at the call site:
|
|
396
|
+
```tsx
|
|
397
|
+
const BigMyComponent = MyComponent.withProps({ size: 'xl', radius: 'lg' });
|
|
398
|
+
|
|
399
|
+
// Same as MyComponent but with size and radius pre-set
|
|
400
|
+
<BigMyComponent>Content</BigMyComponent>
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Namespace exports
|
|
406
|
+
|
|
407
|
+
Add at the bottom of the component file or `index.ts` to let consumers access types without extra imports.
|
|
408
|
+
|
|
409
|
+
```tsx
|
|
410
|
+
export namespace MyComponent {
|
|
411
|
+
export type Props = MyComponentProps;
|
|
412
|
+
export type StylesNames = MyComponentStylesNames;
|
|
413
|
+
export type CssVariables = MyComponentCssVariables;
|
|
414
|
+
export type Factory = MyComponentFactory;
|
|
415
|
+
export type Variant = MyComponentVariant;
|
|
416
|
+
|
|
417
|
+
export namespace Section {
|
|
418
|
+
export type Props = MyComponentSectionProps;
|
|
419
|
+
export type StylesNames = MyComponentSectionStylesNames;
|
|
420
|
+
export type Factory = MyComponentSectionFactory;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Usage:**
|
|
426
|
+
```ts
|
|
427
|
+
import { MyComponent } from './MyComponent';
|
|
428
|
+
|
|
429
|
+
// No need to import MyComponentProps separately
|
|
430
|
+
const props: MyComponent.Props = { radius: 'md' };
|
|
431
|
+
```
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish-lkd-web-kit
|
|
3
|
+
description: Versiona y publica lkd-web-kit en npm mediante GitHub Actions y Trusted Publishing. Usar cuando el usuario pida subir la version del paquete, preparar un release, crear el tag vX.Y.Z, configurar el workflow de publicacion o publicar sin login interactivo del navegador.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Publicar LKD Web Kit
|
|
7
|
+
|
|
8
|
+
## Principio
|
|
9
|
+
|
|
10
|
+
Publica solo desde un estado validado y reproducible. No automatices `npm login` en navegador. La ruta preferida es GitHub Actions con npm Trusted Publishing y `npm publish --provenance`.
|
|
11
|
+
|
|
12
|
+
Para actualizar dependencias antes del release, usa `$update-lkd-dependencies`.
|
|
13
|
+
|
|
14
|
+
## Preflight obligatorio
|
|
15
|
+
|
|
16
|
+
Antes de cambiar version o crear tags:
|
|
17
|
+
|
|
18
|
+
1. Lee `AGENTS.md`, `package.json`, `package-lock.json` y `docs/generated/lkd-web-kit.md`.
|
|
19
|
+
2. Ejecuta `git status --short` y confirma que el worktree esta limpio o que solo contiene cambios esperados para el release.
|
|
20
|
+
3. Verifica que `package.json` y `package-lock.json` declaran la misma version del paquete.
|
|
21
|
+
4. Revisa si existe `.github/workflows/publish.yml`.
|
|
22
|
+
5. Si Trusted Publishing no esta configurado en npm, lee `references/npm-trusted-publishing.md` y detente antes de publicar hasta que un maintainer/admin lo habilite.
|
|
23
|
+
6. Identifica la version anterior publicada/local y la version nueva objetivo; las necesitaras para la upgrade guide.
|
|
24
|
+
|
|
25
|
+
## Versionado SemVer cauteloso
|
|
26
|
+
|
|
27
|
+
Elige el bump por impacto publico:
|
|
28
|
+
|
|
29
|
+
- `major`: cambia compatibilidad publica, elimina APIs, altera contratos de componentes, o hace incompatible algun rango peer importante.
|
|
30
|
+
- `minor`: agrega soporte compatible, nuevos componentes, nuevas props compatibles o amplia peers sin romper consumers.
|
|
31
|
+
- `patch`: mantenimiento, fixes internos, ajustes de build o dependencia compatible sin impacto publico.
|
|
32
|
+
|
|
33
|
+
Si el usuario da una version exacta, usala solo si es SemVer valida y mayor que la version publicada/local.
|
|
34
|
+
|
|
35
|
+
Aplica la version sin crear tag automaticamente:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm version <major|minor|patch> --no-git-tag-version
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
o:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm version <x.y.z> --no-git-tag-version
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Validacion de release
|
|
48
|
+
|
|
49
|
+
Ejecuta siempre:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm run lint
|
|
53
|
+
npm run test
|
|
54
|
+
npm run build
|
|
55
|
+
npm pack --dry-run
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
No continues si falla una validacion. Corrige el problema si esta dentro del alcance del release; si no, reporta el bloqueo.
|
|
59
|
+
|
|
60
|
+
## Upgrade guide obligatoria
|
|
61
|
+
|
|
62
|
+
Antes de crear el commit/tag de release, crea una guia de migracion para consumidores en:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
docs/generated/upgrade-guides/upgrade-v<version-anterior>-to-v<version-nueva>.md
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Ejemplo:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
docs/generated/upgrade-guides/upgrade-v0.8.1-to-v0.9.0.md
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
La guia debe estar en espanol y contener un prompt listo para copiar y pegar en la IA del proyecto consumidor. Usa esta estructura:
|
|
75
|
+
|
|
76
|
+
```md
|
|
77
|
+
# Upgrade v<version-anterior> to v<version-nueva>
|
|
78
|
+
|
|
79
|
+
## Resumen
|
|
80
|
+
|
|
81
|
+
Describe en 2-4 bullets que cambia en `lkd-web-kit` y el riesgo esperado.
|
|
82
|
+
|
|
83
|
+
## Dependencias a actualizar
|
|
84
|
+
|
|
85
|
+
Lista exacta de paquetes y rangos/versiones requeridas:
|
|
86
|
+
- `lkd-web-kit`: `<version-nueva>`
|
|
87
|
+
- `<peer>`: `<rango-nuevo>`
|
|
88
|
+
|
|
89
|
+
Indica tambien peers que no cambian si son relevantes para evitar confusion.
|
|
90
|
+
|
|
91
|
+
## Cambios de API o comportamiento
|
|
92
|
+
|
|
93
|
+
Si hubo cambios de nombres, componentes, props, parametros, tipos, exports, hooks, utils o comportamiento, especifica:
|
|
94
|
+
- Antes: `...`
|
|
95
|
+
- Despues: `...`
|
|
96
|
+
- Accion requerida en consumidores: `...`
|
|
97
|
+
|
|
98
|
+
Si no hubo cambios de API publica, escribe explicitamente: `No hay cambios de API publica detectados.`
|
|
99
|
+
|
|
100
|
+
## Cambios requeridos por dependencias peer
|
|
101
|
+
|
|
102
|
+
Explica si las nuevas versiones de React, Mantine, Next, Zod, React Hook Form, TanStack, Ky u otros peers requieren cambios en los proyectos consumidores. Si no hay cambios esperados, declaralo explicitamente.
|
|
103
|
+
|
|
104
|
+
## Prompt para IA del proyecto consumidor
|
|
105
|
+
|
|
106
|
+
Incluye un prompt completo que instruya a la IA del proyecto consumidor a:
|
|
107
|
+
- Leer `package.json`, lockfile, `AGENTS.md` y documentacion local del proyecto.
|
|
108
|
+
- Actualizar `lkd-web-kit` y peers a los rangos indicados.
|
|
109
|
+
- Buscar imports/usos afectados con `rg`.
|
|
110
|
+
- Aplicar cambios de API descritos en esta guia.
|
|
111
|
+
- Ejecutar `npm install`, `npm run lint`, `npm run test` y `npm run build`.
|
|
112
|
+
- Reportar cambios aplicados, archivos modificados, validaciones y bloqueos.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Reglas:
|
|
116
|
+
|
|
117
|
+
- No inventes breaking changes. Si no hay cambios de nombres, parametros o props, dilo.
|
|
118
|
+
- Si `docs/generated/lkd-web-kit.md` cambio por superficie publica nueva, usa ese diff como fuente para la seccion de API.
|
|
119
|
+
- Si solo cambiaron peers, aun asi crea la guia y enfocate en dependencias y validaciones para consumidores.
|
|
120
|
+
- La guia forma parte del release y debe entrar en el mismo commit `release: vX.Y.Z`.
|
|
121
|
+
|
|
122
|
+
## Commit, tag y publicacion
|
|
123
|
+
|
|
124
|
+
1. Revisa el diff final y confirma que incluye la upgrade guide correspondiente y solo cambios esperados.
|
|
125
|
+
2. Crea un commit de release con el formato:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
git commit -m "release: vX.Y.Z"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
3. Crea el tag:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
git tag vX.Y.Z
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
4. Empuja commit y tag solo cuando el usuario haya pedido publicar:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
git push origin HEAD
|
|
141
|
+
git push origin vX.Y.Z
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
5. La publicacion debe ocurrir en GitHub Actions por el trigger del tag. No ejecutes `npm publish` localmente salvo instruccion explicita y consciente del usuario.
|
|
145
|
+
|
|
146
|
+
## Reporte final
|
|
147
|
+
|
|
148
|
+
Reporta en espanol:
|
|
149
|
+
|
|
150
|
+
- Version anterior y nueva.
|
|
151
|
+
- Tipo de bump y justificacion.
|
|
152
|
+
- Ruta de la upgrade guide generada.
|
|
153
|
+
- Validaciones ejecutadas.
|
|
154
|
+
- Commit/tag creados o pendientes.
|
|
155
|
+
- Estado del workflow de Trusted Publishing y si queda algun paso manual en npm.
|
|
156
|
+
- Comandos exactos que el usuario debe ejecutar para disparar el workflow de publicacion cuando el release quede listo.
|
|
157
|
+
|
|
158
|
+
Incluye siempre este bloque, ajustando `vX.Y.Z` por la version real:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
git push origin HEAD
|
|
162
|
+
git push origin vX.Y.Z
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Si el commit o tag todavia no fueron creados, incluye tambien los comandos pendientes antes del push:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
git commit -m "release: vX.Y.Z"
|
|
169
|
+
git tag vX.Y.Z
|
|
170
|
+
git push origin HEAD
|
|
171
|
+
git push origin vX.Y.Z
|
|
172
|
+
```
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# npm Trusted Publishing para lkd-web-kit
|
|
2
|
+
|
|
3
|
+
Usa esta referencia cuando el usuario quiera publicar sin `npm login` interactivo o cuando falte `.github/workflows/publish.yml`.
|
|
4
|
+
|
|
5
|
+
## Configuracion esperada en npm
|
|
6
|
+
|
|
7
|
+
Un maintainer/admin del paquete debe configurar Trusted Publishing en npm con estos datos:
|
|
8
|
+
|
|
9
|
+
- Package: `lkd-web-kit`
|
|
10
|
+
- Provider: GitHub Actions
|
|
11
|
+
- Repository owner/name: `jrjais/lkd-web-kit`
|
|
12
|
+
- Workflow file: `publish.yml`
|
|
13
|
+
- Environment: dejar vacio salvo que el repo use environments protegidos
|
|
14
|
+
|
|
15
|
+
Si npm rechaza la configuracion por permisos, detenerse. No intentes automatizar el navegador ni pedir credenciales. Indica que debe hacerlo una cuenta con permisos de maintainer/admin sobre el paquete.
|
|
16
|
+
|
|
17
|
+
## Workflow recomendado
|
|
18
|
+
|
|
19
|
+
Crea `.github/workflows/publish.yml` si no existe:
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
name: Publish
|
|
23
|
+
|
|
24
|
+
on:
|
|
25
|
+
push:
|
|
26
|
+
tags:
|
|
27
|
+
- "v*.*.*"
|
|
28
|
+
|
|
29
|
+
permissions:
|
|
30
|
+
contents: read
|
|
31
|
+
id-token: write
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
publish:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checkout
|
|
38
|
+
uses: actions/checkout@v4
|
|
39
|
+
|
|
40
|
+
- name: Setup Node
|
|
41
|
+
uses: actions/setup-node@v4
|
|
42
|
+
with:
|
|
43
|
+
node-version: "22.x"
|
|
44
|
+
registry-url: "https://registry.npmjs.org"
|
|
45
|
+
|
|
46
|
+
- name: Install
|
|
47
|
+
run: npm ci
|
|
48
|
+
|
|
49
|
+
- name: Lint
|
|
50
|
+
run: npm run lint
|
|
51
|
+
|
|
52
|
+
- name: Test
|
|
53
|
+
run: npm run test
|
|
54
|
+
|
|
55
|
+
- name: Build
|
|
56
|
+
run: npm run build
|
|
57
|
+
|
|
58
|
+
- name: Pack dry run
|
|
59
|
+
run: npm pack --dry-run
|
|
60
|
+
|
|
61
|
+
- name: Publish
|
|
62
|
+
run: npm publish --provenance
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Primer release
|
|
66
|
+
|
|
67
|
+
Antes de empujar el tag:
|
|
68
|
+
|
|
69
|
+
1. Confirma que el paquete existe en npm.
|
|
70
|
+
2. Confirma que Trusted Publishing esta configurado para el workflow exacto.
|
|
71
|
+
3. Confirma que `package.json` no necesita `publishConfig.access` especial. Para este paquete no scoped, normalmente no hace falta.
|
|
72
|
+
4. Empuja primero el commit de release y luego el tag `vX.Y.Z`.
|
|
73
|
+
|
|
74
|
+
## Fallback con token
|
|
75
|
+
|
|
76
|
+
Usa `NPM_TOKEN` solo si Trusted Publishing no es viable. Debe ser un automation token guardado como secreto de GitHub Actions. En ese caso:
|
|
77
|
+
|
|
78
|
+
- Mantener `permissions.contents: read`.
|
|
79
|
+
- Eliminar `id-token: write` si no se usa provenance por OIDC.
|
|
80
|
+
- Agregar `NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}` al paso `npm publish`.
|
|
81
|
+
|
|
82
|
+
No guardar tokens en `.npmrc`, `package.json`, logs, scripts ni archivos del repo.
|