create-bestax 3.0.0 β†’ 3.1.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.
Files changed (30) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +2 -0
  3. package/dist/constants.d.ts +3 -0
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/constants.js +21 -0
  6. package/dist/project-creator.d.ts +2 -0
  7. package/dist/project-creator.d.ts.map +1 -1
  8. package/dist/project-creator.js +26 -2
  9. package/dist/prompts.d.ts +1 -0
  10. package/dist/prompts.d.ts.map +1 -1
  11. package/dist/prompts.js +9 -0
  12. package/package.json +3 -2
  13. package/templates/skills/bestax-custom-component/SKILL.md +389 -0
  14. package/templates/skills/bestax-custom-component/references/api.md +77 -0
  15. package/templates/skills/bestax-custom-component/references/patterns.md +133 -0
  16. package/templates/skills/bestax-form/SKILL.md +209 -0
  17. package/templates/skills/bestax-form/references/api.md +102 -0
  18. package/templates/skills/bestax-form/references/patterns.md +210 -0
  19. package/templates/skills/bestax-layout-scaffold/SKILL.md +66 -0
  20. package/templates/skills/bestax-layout-scaffold/examples/app-shell.tsx +80 -0
  21. package/templates/skills/bestax-layout-scaffold/examples/card-grid.tsx +98 -0
  22. package/templates/skills/bestax-layout-scaffold/examples/centered.tsx +56 -0
  23. package/templates/skills/bestax-layout-scaffold/examples/landing.tsx +77 -0
  24. package/templates/skills/bestax-layout-scaffold/references/archetypes.md +183 -0
  25. package/templates/skills/bestax-layout-scaffold/references/layout-components.md +181 -0
  26. package/templates/skills/bestax-theming/SKILL.md +73 -0
  27. package/templates/skills/bestax-theming/examples/dark-mode.tsx +38 -0
  28. package/templates/skills/bestax-theming/examples/theme-config.tsx +58 -0
  29. package/templates/skills/bestax-theming/references/css-variables.md +130 -0
  30. package/templates/skills/bestax-theming/references/themeable-components.md +74 -0
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACtE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGzE,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,IAAI,cAAc,EAChC,iBAAiB,IAAI,iBAAiB,EACtC,iBAAiB,IAAI,iBAAiB,GACvC,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,wBAAsB,cAAc,CAClC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB;AAED,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAGlB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,aAAa,CACjC,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,IAAI,CAAC,CAGf;AAcD,wBAAgB,SAAS,IAAI,OAAO,CAwBnC;AAED,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAE1E;AAED,wBAAgB,MAAM,IAAI,IAAI,CAG7B"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACtE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGzE,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,IAAI,cAAc,EAChC,iBAAiB,IAAI,iBAAiB,EACtC,iBAAiB,IAAI,iBAAiB,GACvC,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,wBAAsB,cAAc,CAClC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB;AAED,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAGlB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,aAAa,CACjC,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,IAAI,CAAC,CAGf;AAcD,wBAAgB,SAAS,IAAI,OAAO,CA0BnC;AAED,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAE1E;AAED,wBAAgB,MAAM,IAAI,IAAI,CAG7B"}
package/dist/cli.js CHANGED
@@ -57,6 +57,8 @@ export function createCLI() {
57
57
  .option('-t, --template <template>', 'template to use (vite, vite-ts)')
58
58
  .option('-b, --bulma <flavor>', 'Bulma CSS flavor (complete, prefixed, no-helpers, no-helpers-prefixed, no-dark-mode)')
59
59
  .option('-i, --icon <library>', 'icon library (none, fontawesome, mdi, ionicons, material-icons, material-symbols)')
60
+ .option('--skills', 'install the bestax AI skills into .claude/skills')
61
+ .option('--no-skills', 'do not install the bestax AI skills')
60
62
  .option('-y, --yes', 'skip prompts and use defaults or provided options')
61
63
  .action((projectDir, options) => {
62
64
  projectCreator.create(projectDir, options);
@@ -20,13 +20,16 @@ export declare const MESSAGES: {
20
20
  readonly PROJECT_CREATED: "βœ” Done! Project created successfully.";
21
21
  readonly NEXT_STEPS: "Next steps:";
22
22
  readonly HAPPY_CODING: "Happy coding! πŸŽ‰";
23
+ readonly SKILLS_ADDED: "βœ” Installed bestax AI skills into .claude/skills/ (+ CLAUDE.md)";
23
24
  };
24
25
  export declare const PROMPTS: {
25
26
  readonly PROJECT_NAME: "Project name:";
26
27
  readonly SELECT_FRAMEWORK: "Select a framework:";
27
28
  readonly SELECT_ICON_LIBRARY: "Would you like to add an icon library?";
28
29
  readonly SELECT_BULMA_FLAVOR: "Which Bulma CSS flavor would you like to use?";
30
+ readonly INSTALL_SKILLS: "Install the bestax AI skills (.claude/skills) for Claude Code and other agents?";
29
31
  };
32
+ export declare const CLAUDE_MD: (projectName: string) => string;
30
33
  export interface IconLibrary {
31
34
  name: string;
32
35
  display: string;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,SAAS,EAAE,QAAQ,EAG/B,CAAC;AAEF,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AACpD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,kBAAkB,QAAsB,CAAC;AAEtD,eAAO,MAAM,QAAQ;;;;;wCAMQ,MAAM;uCAEP,MAAM;sCACP,MAAM;4CAEA,MAAM;;;;CAI7B,CAAC;AAEX,eAAO,MAAM,OAAO;;;;;CAKV,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,cAAc,EAAE,WAAW,EAyCvC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,WAAW,EA0CtC,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,SAAS,EAAE,QAAQ,EAG/B,CAAC;AAEF,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AACpD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,kBAAkB,QAAsB,CAAC;AAEtD,eAAO,MAAM,QAAQ;;;;;wCAMQ,MAAM;uCAEP,MAAM;sCACP,MAAM;4CAEA,MAAM;;;;;CAM7B,CAAC;AAEX,eAAO,MAAM,OAAO;;;;;;CAOV,CAAC;AAIX,eAAO,MAAM,SAAS,GAAI,aAAa,MAAM,KAAG,MAgB/C,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,cAAc,EAAE,WAAW,EAyCvC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,WAAW,EA0CtC,CAAC"}
package/dist/constants.js CHANGED
@@ -18,13 +18,34 @@ export const MESSAGES = {
18
18
  PROJECT_CREATED: 'βœ” Done! Project created successfully.',
19
19
  NEXT_STEPS: 'Next steps:',
20
20
  HAPPY_CODING: 'Happy coding! πŸŽ‰',
21
+ SKILLS_ADDED: 'βœ” Installed bestax AI skills into .claude/skills/ (+ CLAUDE.md)',
21
22
  };
22
23
  export const PROMPTS = {
23
24
  PROJECT_NAME: 'Project name:',
24
25
  SELECT_FRAMEWORK: 'Select a framework:',
25
26
  SELECT_ICON_LIBRARY: 'Would you like to add an icon library?',
26
27
  SELECT_BULMA_FLAVOR: 'Which Bulma CSS flavor would you like to use?',
28
+ INSTALL_SKILLS: 'Install the bestax AI skills (.claude/skills) for Claude Code and other agents?',
27
29
  };
30
+ // Minimal CLAUDE.md scaffolded alongside the skills so an AI agent knows the
31
+ // stack and where the skills live.
32
+ export const CLAUDE_MD = (projectName) => `# ${projectName}
33
+
34
+ This app is built with [\`@allxsmith/bestax-bulma\`](https://bestax.io) β€” React components for
35
+ Bulma 1.x.
36
+
37
+ ## AI skills
38
+
39
+ \`.claude/skills/\` contains Agent Skills that teach Claude how to build with this library. They load
40
+ automatically when the task matches:
41
+
42
+ - **bestax-custom-component** β€” build a new custom component the bestax way.
43
+ - **bestax-form** β€” build forms with the bestax form components (no form library).
44
+ - **bestax-theming** β€” colors, branding, and dark mode via the \`Theme\` component (\`colorMode\`).
45
+ - **bestax-layout-scaffold** β€” scaffold full pages (app shell, landing, centered, card grid).
46
+
47
+ Prefer the library's components and these skills over hand-written Bulma markup or custom CSS.
48
+ `;
28
49
  export const ICON_LIBRARIES = [
29
50
  {
30
51
  name: 'none',
@@ -9,6 +9,7 @@ export interface CLIOptions {
9
9
  template?: string;
10
10
  bulma?: string;
11
11
  icon?: string;
12
+ skills?: boolean;
12
13
  yes?: boolean;
13
14
  }
14
15
  export declare class ProjectCreator {
@@ -18,6 +19,7 @@ export declare class ProjectCreator {
18
19
  checkExistingDirectory(targetPath: string, targetDir: string): Promise<boolean>;
19
20
  getTemplatePath(template: string): string;
20
21
  copyTemplate(template: string, targetPath: string): Promise<void>;
22
+ setupSkills(targetPath: string, projectName: string): Promise<void>;
21
23
  setupBulmaFlavor(targetPath: string, bulmaFlavor: string, template: string): Promise<void>;
22
24
  private getIconName;
23
25
  private getIconProps;
@@ -1 +1 @@
1
- {"version":3,"file":"project-creator.d.ts","sourceRoot":"","sources":["../src/project-creator.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,YAAY,CAAS;gBAEjB,YAAY,CAAC,EAAE,MAAM;IAI3B,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa3D,sBAAsB,CAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAkBnB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAInC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjE,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAmDhB,OAAO,CAAC,WAAW;IA2BnB,OAAO,CAAC,YAAY;IAYd,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IA2IV,mBAAmB,CACvB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAwEV,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAwHvE"}
1
+ {"version":3,"file":"project-creator.d.ts","sourceRoot":"","sources":["../src/project-creator.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,YAAY,CAAS;gBAEjB,YAAY,CAAC,EAAE,MAAM;IAI3B,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa3D,sBAAsB,CAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAkBnB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAInC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjE,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBnE,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAmDhB,OAAO,CAAC,WAAW;IA2BnB,OAAO,CAAC,YAAY;IAYd,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IA2IV,mBAAmB,CACvB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAwEV,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAqIvE"}
@@ -3,10 +3,10 @@ import { fileURLToPath } from 'url';
3
3
  import chalk from 'chalk';
4
4
  import fs from 'fs-extra';
5
5
  import { checkDirectoryExists, isDirectoryEmpty, emptyDirectory, ensureDirectory, copyDirectory, updatePackageJson, } from './file-system.js';
6
- import { promptProjectName, promptOverwriteDirectory, promptTemplate, promptIconLibrary, promptBulmaFlavor, } from './prompts.js';
6
+ import { promptProjectName, promptOverwriteDirectory, promptTemplate, promptIconLibrary, promptBulmaFlavor, promptInstallSkills, } from './prompts.js';
7
7
  import { displayHeader, displaySuccess, displayError, displayCancelled, } from './display.js';
8
8
  import { validateProjectName } from './validators.js';
9
- import { MESSAGES, ICON_LIBRARIES, BULMA_FLAVORS } from './constants.js';
9
+ import { MESSAGES, ICON_LIBRARIES, BULMA_FLAVORS, CLAUDE_MD, } from './constants.js';
10
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
11
  export class ProjectCreator {
12
12
  templatesDir;
@@ -45,6 +45,16 @@ export class ProjectCreator {
45
45
  await ensureDirectory(targetPath);
46
46
  await copyDirectory(templatePath, targetPath);
47
47
  }
48
+ async setupSkills(targetPath, projectName) {
49
+ const skillsSrc = path.join(this.templatesDir, 'skills');
50
+ if (!(await checkDirectoryExists(skillsSrc))) {
51
+ console.log(chalk.yellow(' Skipping skills β€” bundle not found in this build.'));
52
+ return;
53
+ }
54
+ await fs.copy(skillsSrc, path.join(targetPath, '.claude', 'skills'));
55
+ await fs.writeFile(path.join(targetPath, 'CLAUDE.md'), CLAUDE_MD(projectName));
56
+ console.log(chalk.green(MESSAGES.SKILLS_ADDED));
57
+ }
48
58
  async setupBulmaFlavor(targetPath, bulmaFlavor, template) {
49
59
  const flavor = BULMA_FLAVORS.find(f => f.name === bulmaFlavor);
50
60
  if (!flavor) {
@@ -364,6 +374,17 @@ export class ProjectCreator {
364
374
  process.exit(1);
365
375
  }
366
376
  }
377
+ // Install AI skills? (use option -> --yes default -> prompt)
378
+ let installSkills;
379
+ if (options?.skills !== undefined) {
380
+ installSkills = options.skills;
381
+ }
382
+ else if (options?.yes) {
383
+ installSkills = true;
384
+ }
385
+ else {
386
+ installSkills = await promptInstallSkills();
387
+ }
367
388
  // Create project
368
389
  console.log();
369
390
  console.log(chalk.green(MESSAGES.CREATING_PROJECT(targetPath)));
@@ -373,6 +394,9 @@ export class ProjectCreator {
373
394
  await this.setupBulmaFlavor(targetPath, bulmaFlavor, template);
374
395
  await this.setupIconLibrary(targetPath, iconLibrary, template);
375
396
  await this.setupConfigProvider(targetPath, bulmaFlavor, iconLibrary, template);
397
+ if (installSkills) {
398
+ await this.setupSkills(targetPath, projectName);
399
+ }
376
400
  displaySuccess(targetDir);
377
401
  }
378
402
  catch (error) {
package/dist/prompts.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export declare function promptProjectName(): Promise<string | null>;
2
2
  export declare function promptOverwriteDirectory(targetDir: string): Promise<boolean>;
3
+ export declare function promptInstallSkills(): Promise<boolean>;
3
4
  export declare function promptTemplate(): Promise<string | null>;
4
5
  export declare function promptIconLibrary(): Promise<string | null>;
5
6
  export declare function promptBulmaFlavor(): Promise<string | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAWA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAUhE;AAED,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAY7D;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAahE;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAehE"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAWA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAUhE;AAED,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS5D;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAY7D;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAahE;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAehE"}
package/dist/prompts.js CHANGED
@@ -20,6 +20,15 @@ export async function promptOverwriteDirectory(targetDir) {
20
20
  });
21
21
  return response.overwrite === true;
22
22
  }
23
+ export async function promptInstallSkills() {
24
+ const response = await prompts({
25
+ type: 'confirm',
26
+ name: 'skills',
27
+ message: PROMPT_MESSAGES.INSTALL_SKILLS,
28
+ initial: true,
29
+ });
30
+ return response.skills === true;
31
+ }
23
32
  export async function promptTemplate() {
24
33
  const response = await prompts({
25
34
  type: 'select',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bestax",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Create a new bestax-bulma project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,7 +11,8 @@
11
11
  "templates"
12
12
  ],
13
13
  "scripts": {
14
- "build": "tsc",
14
+ "build": "node scripts/sync-skills.mjs && tsc",
15
+ "prepack": "node scripts/sync-skills.mjs",
15
16
  "dev": "tsc --watch",
16
17
  "test": "NODE_OPTIONS=\"--experimental-vm-modules\" jest",
17
18
  "test:watch": "NODE_OPTIONS=\"--experimental-vm-modules\" jest --watch",
@@ -0,0 +1,389 @@
1
+ ---
2
+ name: bestax-custom-component
3
+ description: Build a new custom Bulma "extra" component for @allxsmith/bestax-bulma β€” a React + TypeScript component with Bulma v1 SCSS (the CSS-variable pattern), Storybook stories, tests, and docs. Use when adding a component that goes beyond stock Bulma (like Dialog, Carousel, Switch, Slider, Rate, Taginput), or when extending an existing one to match the library's conventions.
4
+ license: MIT
5
+ ---
6
+
7
+ # Building a custom bestax-bulma component
8
+
9
+ This skill teaches the end-to-end pattern the library uses for its custom "extra"
10
+ components β€” the ones that aren't part of stock Bulma. Follow it whenever you add a new
11
+ component to `@allxsmith/bestax-bulma`, or refactor a component to match house style.
12
+
13
+ ## Use when
14
+
15
+ - Creating a new component beyond stock Bulma (an interactive widget, a composed element).
16
+ - Writing the component's SCSS and you need it to follow the **Bulma v1 CSS-variable pattern**
17
+ (`register-vars` / `getVar`, `--bulma-*` custom properties, the class prefix).
18
+ - Wiring a component into the package exports, the SCSS bundle, Storybook, tests, and docs.
19
+
20
+ For **form** components (Field/Control/Input/etc.) use the `bestax-form` skill instead.
21
+
22
+ ## Check for an existing component first
23
+
24
+ Before building anything, **search the library for a component that already does this β€” or a
25
+ close synonym** β€” and tell the user what you found. Many requests are covered by an existing
26
+ element, or are best built by composing existing ones. Building a near-duplicate (a "label" when
27
+ `Tag` exists, a "banner" when `Notification` exists) fragments the API and is usually the wrong
28
+ call.
29
+
30
+ Where to look:
31
+
32
+ - `bulma-ui/src/index.ts` β€” the full export list; scan it for the name and its synonyms.
33
+ - `docs/docs/api/{elements,components,form}/` β€” one doc page per shipped component.
34
+ - Storybook titles β€” `Elements/*`, `Components/*`, `Form/*`.
35
+
36
+ Then decide, and **surface the decision to the user**:
37
+
38
+ - **Exact / synonym match exists** β†’ recommend using it. Don't build a duplicate. (E.g. a small
39
+ colored label/badge/chip β†’ `Tag` / `Tags` already exist.)
40
+ - **Partial overlap** β†’ prefer **composing or extending** the existing pieces inside your new
41
+ component rather than re-implementing them. (E.g. a "profile card" β†’ there's no `ProfileCard`,
42
+ but `Card`, `Image`, `Title`, `SubTitle`, and `Content` exist; build `ProfileCard` to compose
43
+ them.)
44
+ - **Genuine gap** β†’ build the new component using the pattern below.
45
+
46
+ State plainly which case applies before writing code, e.g. _"`Tag` already covers a colored
47
+ label β€” use that instead"_ or _"No `ProfileCard` exists; I'll build one composing the existing
48
+ `Card`/`Image`/`Title` elements."_
49
+
50
+ ## File layout
51
+
52
+ Every custom component has five files. Mirror the existing names exactly (PascalCase TSX,
53
+ `_kebab.scss` partial):
54
+
55
+ ```
56
+ bulma-ui/src/components/MyComponent.tsx # React + TS component
57
+ bulma-ui/src/components/MyComponent.stories.tsx # Storybook stories
58
+ bulma-ui/src/components/__tests__/MyComponent.test.tsx # Jest + RTL tests
59
+ bulma-ui/src/scss/components/_mycomponent.scss # SCSS partial
60
+ docs/docs/api/components/mycomponent.md # Docusaurus docs page
61
+ ```
62
+
63
+ Then wire two index files (see **Wiring & build**).
64
+
65
+ ## Component template
66
+
67
+ Components use `forwardRef`, accept Bulma helper props via `BulmaClassesProps`, run them
68
+ through `useBulmaClasses`, build their own classes with `usePrefixedClassNames`, and merge
69
+ everything with `classNames`. Spread `rest` (the non-helper props) onto the DOM node.
70
+
71
+ ```tsx
72
+ import React, { forwardRef } from 'react';
73
+ import { classNames, usePrefixedClassNames } from '../helpers/classNames';
74
+ import { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';
75
+
76
+ export type MyComponentColor =
77
+ | 'primary'
78
+ | 'link'
79
+ | 'info'
80
+ | 'success'
81
+ | 'warning'
82
+ | 'danger';
83
+
84
+ /**
85
+ * Props for the MyComponent component.
86
+ *
87
+ * @property {MyComponentColor} [color] - Bulma color modifier.
88
+ * @property {'small' | 'medium' | 'large'} [size] - Size modifier.
89
+ * @property {boolean} [isActive] - Whether the component is active.
90
+ */
91
+ export interface MyComponentProps
92
+ extends
93
+ Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,
94
+ Omit<BulmaClassesProps, 'color'> {
95
+ color?: MyComponentColor;
96
+ size?: 'small' | 'medium' | 'large';
97
+ isActive?: boolean;
98
+ }
99
+
100
+ /**
101
+ * MyComponent β€” short description of what it does.
102
+ *
103
+ * @example
104
+ * <MyComponent color="primary" size="large" isActive>Hello</MyComponent>
105
+ */
106
+ export const MyComponent = forwardRef<HTMLDivElement, MyComponentProps>(
107
+ ({ color, size, isActive, className, children, ...props }, ref) => {
108
+ // 1. Pull Bulma helper classes (m/p, text*, display, etc.) out of props.
109
+ const { bulmaHelperClasses, rest } = useBulmaClasses(props);
110
+
111
+ // 2. Build this component's own classes (respects the Config classPrefix).
112
+ const mainClasses = usePrefixedClassNames('mycomponent', {
113
+ [`is-${color}`]: !!color,
114
+ [`is-${size}`]: !!size,
115
+ 'is-active': !!isActive,
116
+ });
117
+
118
+ // 3. Merge: own classes + helper classes + caller className.
119
+ const combined = classNames(mainClasses, bulmaHelperClasses, className);
120
+
121
+ return (
122
+ <div ref={ref} className={combined} {...rest}>
123
+ {children}
124
+ </div>
125
+ );
126
+ }
127
+ );
128
+
129
+ MyComponent.displayName = 'MyComponent';
130
+
131
+ export default MyComponent;
132
+ ```
133
+
134
+ Rules that keep components consistent:
135
+
136
+ - **Always `Omit<…, 'color'>`** from both `HTMLAttributes` and `BulmaClassesProps` when the
137
+ component exposes its own typed `color`, so the native/helper `color` doesn't collide.
138
+ - **Never hand-build class strings.** Use `usePrefixedClassNames(base, conditionalMap)` so the
139
+ optional `classPrefix` from `Config` is honored, then `classNames(...)` to merge.
140
+ - **Spread `rest`, not `props`**, onto the DOM node β€” `useBulmaClasses` has already stripped the
141
+ helper props out of `rest`, so they don't leak to the DOM as invalid attributes.
142
+ - **Set `displayName`** on `forwardRef` components (needed for tests and Storybook autodocs).
143
+ - **Element sizing uses an inline `'small' | 'medium' | 'large'` union**, mapped to `is-small` /
144
+ `is-medium` / `is-large` (see `Tabs.tsx`, `Control.tsx`). Do **not** reach for the `validSizes`
145
+ constant β€” that one is `'0'…'6' | 'auto'` and exists for **spacing** helpers, not element size.
146
+ - **Format before you lint.** The repo enforces Prettier and ESLint fails on unformatted code.
147
+ Run `npx prettier --write` on your new files (or `npm run format` from the repo root) before
148
+ `npm run lint`. Copy snippets as a starting point, then let Prettier normalize them.
149
+
150
+ See `references/api.md` for the full helper API and `references/patterns.md` for the complete
151
+ Dialog walkthrough.
152
+
153
+ ## SCSS pattern (required)
154
+
155
+ This is the library's house convention β€” **the Bulma v1 CSS-variable pattern**. Do not write
156
+ plain hard-coded CSS or homebrew `--mycomponent-*` variables. Import Bulma's utilities, declare
157
+ SCSS vars with `!default`, register them as `--bulma-*` custom properties on the root selector
158
+ with `cv.register-vars`, then consume them with `cv.getVar`. Prefix every selector with
159
+ `iv.$class-prefix`.
160
+
161
+ ```scss
162
+ // bulma-ui/src/scss/components/_mycomponent.scss
163
+ @use 'bulma/sass/utilities/initial-variables' as iv;
164
+ @use 'bulma/sass/utilities/css-variables' as cv;
165
+
166
+ // 1. SCSS variables, overridable, referencing Bulma vars via cv.getVar.
167
+ $mycomponent-radius: cv.getVar('radius') !default;
168
+ $mycomponent-background: cv.getVar('scheme-main') !default;
169
+ $mycomponent-color: cv.getVar('text') !default;
170
+ $mycomponent-padding: 1rem !default;
171
+
172
+ // 2. Register them as runtime --bulma-* custom properties on the root selector.
173
+ .#{iv.$class-prefix}mycomponent {
174
+ @include cv.register-vars(
175
+ (
176
+ 'mycomponent-radius': #{$mycomponent-radius},
177
+ 'mycomponent-background': #{$mycomponent-background},
178
+ 'mycomponent-color': #{$mycomponent-color},
179
+ 'mycomponent-padding': #{$mycomponent-padding},
180
+ )
181
+ );
182
+ }
183
+
184
+ // 3. Consume via cv.getVar. Prefix every selector with iv.$class-prefix.
185
+ .#{iv.$class-prefix}mycomponent {
186
+ background-color: cv.getVar('mycomponent-background');
187
+ border-radius: cv.getVar('mycomponent-radius');
188
+ color: cv.getVar('mycomponent-color');
189
+ padding: cv.getVar('mycomponent-padding');
190
+ }
191
+
192
+ // Color variants reuse Bulma's registered color vars.
193
+ .#{iv.$class-prefix}mycomponent.#{iv.$class-prefix}is-primary {
194
+ background-color: cv.getVar('primary');
195
+ color: cv.getVar('primary-invert');
196
+ }
197
+
198
+ // Respect reduced-motion if you animate.
199
+ @media (prefers-reduced-motion: reduce) {
200
+ .#{iv.$class-prefix}mycomponent {
201
+ animation: none;
202
+ }
203
+ }
204
+ ```
205
+
206
+ Why this matters: registering vars makes the component themeable at runtime (the docs site and
207
+ `Theme`/`Config` providers override `--bulma-*` properties), and the `iv.$class-prefix` keeps
208
+ the component working when consumers opt into a class prefix to avoid collisions.
209
+
210
+ The canonical reference file is `bulma-ui/src/scss/components/_dialog.scss`.
211
+
212
+ ## Stories
213
+
214
+ `MyComponent.stories.tsx` beside the component. Use `tags: ['autodocs']` so the JSDoc becomes
215
+ the docs page, declare `argTypes`, and write one named `function`-style render per variant.
216
+
217
+ ```tsx
218
+ import type { Meta, StoryObj } from '@storybook/react';
219
+ import { MyComponent } from './MyComponent';
220
+
221
+ const meta: Meta<typeof MyComponent> = {
222
+ title: 'Components/MyComponent',
223
+ component: MyComponent,
224
+ tags: ['autodocs'],
225
+ argTypes: {
226
+ color: {
227
+ control: 'select',
228
+ options: ['primary', 'link', 'info', 'success', 'warning', 'danger'],
229
+ },
230
+ isActive: { control: 'boolean' },
231
+ },
232
+ };
233
+ export default meta;
234
+ type Story = StoryObj<typeof MyComponent>;
235
+
236
+ export const Default: Story = {
237
+ render: function DefaultExample() {
238
+ return <MyComponent>Default</MyComponent>;
239
+ },
240
+ };
241
+
242
+ export const Colors: Story = {
243
+ render: function ColorsExample() {
244
+ return (
245
+ <>
246
+ <MyComponent color="primary">Primary</MyComponent>
247
+ <MyComponent color="danger">Danger</MyComponent>
248
+ </>
249
+ );
250
+ },
251
+ };
252
+ ```
253
+
254
+ ## Tests
255
+
256
+ `__tests__/MyComponent.test.tsx`, Jest + `@testing-library/react`. Cover render, each prop β†’
257
+ class mapping, the helper-prop passthrough, ref forwarding, and any interaction/a11y.
258
+
259
+ ```tsx
260
+ import { render, screen } from '@testing-library/react';
261
+ import { createRef } from 'react';
262
+ import { MyComponent } from '../MyComponent';
263
+
264
+ describe('MyComponent', () => {
265
+ it('renders children', () => {
266
+ render(<MyComponent>Hello</MyComponent>);
267
+ expect(screen.getByText('Hello')).toBeInTheDocument();
268
+ });
269
+
270
+ it('applies the color modifier', () => {
271
+ render(<MyComponent color="primary">x</MyComponent>);
272
+ expect(screen.getByText('x')).toHaveClass('mycomponent', 'is-primary');
273
+ });
274
+
275
+ it('passes Bulma helper props through', () => {
276
+ render(<MyComponent m="3">x</MyComponent>);
277
+ expect(screen.getByText('x')).toHaveClass('m-3');
278
+ });
279
+
280
+ it('forwards the ref', () => {
281
+ const ref = createRef<HTMLDivElement>();
282
+ render(<MyComponent ref={ref}>x</MyComponent>);
283
+ expect(ref.current).toBeInstanceOf(HTMLDivElement);
284
+ });
285
+ });
286
+ ```
287
+
288
+ ## Docs page
289
+
290
+ `docs/docs/api/components/mycomponent.md` β€” Overview, Import, a Props table, and `Usage` with
291
+ live examples. Live code blocks use the ` ```tsx live ` fence (Docusaurus live-codeblock).
292
+
293
+ ````md
294
+ ---
295
+ title: MyComponent
296
+ sidebar_label: MyComponent
297
+ ---
298
+
299
+ # MyComponent
300
+
301
+ ## Overview
302
+
303
+ Short description of the component.
304
+
305
+ ## Import
306
+
307
+ ```tsx
308
+ import { MyComponent } from '@allxsmith/bestax-bulma';
309
+ ```
310
+
311
+ ## Props
312
+
313
+ | Prop | Type | Default | Description |
314
+ | ---------- | ---------------------------- | ------- | --------------------- |
315
+ | `color` | `'primary' \| 'link' \| ...` | β€” | Bulma color modifier. |
316
+ | `isActive` | `boolean` | `false` | Active state. |
317
+
318
+ ## Usage
319
+
320
+ ### Default
321
+
322
+ ```tsx live
323
+ <MyComponent>Hello</MyComponent>
324
+ ```
325
+ ````
326
+
327
+ > Note: the Docusaurus docs load the **built** dist CSS. After SCSS changes, run
328
+ > `cd bulma-ui && npm run build` before the new styles show up in the docs site (Storybook
329
+ > compiles SCSS live and does not need this).
330
+
331
+ ## Wiring & build
332
+
333
+ Two index files must be updated or the component won't ship:
334
+
335
+ 1. **Package export** β€” add to `bulma-ui/src/index.ts`, in the **components** group (the file
336
+ groups exports by directory β€” keep yours next to the other `./components/*` lines):
337
+ ```ts
338
+ export * from './components/MyComponent';
339
+ ```
340
+ 2. **SCSS bundle** β€” add to `bulma-ui/src/scss/components/_index.scss`:
341
+ ```scss
342
+ @use 'mycomponent';
343
+ ```
344
+
345
+ Then build and verify:
346
+
347
+ ```sh
348
+ cd bulma-ui
349
+ npx prettier --write src/components/MyComponent.tsx src/scss/components/_mycomponent.scss
350
+ npm run lint
351
+ npm test
352
+ npm run build # compiles JS + the bestax/extras CSS bundles
353
+ ```
354
+
355
+ ## Visually inspect it in a browser
356
+
357
+ Types and unit tests don't see layout. **Render the component and actually look at it** before
358
+ you call it done β€” spacing, padding, vertical centering, alignment, and every variant/state
359
+ (colors, sizes, hover/active, dark mode). Visual bugs hide from `tsc` and `@testing-library`.
360
+
361
+ 1. Run a surface that renders it: `npm run storybook` (compiles SCSS live) or the docs dev server.
362
+ 2. Open the component and inspect it. If a browser-automation tool (claude-in-chrome, Playwright)
363
+ is available, drive the browser and screenshot each variant; otherwise open it yourself and
364
+ eyeball it.
365
+ 3. Check the usual offenders:
366
+ - **Vertical centering of inline text** β€” `display: inline-block` + `line-height: 1` makes
367
+ text sit low. For chips/labels/buttons use `display: inline-flex; align-items: center;
368
+ justify-content: center;` with a normal `line-height` (Bulma's `Tag` is the reference).
369
+ - Padding/gaps look balanced; nothing clips or overflows.
370
+ - Every color/size variant renders; dark mode is legible.
371
+
372
+ Fix what you see, then re-inspect. A green test suite with a misaligned component is not done.
373
+
374
+ ## Checklist
375
+
376
+ - [ ] **Checked the inventory first** β€” searched `src/index.ts` / docs / Storybook for an existing
377
+ match or synonym, and told the user (reuse/extend it, or confirm there's a genuine gap).
378
+ - [ ] `MyComponent.tsx` β€” `forwardRef`, `Omit<…, 'color'>`, `useBulmaClasses`,
379
+ `usePrefixedClassNames`, `classNames`, spread `rest`, `displayName` set.
380
+ - [ ] `_mycomponent.scss` β€” `@use` Bulma utilities, `$vars !default`, `cv.register-vars`,
381
+ `cv.getVar`, every selector prefixed with `iv.$class-prefix`.
382
+ - [ ] `MyComponent.stories.tsx` β€” `tags: ['autodocs']`, `argTypes`, one story per variant.
383
+ - [ ] `__tests__/MyComponent.test.tsx` — render, prop→class, helper passthrough, ref.
384
+ - [ ] `docs/docs/api/components/mycomponent.md` β€” Overview / Import / Props / `tsx live`.
385
+ - [ ] `src/index.ts` exports the component (in the `./components/*` group).
386
+ - [ ] `scss/components/_index.scss` `@use`s the partial.
387
+ - [ ] Prettier-formatted, then `npm run lint && npm test && npm run build` all pass.
388
+ - [ ] **Rendered and visually inspected in a browser** β€” centering/spacing/variants all look
389
+ right (not just green tests).