create-bestax 4.0.1 → 4.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.
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +20 -1
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +6 -2
- package/dist/file-system.d.ts +1 -1
- package/dist/file-system.d.ts.map +1 -1
- package/dist/file-system.js +11 -1
- package/dist/package-manager.d.ts +5 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/package-manager.js +9 -0
- package/dist/project-creator.d.ts.map +1 -1
- package/dist/project-creator.js +7 -1
- package/package.json +1 -1
- package/templates/skills/bestax-custom-component/SKILL.md +4 -3
- package/templates/skills/bestax-custom-component/references/api.md +3 -2
- package/templates/skills/bestax-custom-component/references/component-catalog.md +2 -2
- package/templates/skills/bestax-form/SKILL.md +57 -22
- package/templates/skills/bestax-form/references/api.md +11 -11
- package/templates/skills/bestax-layout-scaffold/SKILL.md +41 -12
- package/templates/skills/bestax-layout-scaffold/examples/centered.tsx +1 -1
- package/templates/skills/bestax-layout-scaffold/references/layout-components.md +22 -8
- package/templates/skills/bestax-migrate/references/prop-map.md +1 -1
- package/templates/skills/bestax-theming/references/css-variables.md +21 -0
- package/templates/skills/bestax-theming/references/themeable-components.md +47 -41
- package/templates/vite/_gitignore +25 -0
- package/templates/vite-ts/_gitignore +25 -0
- package/templates/vite-ts/tsconfig.json +1 -0
package/dist/constants.d.ts.map
CHANGED
|
@@ -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;;;;;;;wCAaQ,MAAM;uCAEP,MAAM;sCACP,MAAM;4CAEA,MAAM;;;;;CAM7B,CAAC;AASX,eAAO,MAAM,WAAW,QAed,CAAC;AAEX,eAAO,MAAM,OAAO;;;;;;CAOV,CAAC;AAOX,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK9D,CAAC;AAKF,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,SAAS,GACpB,aAAa,MAAM,EACnB,8BAA8B,eAAe,KAC5C,
|
|
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;;;;;;;wCAaQ,MAAM;uCAEP,MAAM;sCACP,MAAM;4CAEA,MAAM;;;;;CAM7B,CAAC;AASX,eAAO,MAAM,WAAW,QAed,CAAC;AAEX,eAAO,MAAM,OAAO;;;;;;CAOV,CAAC;AAOX,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK9D,CAAC;AAKF,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,SAAS,GACpB,aAAa,MAAM,EACnB,8BAA8B,eAAe,KAC5C,MAoIF,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;IAIrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,cAAc,EAAE,WAAW,EA6CvC,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,EA4CtC,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -129,6 +129,7 @@ cases. Before writing \`style\`, translate each declaration with this table:
|
|
|
129
129
|
and \`Tabs.Tab\` has built-in \`icon\`/\`disabled\` props — no nested \`Icon\` needed.
|
|
130
130
|
- Compose existing components before writing custom CSS; theme via \`Theme\` and \`--bulma-*\`
|
|
131
131
|
variables, never hardcoded colors.
|
|
132
|
+
|
|
132
133
|
- \`Navbar.Burger\`/\`Navbar.Menu\` are controlled — wire \`active\` via state on both, and pair
|
|
133
134
|
\`Navbar fixed="top"\` with the \`has-navbar-fixed-top\` class on \`<html>\` (never an inline
|
|
134
135
|
padding offset).
|
|
@@ -144,6 +145,22 @@ cases. Before writing \`style\`, translate each declaration with this table:
|
|
|
144
145
|
(\`pnpm-lock.yaml\` → pnpm, \`package-lock.json\` → npm, \`yarn.lock\` → yarn) — a mismatched
|
|
145
146
|
install fails or forks the lockfile.
|
|
146
147
|
|
|
148
|
+
### Three components Bulma will talk you out of
|
|
149
|
+
|
|
150
|
+
Everything else here gets found because Bulma has no equivalent; these three have a near-miss
|
|
151
|
+
close enough to end the search.
|
|
152
|
+
|
|
153
|
+
- **Confirmation after an action** — \`Toast\`, not \`Notification\`/\`Message\`. Mount
|
|
154
|
+
\`<ToastContainer position="top-right" />\` once at the root, then \`toast.success('Saved')\`.
|
|
155
|
+
- **A confirm or alert** — \`Dialog\`, not \`Modal\`. Mount \`<DialogContainer />\`, then
|
|
156
|
+
\`if (await dialog.confirm({ title, message })) …\`.
|
|
157
|
+
- **A control that reads as text or a link** — \`LinkButton\`
|
|
158
|
+
(\`variant="text" \\| "ghost" \\| "underline"\`), not \`<a href="#">\`, \`<div onClick>\` or
|
|
159
|
+
\`Button color="text"\`.
|
|
160
|
+
|
|
161
|
+
Mounting a container without ever calling \`toast.*\`/\`dialog.*\` does nothing. Both also work
|
|
162
|
+
as controlled components (\`<Toast message … onClose>\`, \`<Dialog isOpen … onConfirm>\`).
|
|
163
|
+
|
|
147
164
|
## AI skills
|
|
148
165
|
|
|
149
166
|
\`.claude/skills/\` contains Agent Skills that teach Claude how to build with this library. They load
|
|
@@ -162,7 +179,9 @@ Read skill \`references/\` files with absolute paths — the shell's cwd is not
|
|
|
162
179
|
|
|
163
180
|
\`.claude/launch.json\` declares this app's dev server for Claude Code's browser preview
|
|
164
181
|
(\`npm run dev\` on port 5173, \`--strictPort\`) — start it from there rather than rediscovering
|
|
165
|
-
the command.
|
|
182
|
+
the command. \`--strictPort\` failing because 5173 is busy means an orphaned dev server from an
|
|
183
|
+
earlier session owns the port — kill the listener (\`lsof -tiTCP:5173 -sTCP:LISTEN | xargs kill\`)
|
|
184
|
+
and relaunch; don't move the app to another port.
|
|
166
185
|
|
|
167
186
|
## Docs
|
|
168
187
|
|
package/dist/display.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CA2BtD;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
|
package/dist/display.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import figures from 'figures';
|
|
3
3
|
import { MESSAGES } from './constants.js';
|
|
4
|
+
import { detectPackageManager } from './package-manager.js';
|
|
4
5
|
export function displayHeader() {
|
|
5
6
|
console.log();
|
|
6
7
|
console.log(chalk.cyan('━'.repeat(50)));
|
|
@@ -14,9 +15,12 @@ export function displaySuccess(targetDir) {
|
|
|
14
15
|
console.log();
|
|
15
16
|
console.log(chalk.bold(MESSAGES.NEXT_STEPS));
|
|
16
17
|
console.log();
|
|
18
|
+
// Mirror the package manager that invoked the CLI — `<pm> install` and
|
|
19
|
+
// `<pm> run dev` are valid for all four supported PMs.
|
|
20
|
+
const pm = detectPackageManager();
|
|
17
21
|
console.log(chalk.cyan(` cd ${targetDir}`));
|
|
18
|
-
console.log(chalk.cyan(
|
|
19
|
-
console.log(chalk.cyan(
|
|
22
|
+
console.log(chalk.cyan(` ${pm} install`));
|
|
23
|
+
console.log(chalk.cyan(` ${pm} run dev`));
|
|
20
24
|
console.log();
|
|
21
25
|
console.log(chalk.gray(' Your app includes a beautiful logo-centric homepage'));
|
|
22
26
|
console.log(chalk.gray(' showcasing Bestax, Vite, and React branding.'));
|
package/dist/file-system.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export declare function checkDirectoryExists(targetPath: string): Promise<boolea
|
|
|
2
2
|
export declare function isDirectoryEmpty(targetPath: string): Promise<boolean>;
|
|
3
3
|
export declare function emptyDirectory(targetPath: string): Promise<void>;
|
|
4
4
|
export declare function ensureDirectory(targetPath: string): Promise<void>;
|
|
5
|
-
export declare function copyDirectory(source: string, destination: string): Promise<void>;
|
|
5
|
+
export declare function copyDirectory(source: string, destination: string, renames?: Record<string, string>): Promise<void>;
|
|
6
6
|
export declare function readJsonFile<T = unknown>(filePath: string): Promise<T>;
|
|
7
7
|
export declare function writeJsonFile(filePath: string, data: unknown, spaces?: number): Promise<void>;
|
|
8
8
|
export declare function updatePackageJson(targetPath: string, projectName: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-system.d.ts","sourceRoot":"","sources":["../src/file-system.ts"],"names":[],"mappings":"AAIA,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAElB;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAM3E;AAED,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"file-system.d.ts","sourceRoot":"","sources":["../src/file-system.ts"],"names":[],"mappings":"AAIA,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAElB;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAM3E;AAED,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAE5E;AAED,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,MAAM,SAAI,GACT,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAQf"}
|
package/dist/file-system.js
CHANGED
|
@@ -17,11 +17,21 @@ export async function emptyDirectory(targetPath) {
|
|
|
17
17
|
export async function ensureDirectory(targetPath) {
|
|
18
18
|
await fs.ensureDir(targetPath);
|
|
19
19
|
}
|
|
20
|
-
export async function copyDirectory(source, destination) {
|
|
20
|
+
export async function copyDirectory(source, destination, renames) {
|
|
21
21
|
if (!(await checkDirectoryExists(source))) {
|
|
22
22
|
throw new Error(MESSAGES.TEMPLATE_NOT_FOUND(source));
|
|
23
23
|
}
|
|
24
24
|
await fs.copy(source, destination);
|
|
25
|
+
if (renames) {
|
|
26
|
+
for (const [from, to] of Object.entries(renames)) {
|
|
27
|
+
const copiedPath = path.join(destination, from);
|
|
28
|
+
if (fs.existsSync(copiedPath)) {
|
|
29
|
+
await fs.move(copiedPath, path.join(destination, to), {
|
|
30
|
+
overwrite: true,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
25
35
|
}
|
|
26
36
|
export async function readJsonFile(filePath) {
|
|
27
37
|
return fs.readJson(filePath);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
2
|
+
/** Detect the package manager that invoked the CLI from npm_config_user_agent
|
|
3
|
+
* (e.g. "pnpm/9.12.0 npm/? node/v22 darwin arm64"). Falls back to npm. */
|
|
4
|
+
export declare function detectPackageManager(userAgent?: string | undefined): PackageManager;
|
|
5
|
+
//# sourceMappingURL=package-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../src/package-manager.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAI7D;2EAC2E;AAC3E,wBAAgB,oBAAoB,CAClC,SAAS,GAAE,MAAM,GAAG,SAA6C,GAChE,cAAc,CAKhB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const KNOWN = ['npm', 'pnpm', 'yarn', 'bun'];
|
|
2
|
+
/** Detect the package manager that invoked the CLI from npm_config_user_agent
|
|
3
|
+
* (e.g. "pnpm/9.12.0 npm/? node/v22 darwin arm64"). Falls back to npm. */
|
|
4
|
+
export function detectPackageManager(userAgent = process.env.npm_config_user_agent) {
|
|
5
|
+
const name = userAgent?.split('/')[0] ?? '';
|
|
6
|
+
return KNOWN.includes(name)
|
|
7
|
+
? name
|
|
8
|
+
: 'npm';
|
|
9
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-creator.d.ts","sourceRoot":"","sources":["../src/project-creator.ts"],"names":[],"mappings":"AA2BA,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"project-creator.d.ts","sourceRoot":"","sources":["../src/project-creator.ts"],"names":[],"mappings":"AA2BA,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAWxB,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,oBAAoB,CACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAgBV,WAAW,CACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,CAAC;IAqBV,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;IAgJV,mBAAmB,CACvB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAmEV,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAyIvE"}
|
package/dist/project-creator.js
CHANGED
|
@@ -8,6 +8,12 @@ import { displayHeader, displaySuccess, displayError, displayCancelled, } from '
|
|
|
8
8
|
import { validateProjectName } from './validators.js';
|
|
9
9
|
import { MESSAGES, ICON_LIBRARIES, BULMA_FLAVORS, CLAUDE_MD, LAUNCH_JSON, CONFIG_PROVIDER_ICON_VALUES, } from './constants.js';
|
|
10
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
// npm strips literal `.gitignore` files from published tarballs, so the
|
|
12
|
+
// templates track `_gitignore` instead and the scaffolder renames it back
|
|
13
|
+
// on copy — otherwise published scaffolds would ship with no .gitignore.
|
|
14
|
+
const TEMPLATE_RENAMES = {
|
|
15
|
+
_gitignore: '.gitignore',
|
|
16
|
+
};
|
|
11
17
|
export class ProjectCreator {
|
|
12
18
|
templatesDir;
|
|
13
19
|
constructor(templatesDir) {
|
|
@@ -43,7 +49,7 @@ export class ProjectCreator {
|
|
|
43
49
|
async copyTemplate(template, targetPath) {
|
|
44
50
|
const templatePath = this.getTemplatePath(template);
|
|
45
51
|
await ensureDirectory(targetPath);
|
|
46
|
-
await copyDirectory(templatePath, targetPath);
|
|
52
|
+
await copyDirectory(templatePath, targetPath, TEMPLATE_RENAMES);
|
|
47
53
|
}
|
|
48
54
|
async updateIndexHtmlTitle(targetPath, projectName) {
|
|
49
55
|
const indexHtmlPath = path.join(targetPath, 'index.html');
|
package/package.json
CHANGED
|
@@ -50,11 +50,12 @@ label — use that instead"_ or _"No `ProfileCard` exists; I'll build one compos
|
|
|
50
50
|
|
|
51
51
|
Build from existing components before writing any CSS: `Box`, `Card`, `Title`, `SubTitle`,
|
|
52
52
|
`Icon`, `Block`, `Content`, `Tag`, plus the shared Bulma helper props (spacing, color,
|
|
53
|
-
typography, flexbox).
|
|
54
|
-
`
|
|
53
|
+
typography, flexbox). Some compound sub-parts are the exception — `Modal.Card`, `Tabs.Tab`,
|
|
54
|
+
`Message.Body` take **no Bulma helper props**, just `className` + HTML attributes
|
|
55
55
|
plus their own few (`Tabs.Tab` requires `index={i}` and has built-in `disabled` and
|
|
56
56
|
`icon`/`iconLibrary`/`iconVariant`/`iconSize`/`iconFeatures` — don't nest an `<Icon>` there) —
|
|
57
|
-
so put helper props on the parent or on an element inside them, never invent them there.
|
|
57
|
+
so put helper props on the parent or on an element inside them, never invent them there.
|
|
58
|
+
(`Card.*` sub-parts do take helper props, like `Table.*`/`Menu.*`/`Hero.*`.) Most "custom components" are a composition function — zero new styles.
|
|
58
59
|
See `examples/stat-card.tsx` for a complete worked example.
|
|
59
60
|
|
|
60
61
|
## The component spine
|
|
@@ -31,9 +31,10 @@ that can also be used on their own:
|
|
|
31
31
|
|
|
32
32
|
Because the component destructures these into `bulmaHelperClasses`, callers get the full Bulma
|
|
33
33
|
helper surface for free on every component built this way, and `rest` stays clean for DOM
|
|
34
|
-
spreading. (
|
|
34
|
+
spreading. (Some library compound sub-parts — `Modal.Card`, `Tabs.Tab`,
|
|
35
35
|
`Message.Body` — do **not** take helper props: just `className`, HTML attributes, and their own
|
|
36
|
-
few, e.g. `Tabs.Tab`'s required `index` and its built-in `icon`/`disabled` props.
|
|
36
|
+
few, e.g. `Tabs.Tab`'s required `index` and its built-in `icon`/`disabled` props. `Card.*`
|
|
37
|
+
sub-parts do take them.)
|
|
37
38
|
|
|
38
39
|
## `classNames(...)` and friends — `helpers/classNames.ts`
|
|
39
40
|
|
|
@@ -24,8 +24,8 @@ instead of hand-writing markup.
|
|
|
24
24
|
- **Compound components** expose sub-parts via dot access (e.g. `Card.Header`,
|
|
25
25
|
`Navbar.Item`, `Tabs.Tab`, `Hero.Body`, `Columns.Column`, `Table.Tr`); see the
|
|
26
26
|
component's linked page for the full set. Sub-parts do **not** all take helper
|
|
27
|
-
props: the `Table.*`, `Menu.*`, and `Hero.*` families do (most
|
|
28
|
-
too), but `
|
|
27
|
+
props: the `Card.*`, `Table.*`, `Menu.*`, and `Hero.*` families do (most
|
|
28
|
+
`Navbar.*` too), but `Modal.*`, `Tabs.*`, and `Message.*` sub-parts take none —
|
|
29
29
|
just `className`, HTML attributes, and their own few (`Tabs.Tab` requires
|
|
30
30
|
`index` and has built-in `icon`/`disabled` props). Put helper props on the
|
|
31
31
|
parent or on an element inside (`Span`, `Paragraph`, …) instead.
|
|
@@ -96,32 +96,47 @@ All import from `@allxsmith/bestax-bulma`. Convenience components auto-wrap Fiel
|
|
|
96
96
|
| `Taginput` | Tag/chip input; suggestions, confirm keys, closable tags. |
|
|
97
97
|
| `DateInput` / `TimeInput` / `DateTimeInput` (+ `*Base`) | Date / time / datetime pickers. |
|
|
98
98
|
|
|
99
|
+
(`NumberInput` and `TagInput` also exist as deprecated aliases of `Numberinput`/`Taginput` —
|
|
100
|
+
same components; prefer the lowercase-second-word spellings.)
|
|
101
|
+
|
|
99
102
|
## Common props
|
|
100
103
|
|
|
101
104
|
Across the convenience inputs (`Input`, `Select`, `TextArea`, and similar):
|
|
102
105
|
|
|
103
|
-
| Prop | Type | Purpose
|
|
104
|
-
| -------------------------------- | --------------------------------------------------------------------- |
|
|
105
|
-
| `color` | `'primary' \| 'link' \| 'info' \| 'success' \| 'warning' \| 'danger'` | Visual state — use `'danger'` for errors, `'success'` for valid.
|
|
106
|
-
| `size` | `'small' \| 'medium' \| 'large'` | Input size.
|
|
107
|
-
| `value` / `onChange` | controlled value + handler | Standard React controlled inputs.
|
|
108
|
-
| `defaultValue` | uncontrolled initial value | When not controlling state.
|
|
109
|
-
| `disabled`, `readOnly` | `boolean` | Native states (`readOnly` on `*Base`).
|
|
110
|
-
| `label` | `ReactNode` | Field label (convenience components).
|
|
111
|
-
| `message` | `ReactNode` | Help / validation text rendered as `<p class="help">`.
|
|
112
|
-
| `messageColor` | a Bulma color | Colors the help text (`'danger'` for errors).
|
|
113
|
-
| `iconLeftName` / `iconRightName` | `string` | Icon shortcuts; pair with `hasIconsLeft/Right`.
|
|
114
|
-
| `isLoading` | `boolean` | Loading indicator on the Control.
|
|
106
|
+
| Prop | Type | Purpose |
|
|
107
|
+
| -------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
108
|
+
| `color` | `'primary' \| 'link' \| 'info' \| 'success' \| 'warning' \| 'danger'` | Visual state — use `'danger'` for errors, `'success'` for valid. |
|
|
109
|
+
| `size` | `'small' \| 'medium' \| 'large'` | Input size. |
|
|
110
|
+
| `value` / `onChange` | controlled value + handler | Standard React controlled inputs. |
|
|
111
|
+
| `defaultValue` | uncontrolled initial value | When not controlling state. |
|
|
112
|
+
| `disabled`, `readOnly` | `boolean` | Native states (`readOnly` on `*Base`). |
|
|
113
|
+
| `label` | `ReactNode` | Field label (convenience components; auto-associated via `htmlFor`). |
|
|
114
|
+
| `message` | `ReactNode` | Help / validation text rendered as `<p class="help">`. |
|
|
115
|
+
| `messageColor` | a Bulma color | Colors the help text (`'danger'` for errors). |
|
|
116
|
+
| `iconLeftName` / `iconRightName` | `string` | Icon shortcuts; pair with `hasIconsLeft/Right`. |
|
|
117
|
+
| `isLoading` | `boolean` | Loading indicator on the Control. |
|
|
115
118
|
|
|
116
119
|
Plus the full Bulma **helper props** (`m`, `p`, `textColor`, `display`, …) on every component
|
|
117
120
|
via `useBulmaClasses`.
|
|
118
121
|
|
|
119
|
-
|
|
120
|
-
`
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
convenience
|
|
122
|
+
Full-width is `isFullwidth` on every component that supports it (`Button`, `LinkButton`,
|
|
123
|
+
`Select`, `File`, `Table`, `Tabs`, `Sidebar`) — always write `isFullwidth`. The deprecated
|
|
124
|
+
spellings compile only where they historically existed: `isFullWidth` everywhere except
|
|
125
|
+
`Sidebar`, `fullwidth` on `Tabs` only, `fullWidth` on `Sidebar` only.
|
|
126
|
+
|
|
127
|
+
The `label` prop on the single-control convenience inputs (`Input`, `Select`, `TextArea`,
|
|
128
|
+
`File`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`,
|
|
129
|
+
`Taginput`) wires `htmlFor`/`id` automatically — your `id` is used when provided, a
|
|
130
|
+
generated one otherwise, and an explicit `labelProps={{ htmlFor }}` wins. The wiring only
|
|
131
|
+
happens when the component renders its own `Field` (nested inside one, the `label` prop is
|
|
132
|
+
dropped); the date/time pickers skip it in `inline` mode and `Taginput` skips it at
|
|
133
|
+
`maxTags` (no visible input to label). The group inputs (`Checkboxes`, `Radios`, `Rate`)
|
|
134
|
+
associate their `label` too, but group-style: the wrapper gets `role="group"`/`"radiogroup"`
|
|
135
|
+
and `aria-labelledby` pointing at the label. Composing `Field` + bases yourself also
|
|
136
|
+
associates: `Field`'s own `label` wires to a single composed `InputBase`/`SelectBase`/
|
|
137
|
+
`TextAreaBase` (skipped for `grouped`/`hasAddons`). Pass `labelProps={{ htmlFor }}` plus a
|
|
138
|
+
matching `id` only when you want a stable id, or `labelProps={{ htmlFor: undefined }}` to
|
|
139
|
+
opt out — e.g. when the labeled `Field` wraps something that is not one of those bases.
|
|
125
140
|
|
|
126
141
|
## Convenience vs composed
|
|
127
142
|
|
|
@@ -168,8 +183,6 @@ function SignupForm() {
|
|
|
168
183
|
message={error}
|
|
169
184
|
messageColor={error ? 'danger' : undefined}
|
|
170
185
|
iconLeftName="envelope"
|
|
171
|
-
id="signup-email"
|
|
172
|
-
labelProps={{ htmlFor: 'signup-email' }}
|
|
173
186
|
/>
|
|
174
187
|
<Button color="primary" type="submit" mt="3">
|
|
175
188
|
Sign up
|
|
@@ -199,6 +212,23 @@ inventory above). **Compose these; don't hand-roll raw `<input class="input">` m
|
|
|
199
212
|
reinvent a control.** If you think a control is missing, check `bulma-ui/src/index.ts` and
|
|
200
213
|
`docs/docs/api/form/` first — it's probably already there under a different name.
|
|
201
214
|
|
|
215
|
+
## What happens after submit
|
|
216
|
+
|
|
217
|
+
A form is not finished at the last field. The two components that carry the result are easy to
|
|
218
|
+
miss because Bulma has something that looks close:
|
|
219
|
+
|
|
220
|
+
- **Confirmation** — `Toast`, not `Notification`/`Message`. Mount
|
|
221
|
+
`<ToastContainer position="top-right" />` once at the app root, then call
|
|
222
|
+
`toast.success('Demo booked')` from the submit handler (`.danger` for a failed submit). It
|
|
223
|
+
self-dismisses; a `Notification` is a static element you place and tear down yourself.
|
|
224
|
+
- **"Are you sure?"** — `Dialog`, not `Modal`. Mount `<DialogContainer />` at the root, then
|
|
225
|
+
`if (await dialog.confirm({ title: 'Delete this key?', message: '…', type: 'danger' })) …`.
|
|
226
|
+
It resolves to a boolean, so a destructive action stays one `if` rather than a state machine.
|
|
227
|
+
`Modal` is an empty shell — with it you rebuild the title, message and button row by hand.
|
|
228
|
+
|
|
229
|
+
Both also work as plain controlled components (`<Toast message … onClose>`,
|
|
230
|
+
`<Dialog isOpen … onConfirm onCancel>`) when the state should live in your component.
|
|
231
|
+
|
|
202
232
|
## Visually inspect it in a browser
|
|
203
233
|
|
|
204
234
|
Forms have layout, spacing, and _stateful_ behavior that types and unit tests don't cover.
|
|
@@ -213,12 +243,17 @@ for the expected classes/states, and say plainly that the visual pass is still o
|
|
|
213
243
|
## Checklist
|
|
214
244
|
|
|
215
245
|
- [ ] Built from the shipped form components (no hand-rolled inputs / reinvented controls).
|
|
216
|
-
- [ ] Every label is programmatically associated
|
|
217
|
-
`
|
|
246
|
+
- [ ] Every label is programmatically associated — the convenience `label` prop, the group
|
|
247
|
+
inputs, and `Field` + single-base composition all do this automatically; pass
|
|
248
|
+
`labelProps={{ htmlFor }}` plus a matching `id` only for a stable id, and label a
|
|
249
|
+
multi-control `Field`'s controls individually (`aria-label`, `aria-labelledby`, or
|
|
250
|
+
a `<label htmlFor>` matching each control's `id`).
|
|
218
251
|
- [ ] Controlled inputs have both `value` and `onChange` (or use `defaultValue` uncontrolled).
|
|
219
252
|
- [ ] Error state shows via `color="danger"` + `message` + `messageColor="danger"`.
|
|
220
253
|
- [ ] Grouped/addon layouts use explicit `Field` + `Control` composition.
|
|
221
254
|
- [ ] No assumption of a built-in validation/form library — state is owned by the app.
|
|
255
|
+
- [ ] Submit feedback is a `Toast` and any "are you sure?" is a `Dialog` — not a hand-placed
|
|
256
|
+
`Notification` or a `Modal` you filled in yourself.
|
|
222
257
|
- [ ] **Rendered and visually inspected in a browser** — layout and the error/validation states
|
|
223
258
|
look right, not just green tests. No browser available? The `renderToString` fallback above
|
|
224
259
|
counts only if you grepped the emitted classes/states **and** said the visual pass is owed.
|
|
@@ -8,16 +8,16 @@ via `useBulmaClasses`.
|
|
|
8
8
|
|
|
9
9
|
Container and layout. Compound parts: `Field.Label`, `Field.Body`.
|
|
10
10
|
|
|
11
|
-
| Prop | Type | Notes
|
|
12
|
-
| ----------------------- | ------------------------------------------------- |
|
|
13
|
-
| `horizontal` | `boolean` | Label + control side by side. Auto-wraps children in `Field.Body`.
|
|
14
|
-
| `grouped` | `boolean \| 'centered' \| 'right' \| 'multiline'` | Controls in a row.
|
|
15
|
-
| `hasAddons` | `boolean \| 'centered' \| 'right'` | Attached controls.
|
|
16
|
-
| `narrow` | `boolean` | Constrain to content width (inside horizontal bodies).
|
|
17
|
-
| `label` | `ReactNode` | Convenience label.
|
|
18
|
-
| `labelSize` | `'small' \| 'normal' \| 'medium' \| 'large'` | Label size.
|
|
19
|
-
| `labelProps` | label attributes | Props for the `<label
|
|
20
|
-
| `textColor` / `bgColor` | Bulma color | Helper colors for the field.
|
|
11
|
+
| Prop | Type | Notes |
|
|
12
|
+
| ----------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
13
|
+
| `horizontal` | `boolean` | Label + control side by side. Auto-wraps children in `Field.Body`. |
|
|
14
|
+
| `grouped` | `boolean \| 'centered' \| 'right' \| 'multiline'` | Controls in a row. |
|
|
15
|
+
| `hasAddons` | `boolean \| 'centered' \| 'right'` | Attached controls. |
|
|
16
|
+
| `narrow` | `boolean` | Constrain to content width (inside horizontal bodies). |
|
|
17
|
+
| `label` | `ReactNode` | Convenience label; auto-associates with a single composed `InputBase`/`SelectBase`/`TextAreaBase` (skipped for `grouped`/`hasAddons`). |
|
|
18
|
+
| `labelSize` | `'small' \| 'normal' \| 'medium' \| 'large'` | Label size. |
|
|
19
|
+
| `labelProps` | label attributes | Props for the `<label>`. An explicit `htmlFor` (even `undefined`) takes over the association; otherwise it is set automatically. |
|
|
20
|
+
| `textColor` / `bgColor` | Bulma color | Helper colors for the field. |
|
|
21
21
|
|
|
22
22
|
## Control — `form/Control.tsx`
|
|
23
23
|
|
|
@@ -59,7 +59,7 @@ Wraps a single input; adds icons and loading.
|
|
|
59
59
|
## Select / SelectBase, TextArea / TextAreaBase
|
|
60
60
|
|
|
61
61
|
Same convenience/raw split as Input. `Select` supports `isLoading` (on the control), `color`,
|
|
62
|
-
`size`, `isRounded`, `isFullwidth
|
|
62
|
+
`size`, `isRounded`, `isFullwidth`, `multiple` +
|
|
63
63
|
`multipleSize`, plus the Field/Control/message props. `TextArea` adds `rows` and
|
|
64
64
|
`hasFixedSize`.
|
|
65
65
|
|
|
@@ -70,11 +70,12 @@ Centered; a collection of items → Card grid. For mixed requests, pick the domi
|
|
|
70
70
|
`textWeight`, `textSize` directly (their `color` prop colors the cell; for muted cell text
|
|
71
71
|
wrap content in `Span textColor="grey"`). Set the app-wide icon library once with
|
|
72
72
|
`<ConfigProvider iconLibrary="…">` at the root rather than `library` on every `<Icon>`.
|
|
73
|
-
- **Decorative CSS is budgeted:
|
|
73
|
+
- **Decorative CSS is budgeted: three compact rules, ≤13 lines per app — comments count:
|
|
74
74
|
at most one short inline note, never a file-header comment block — every value derived
|
|
75
|
-
from `--bulma-*`.** A marketing page gets at most one hero wash
|
|
76
|
-
band, applied via `className` — no resets (Bulma ships one;
|
|
77
|
-
zero) and no grid textures, masks, or multi-layer backdrops;
|
|
75
|
+
from `--bulma-*`.** A marketing page gets at most one hero wash, one alternating section
|
|
76
|
+
band, and one featured-card ring, applied via `className` — no resets (Bulma ships one;
|
|
77
|
+
body/list margins are already zero) and no grid textures, masks, or multi-layer backdrops;
|
|
78
|
+
the components carry the design:
|
|
78
79
|
|
|
79
80
|
```css
|
|
80
81
|
.hero-wash {
|
|
@@ -87,14 +88,19 @@ Centered; a collection of items → Card grid. For mixed requests, pick the domi
|
|
|
87
88
|
.section-alt {
|
|
88
89
|
background: var(--bulma-scheme-main-bis); /* next band: -ter */
|
|
89
90
|
}
|
|
91
|
+
.featured-ring {
|
|
92
|
+
--bulma-shadow: 0 0 0 2px var(--bulma-primary);
|
|
93
|
+
}
|
|
90
94
|
```
|
|
91
95
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
`--bulma-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
The ring works by overriding the **upstream token**, not the component's own var: `.card`
|
|
97
|
+
and `.box` re-declare `--bulma-card-shadow`/`--bulma-box-shadow` from `--bulma-shadow` on
|
|
98
|
+
their own selector, so setting _those_ from an ancestor never wins (same for
|
|
99
|
+
`--bulma-box-radius`; `--bulma-card-radius` is a literal with no ancestor route at all).
|
|
100
|
+
It has to be a CSS rule rather than `<Theme bulmaVars={{ '--bulma-shadow': … }}>`, because
|
|
101
|
+
`bulmaVars` is a closed typed record and `--bulma-shadow` is not one of its keys — that
|
|
102
|
+
exact call **does not compile**, and it was the single most repeated invention across this
|
|
103
|
+
library's cold-start evals. Either way the subtree stays theme- and dark-mode-aware.
|
|
98
104
|
|
|
99
105
|
- **CTAs on a colored hero must stay legible in both schemes.** On a fixed-color surface
|
|
100
106
|
(`Hero color="primary"`, a dark banner), use **filled** buttons — `color="light"` or
|
|
@@ -104,6 +110,26 @@ Centered; a collection of items → Card grid. For mixed requests, pick the domi
|
|
|
104
110
|
`<Theme isRoot colorMode="light">` — so a visitor's OS dark mode can't flip Bulma's text
|
|
105
111
|
colors out from under the fixed palette (details: the `bestax-theming` skill's contrast rules).
|
|
106
112
|
|
|
113
|
+
## Three components core Bulma will talk you out of
|
|
114
|
+
|
|
115
|
+
Most of this library's additions get found on their own, because nothing in Bulma does the
|
|
116
|
+
job. These three do not: each has a Bulma near-miss close enough to stop the search. Across
|
|
117
|
+
44 cold-start builds, `Dialog` was used **zero** times and `LinkButton` in two thirds — and
|
|
118
|
+
every miss shipped the "not this" column instead.
|
|
119
|
+
|
|
120
|
+
| You need | Use | Not this |
|
|
121
|
+
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
122
|
+
| A brief confirmation after an action, self-dismissing | `Toast` — mount `<ToastContainer position="top-right" />` once at the app root, then `toast.success('Saved')` (also `.danger`/`.warning`/`.info`) from anywhere | `Notification`/`Message` — static page elements you have to place, position and dismiss yourself |
|
|
123
|
+
| A confirm or alert the user must answer before anything | `Dialog` — mount `<DialogContainer />` at the root, then `if (await dialog.confirm({ title, message })) …` | `Modal` — an empty shell; the title, message, button row and confirm/cancel wiring are all yours to rebuild |
|
|
124
|
+
| A control that reads as text or a link but _does_ something | `LinkButton` (`variant="text" \| "ghost" \| "underline"`, optional `color`) | `<a href="#">`/`<div onClick>` (no keyboard or screen-reader support) or `Button color="text"` (still button-shaped) |
|
|
125
|
+
|
|
126
|
+
Mounting a container without ever calling `toast.*`/`dialog.*` is not usage — the container is
|
|
127
|
+
the mount point, the imperative call is the thing that shows something. Both also work as
|
|
128
|
+
ordinary controlled components when you would rather hold the state yourself —
|
|
129
|
+
`<Toast message … duration onClose>`, `<Dialog isOpen title message type onConfirm onCancel>` —
|
|
130
|
+
but in an app with more than one call site the root container plus the imperative helper is
|
|
131
|
+
less wiring, not more.
|
|
132
|
+
|
|
107
133
|
## Inline style → helper prop mapping
|
|
108
134
|
|
|
109
135
|
Look up the declaration you were about to inline. The spacing, typography, and flex helpers
|
|
@@ -157,11 +183,14 @@ inline `style`.
|
|
|
157
183
|
- [ ] Wire `active` state to **both** `Navbar.Burger` and `Navbar.Menu` (they are controlled).
|
|
158
184
|
- [ ] For a fixed navbar, add `has-navbar-fixed-top` to `<html>`.
|
|
159
185
|
- [ ] Do not use `Tile` — it is not shipped.
|
|
186
|
+
- [ ] Action feedback goes through `Toast`, a confirmation through `Dialog`, a text-styled
|
|
187
|
+
action through `LinkButton` — not `Notification`, `Modal` or a bare `<a>`.
|
|
160
188
|
- [ ] Style with helper props, not inline `style` — translate via the mapping table; values
|
|
161
189
|
with no helper get a named class in the stylesheet, never `style={{}}`. No raw Bulma
|
|
162
190
|
`className`s either (`Span`/`Paragraph` wrap bare text; `Th`/`Td` take `textAlign`/`textWeight`).
|
|
163
|
-
- [ ] Decorative CSS ≤
|
|
164
|
-
|
|
191
|
+
- [ ] Decorative CSS ≤13 lines total incl. comments — no file-header comment (hero wash +
|
|
192
|
+
section band + featured-card ring), `--bulma-*`-derived; no resets — Bulma ships one.
|
|
193
|
+
The ring sets `--bulma-shadow` in a CSS rule; `Theme bulmaVars` has no such key.
|
|
165
194
|
- [ ] Set the icon library once via `<ConfigProvider iconLibrary="…">` at the root.
|
|
166
195
|
- [ ] Site built? ~800 KB raw / ~82 KB gzip CSS is the expected default-flavor size — to shrink
|
|
167
196
|
it, run the `bestax-optimize` skill (measure first).
|
|
@@ -58,11 +58,11 @@ Every component also accepts the shared Bulma helper props (`m`/`p` spacing, `te
|
|
|
58
58
|
|
|
59
59
|
`<Hero>` is a full-width banner. Subcomponents: `Hero.Head`, `Hero.Body`, `Hero.Foot`.
|
|
60
60
|
|
|
61
|
-
| Prop | Type
|
|
62
|
-
| ---------------------- |
|
|
63
|
-
| `color` |
|
|
64
|
-
| `size` | `'small' \| 'medium' \| 'large' \| 'fullheight' \| 'fullheight-with-navbar'`
|
|
65
|
-
| `fullheightWithNavbar` | `boolean`
|
|
61
|
+
| Prop | Type |
|
|
62
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `color` | `primary \| link \| info \| success \| warning \| danger \| black \| white \| light \| dark` (CSS-backed). Also accepted but deprecated, no CSS, dev-warn: `black-bis`, `black-ter`, the greys, `inherit`, `current` |
|
|
64
|
+
| `size` | `'small' \| 'medium' \| 'large' \| 'fullheight' \| 'fullheight-with-navbar'` |
|
|
65
|
+
| `fullheightWithNavbar` | `boolean` |
|
|
66
66
|
|
|
67
67
|
```tsx
|
|
68
68
|
<Hero color="primary" size="medium">
|
|
@@ -118,6 +118,18 @@ The responsive grid. `Columns` is the row; `Column` is a cell (also reachable as
|
|
|
118
118
|
```ts
|
|
119
119
|
type BulmaColumnSize =
|
|
120
120
|
| number // 1–12
|
|
121
|
+
| '1'
|
|
122
|
+
| '2'
|
|
123
|
+
| '3'
|
|
124
|
+
| '4'
|
|
125
|
+
| '5'
|
|
126
|
+
| '6'
|
|
127
|
+
| '7'
|
|
128
|
+
| '8'
|
|
129
|
+
| '9'
|
|
130
|
+
| '10'
|
|
131
|
+
| '11'
|
|
132
|
+
| '12' // string form, equivalent
|
|
121
133
|
| 'full'
|
|
122
134
|
| 'half'
|
|
123
135
|
| 'one-third'
|
|
@@ -130,8 +142,8 @@ type BulmaColumnSize =
|
|
|
130
142
|
| 'four-fifths';
|
|
131
143
|
```
|
|
132
144
|
|
|
133
|
-
Numeric sizes
|
|
134
|
-
|
|
145
|
+
Numeric sizes accept a number **or** its string form — `sizeDesktop={7}` and
|
|
146
|
+
`sizeDesktop="7"` are equivalent, and the fraction names are strings.
|
|
135
147
|
|
|
136
148
|
> Columns **stack on mobile** by default and go side-by-side at the tablet breakpoint and up.
|
|
137
149
|
> Use the per-breakpoint `size*` props to control how many cells share a row at each width.
|
|
@@ -157,7 +169,9 @@ the column's auto height). Make the `Column` a flex container and let the card g
|
|
|
157
169
|
```
|
|
158
170
|
|
|
159
171
|
`display`, `flexDirection`, and `flexGrow` are helper props every component accepts;
|
|
160
|
-
`flexGrow` takes a string (`"1"`).
|
|
172
|
+
`flexGrow` takes a string (`"1"`). `Card.*` sub-parts accept helper props too, so pinning a
|
|
173
|
+
footer inside a card is `<Card display="flex" flexDirection="column">` +
|
|
174
|
+
`<Card.Content flexGrow="1">` — no `Box` swap needed.
|
|
161
175
|
|
|
162
176
|
## Grid / Cell
|
|
163
177
|
|
|
@@ -32,7 +32,7 @@ this automatically for literal values; dynamic values get TODOs.
|
|
|
32
32
|
## Boolean modifier convention
|
|
33
33
|
|
|
34
34
|
RBC uses bare booleans (`loading`, `outlined`, `rounded`, `fullwidth`); bestax prefixes
|
|
35
|
-
with `is`/`has` (`isLoading`, `isOutlined`, `isRounded`, `
|
|
35
|
+
with `is`/`has` (`isLoading`, `isOutlined`, `isRounded`, `isFullwidth`). Per-component
|
|
36
36
|
tables live in [component-map.md](component-map.md).
|
|
37
37
|
|
|
38
38
|
## Responsive breakpoint objects → flat per-viewport props
|
|
@@ -100,6 +100,27 @@ and numeric shades `--bulma-<c>-00` … `--bulma-<c>-95`.
|
|
|
100
100
|
| `--bulma-size-small` / `-normal` / `-medium` / `-large` | 0.75 / 1 / 1.25 / 1.5rem | via `bulmaVars` |
|
|
101
101
|
| `--bulma-weight-light/normal/medium/semibold/bold/extrabold` | 300 / 400 / 500 / 600 / 700 / 800 | via `bulmaVars` |
|
|
102
102
|
|
|
103
|
+
## Shadow — the one token `bulmaVars` cannot set
|
|
104
|
+
|
|
105
|
+
`--bulma-shadow` is a real Bulma variable (`.box` and `.card` both derive
|
|
106
|
+
`--bulma-box-shadow`/`--bulma-card-shadow` from it), but it is **not a key of `bulmaVars`** —
|
|
107
|
+
that record is a closed union built from an explicit list, and shadow was left out. Writing
|
|
108
|
+
`<Theme bulmaVars={{ '--bulma-shadow': … }}>` is a compile error, and it is the single most
|
|
109
|
+
repeated invention in this library's cold-start evals: every run on every guidance channel
|
|
110
|
+
tried it.
|
|
111
|
+
|
|
112
|
+
Set it in CSS instead, then apply the class to the one element that needs it:
|
|
113
|
+
|
|
114
|
+
```css
|
|
115
|
+
.featured-ring {
|
|
116
|
+
--bulma-shadow: 0 0 0 2px var(--bulma-primary);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Do **not** reach for `--bulma-box-shadow`/`--bulma-card-shadow` from an ancestor instead —
|
|
121
|
+
those are re-declared on `.box`/`.card` themselves, so an inherited value always loses (the
|
|
122
|
+
same rule as the extras section below).
|
|
123
|
+
|
|
103
124
|
## Extras component variables
|
|
104
125
|
|
|
105
126
|
Every "Beyond Bulma" extra registers its own `--bulma-<component>-*` variables. They are
|
|
@@ -10,9 +10,14 @@ This is the self-contained inventory of the color/size/variant props that matter
|
|
|
10
10
|
values are component-specific (see the table). Example: `<Button color="primary">` → `is-primary`.
|
|
11
11
|
⚠️ Some unions are **typed wider than the CSS Bulma ships** — the class is emitted but no rule
|
|
12
12
|
matches. No component ships `is-grey*`/`is-*-bis`/`is-*-ter` rules at all: those `validColors`
|
|
13
|
-
members typecheck on `Progress`/`Notification`/`Hero` but style nothing
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
members still typecheck on `Progress`/`Notification`/`Hero` but style nothing. They are
|
|
14
|
+
**deprecated**: passing one logs a console warning in development, and they will be removed
|
|
15
|
+
from those unions in the next major (the `has-text-*`/`has-background-*` **helpers** do cover
|
|
16
|
+
all 17). On the `Hero` root, `inherit` and `current` are equally CSS-less and deprecated
|
|
17
|
+
(its `Head`/`Body`/`Foot` sub-components keep them, as text helpers). `Pagination` and
|
|
18
|
+
`Tabs` ship no color CSS for **any** value — their entire `color`
|
|
19
|
+
prop is deprecated. Before relying on an unusual value, grep the shipped CSS:
|
|
20
|
+
`node_modules/@allxsmith/bestax-bulma/dist/bestax.css` for e.g. `.progress.is-grey`.
|
|
16
21
|
2. **Helper color props** (on most components, applied as utility classes):
|
|
17
22
|
- `color` / `textColor` → `has-text-<color>` (text color)
|
|
18
23
|
- `backgroundColor` / `bgColor` → `has-background-<color>` (background)
|
|
@@ -21,7 +26,8 @@ This is the self-contained inventory of the color/size/variant props that matter
|
|
|
21
26
|
Components with a real `is-<color>` modifier (`Button`, `Hero`) drop the `color` helper and
|
|
22
27
|
re-expose it as **`textColor`** / **`bgColor`**. `Box`/`Card`/`Section` ship no `is-<color>`
|
|
23
28
|
rule — their `color` _is_ the text helper (`has-text-<color>`; narrowed to the 6 on
|
|
24
|
-
`Box`/`Card`), so `color` and `textColor` are the same lever there
|
|
29
|
+
`Box`/`Card`), so `color` and `textColor` are the same lever there (prefer `textColor`; it
|
|
30
|
+
takes precedence when both are set). `Tag` and `Td`/`Th` have
|
|
25
31
|
**no text-color prop** — wrap content in `<Span textColor="…">`. `Input` has none either and
|
|
26
32
|
the wrapper trick can't work (it renders a native `<input>`; a child can't color its value):
|
|
27
33
|
recolor via the upstream `--bulma-text-strong-l`, since Bulma re-declares `--bulma-input-*` on
|
|
@@ -40,43 +46,43 @@ Shades (`colorShade` / `backgroundColorShade`): `00, 05, 10, … 95, invert, lig
|
|
|
40
46
|
|
|
41
47
|
## Component `color` / `size` props (verbatim unions)
|
|
42
48
|
|
|
43
|
-
| Component | `color` accepts
|
|
44
|
-
| ------------------ |
|
|
45
|
-
| `Button` | `primary \| link \| info \| success \| warning \| danger \| white \| light \| dark \| black \| text \| ghost`
|
|
46
|
-
| `Notification` | the 17 `validColors` (greys
|
|
47
|
-
| `Tag` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
48
|
-
| `Box` | `primary \| link \| info \| success \| warning \| danger`
|
|
49
|
-
| `Message` | `primary \| link \| info \| success \| warning \| danger`
|
|
50
|
-
| `Input` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
51
|
-
| `Avatar` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
52
|
-
| `Badge` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
53
|
-
| `Title` | — (no `color`; use `textColor`)
|
|
54
|
-
| `SubTitle` | — (no `color`; use `textColor`)
|
|
55
|
-
| `Autocomplete` | `primary \| link \| info \| success \| warning \| danger`
|
|
56
|
-
| `Checkbox` | `primary \| link \| info \| success \| warning \| danger`
|
|
57
|
-
| `DateInput` | `primary \| link \| info \| success \| warning \| danger`
|
|
58
|
-
| `DateTimeInput` | `primary \| link \| info \| success \| warning \| danger`
|
|
59
|
-
| `File` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
60
|
-
| `Hero` | the 17 `validColors` (greys
|
|
61
|
-
| `LinkButton` | `primary \| link \| info \| success \| warning \| danger \| white \| light \| dark \| black`
|
|
62
|
-
| `Loading` | `primary \| link \| info \| success \| warning \| danger`
|
|
63
|
-
| `Navbar` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
64
|
-
| `Numberinput` | `primary \| link \| info \| success \| warning \| danger \| light \| dark`
|
|
65
|
-
| `Pagination` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
66
|
-
| `Panel` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
67
|
-
| `Progress` | the 17 `validColors` (greys
|
|
68
|
-
| `Radio` | `primary \| link \| info \| success \| warning \| danger`
|
|
69
|
-
| `Rate` | `primary \| link \| info \| success \| warning \| danger`
|
|
70
|
-
| `Select` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
71
|
-
| `Slider` | `primary \| link \| info \| success \| warning \| danger`
|
|
72
|
-
| `Steps` | `primary \| link \| info \| success \| warning \| danger`
|
|
73
|
-
| `Switch` | `primary \| link \| info \| success \| warning \| danger`
|
|
74
|
-
| `Tabs` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
75
|
-
| `Taginput` | `primary \| link \| info \| success \| warning \| danger`
|
|
76
|
-
| `TextArea` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
77
|
-
| `TimeInput` | `primary \| link \| info \| success \| warning \| danger`
|
|
78
|
-
| `Tooltip` | `primary \| link \| info \| success \| warning \| danger \| dark \| light`
|
|
79
|
-
| `Tr` / `Td` / `Th` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white`
|
|
49
|
+
| Component | `color` accepts | `size` accepts | Notes |
|
|
50
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| `Button` | `primary \| link \| info \| success \| warning \| danger \| white \| light \| dark \| black \| text \| ghost` | `small \| normal \| medium \| large` | adds `text`, `ghost`; also `isLight`, `isOutlined`, `isInverted`, `isRounded` |
|
|
52
|
+
| `Notification` | the 17 `validColors` (`black-bis`, `black-ter`, and greys deprecated: no CSS, dev-warn, removed next major — see ⚠️) | — | also `isLight` |
|
|
53
|
+
| `Tag` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `normal \| medium \| large` | also `isLight`, `isRounded`, `isDelete`, `isHoverable` |
|
|
54
|
+
| `Box` | `primary \| link \| info \| success \| warning \| danger` | — | `color` renders `has-text-<color>`, same as `textColor` (which wins when both are set; no `.box.is-*` ships — tint via `bgColor`); also `hasShadow` |
|
|
55
|
+
| `Message` | `primary \| link \| info \| success \| warning \| danger` | — | the 6 only |
|
|
56
|
+
| `Input` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | also `isRounded`, `isStatic` |
|
|
57
|
+
| `Avatar` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `16x16 \| 24x24 \| 32x32 \| 48x48 \| 64x64 \| 96x96 \| 128x128 \| number` | initials/icon background (auto-derived from `name` when unset); also `shape` |
|
|
58
|
+
| `Badge` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | — | pill background; default `danger` |
|
|
59
|
+
| `Title` | — (no `color`; use `textColor`) | `1`–`6` (string or number) | also `isSpaced` |
|
|
60
|
+
| `SubTitle` | — (no `color`; use `textColor`) | `1`–`6` (string or number) | — |
|
|
61
|
+
| `Autocomplete` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | the 6 only |
|
|
62
|
+
| `Checkbox` | `primary \| link \| info \| success \| warning \| danger` | `small \| normal \| medium \| large` | the 6 only |
|
|
63
|
+
| `DateInput` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | also `isRounded` |
|
|
64
|
+
| `DateTimeInput` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | also `isRounded` |
|
|
65
|
+
| `File` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | also `isBoxed`, `isFullwidth` |
|
|
66
|
+
| `Hero` | the 17 `validColors` + `inherit`/`current` (`black-bis`, `black-ter`, greys, `inherit`, `current` deprecated: no CSS, dev-warn, removed next major — see ⚠️) | `small \| medium \| large \| fullheight \| fullheight-with-navbar` | section background |
|
|
67
|
+
| `LinkButton` | `primary \| link \| info \| success \| warning \| danger \| white \| light \| dark \| black` | — | button-styled link; emits `link-button-<color>` — **no `isLight`/`isOutlined`/`isInverted`** |
|
|
68
|
+
| `Loading` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | spinner color; default light grey |
|
|
69
|
+
| `Navbar` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | — | — |
|
|
70
|
+
| `Numberinput` | `primary \| link \| info \| success \| warning \| danger \| light \| dark` | `small \| medium \| large` | also `inputColor` (the 6) for the inner input |
|
|
71
|
+
| `Pagination` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | **entire `color` prop deprecated** (no CSS ships; dev-warn; removal next major) |
|
|
72
|
+
| `Panel` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | — | — |
|
|
73
|
+
| `Progress` | the 17 `validColors` (`black-bis`, `black-ter`, and greys deprecated: no CSS, dev-warn, removed next major — see ⚠️) | `small \| medium \| large` | — |
|
|
74
|
+
| `Radio` | `primary \| link \| info \| success \| warning \| danger` | `small \| normal \| medium \| large` | the 6 only |
|
|
75
|
+
| `Rate` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | the 6 only |
|
|
76
|
+
| `Select` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | also `isRounded` |
|
|
77
|
+
| `Slider` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | also `isRounded`, `isCircle` |
|
|
78
|
+
| `Steps` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | the 6 only |
|
|
79
|
+
| `Switch` | `primary \| link \| info \| success \| warning \| danger` | `small \| normal \| medium \| large` | also `isRounded`, `isThin`, `isOutlined` |
|
|
80
|
+
| `Tabs` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | **entire `color` prop deprecated** (no CSS ships; dev-warn; removal next major) |
|
|
81
|
+
| `Taginput` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | also `tagColor` (the 6 + `dark \| light`) for the tags |
|
|
82
|
+
| `TextArea` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | also `isRounded`, `isStatic` |
|
|
83
|
+
| `TimeInput` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | — |
|
|
84
|
+
| `Tooltip` | `primary \| link \| info \| success \| warning \| danger \| dark \| light` | `small \| medium \| large` | — |
|
|
85
|
+
| `Tr` / `Td` / `Th` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | — | cell background; cells take `textAlign`/`textWeight`/`textSize` directly |
|
|
80
86
|
|
|
81
87
|
The 6 brand colors (`primary, link, info, success, warning, danger`) are the ones a custom theme
|
|
82
88
|
recolors via the HSL trios (see `css-variables.md`). The greyscale and `white`/`light`/`dark`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
*.tsbuildinfo
|
|
15
|
+
|
|
16
|
+
# Editor directories and files
|
|
17
|
+
.vscode/*
|
|
18
|
+
!.vscode/extensions.json
|
|
19
|
+
.idea
|
|
20
|
+
.DS_Store
|
|
21
|
+
*.suo
|
|
22
|
+
*.ntvs*
|
|
23
|
+
*.njsproj
|
|
24
|
+
*.sln
|
|
25
|
+
*.sw?
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
*.tsbuildinfo
|
|
15
|
+
|
|
16
|
+
# Editor directories and files
|
|
17
|
+
.vscode/*
|
|
18
|
+
!.vscode/extensions.json
|
|
19
|
+
.idea
|
|
20
|
+
.DS_Store
|
|
21
|
+
*.suo
|
|
22
|
+
*.ntvs*
|
|
23
|
+
*.njsproj
|
|
24
|
+
*.sln
|
|
25
|
+
*.sw?
|