@ brilo/ 基本块
共享古腾堡区块工厂图书馆. 租户调用工厂功能,登记结果,只拥有
block.json + 图标文件。 这个文件是唯一一个文件——当它不同意时 src/blocks/*,代码获胜.
安装( 租户)
发表于 @brilo/base-blocks npm 软件包——普通 bun install 在租户拉它.
针对未承诺的基块变化的本地 dev 使用 bun link数字 :
# in base-blocks
bun run build
bun link
# in tenant gutenberg dir
bun link @brilo/base-blocks
重新运行 bun run build 任何变化后在基块中的链接点- build/没有 src/。 。 。 .
图标
bun run build # biome check + tsc → build/
bun run check # biome check --write + tsc --noEmit
bun run format # biome (TS) + prettier (SCSS)
结构
src/
blocks/
<domain>/ one per content type, mirrors frontoffice twig components 1:1:
anchor/, compare/, contact/, faq/, gallery/, hero/, person/,
signpost/, step/, testimonial/, usp/ … each with <domain>-group/
and/or <domain>-item/
core/ atomic, no inner blocks: basic-button · basic-heading · basic-overline
groups/ generic (non-domain) layout groups: banner-group · basic-header-group ·
button-group · content-group · text-and-media-group
sections/ top-level page sections: base-section
layout/ aside/content layout blocks
form/ form-group · form-field
link/ · map/ · newsletter/ · post/ · responsive-grid/
components/ IconControl · ImagePicker · ItemIconControl · PaletteColorControl
hooks/ useGroupBlock · useTenantColorPalette
utils/ createEditAdapter
constants.ts shared HEADING_LEVELS · HEADING_STYLES · CONTENT_SIZES
editor.scss SCSS barrel — @forward all block + component + global styles
globals.scss global editor utility classes (flex, gap-*, u-grid-*, …)
index.ts JS/TS barrel
types.ts shared types (BriloBlockType, SelectOption, Icon, OptionArray, …)
不要发明新的顶级文件夹: 显示前台组件的块镜像会进入它的域名文件夹, 一个原子
一个英寸 core/,一个没有内容域的通用包装 groups/。 。 。 .
后缀告诉工作,与前台相同:
| 后缀 | 任务 |
|---|---|
-group | InnerBlocks 集装箱。 布局/栏/方向控制。 限制儿童通过 allowedBlocks。从不使实体标记. |
-item | 匹配组内的单个实体块( E)parent: ['brilo/xxx-group']) (中文(简体) ). 从不累. |
-section | 顶级页面部分, 包接组( T)sections/base-section) (中文(简体) ). |
-form 编号 : -field | 格式容器/单字段. |
块文件
blocks/<domain>/<block-name>/
├── factory.tsx required
├── edit.tsx required
├── types.ts required
├── index.ts required
├── constants.ts only if the block has option arrays
├── icon.tsx only if the block needs a custom icon
└── editor.scss only if the block needs editor styles
| 文件 | 出口 | 规则 |
|---|---|---|
factory.tsx | createXxxBlock(options) → BlockConfiguration<XxxAttributes> | 仅限WP位置 attributes 计划是定义的. save: () => null (原子/项目)或 () => <InnerBlocks.Content /> (组/科). 再出口 XxxAttributes编号 :XxxOptions。 。 。 . |
edit.tsx | createXxxEdit(options) − 反应组件 | 没有内置数组——取自 constants.ts无模块级 __()。 。 。 . |
types.ts | XxxAttributes, (中文(简体) ), XxxOptions | XxxAttributes extends Record<string, unknown>, (中文(简体) ), XxxOptions extends BriloBlockType。 。 。 . |
constants.ts | 选项数组, DEFAULT_* | as const。翻译的标签住在这里,而不是在 edit.tsx。 。 。 . |
icon.tsx | icon (日语) <svg>(中文(简体) ) | 否则工厂会使用WP图标弹簧弦(例如. 'admin-links') (中文(简体) ). |
index.ts | 枪管+ xxxDefaults | xxxDefaults 在此定义, 不在 factory.tsx常数不再出口 阻断-私人. |
editor.scss | 只编辑器样式 | @forward 它从 src/editor.scss。没有前端样式. |
命名
| 东西 | 模式 | 实例 |
|---|---|---|
| 工厂 | createXxxBlock | createBasicButtonBlock |
| 编辑厂 | createXxxEdit | createBasicButtonEdit |
| 属性类型 | XxxAttributes | BasicButtonAttributes |
| 选项类型 | XxxOptions | BasicButtonOptions |
| 默认对象 | xxxDefaults | basicButtonDefaults |
常数是尖叫-SNAKE. DEFAULT_ 仅用于租户可支配选项的倒置; 固定套件
(单位:千美元)HEADING_LEVELS, (中文(简体) ), CHIP_POSITIONS)没有前缀.
进口
tsconfig.json 地图 ~/* → ./src/*。共享代码总是 ~/types, (中文(简体) ), ~/constants, (中文(简体) ), ~/hooks/..., (中文(简体) ),
~/components/... 从来没有 ../../../。块本地代码为 ./constants, (中文(简体) ), ./types。将冲突命名为 — 导入别名
(单位:千美元)import {HEADING_LEVELS as SHARED_HEADING_LEVELS} from '~/constants') (中文(简体) ).
类型
BriloBlockType (从) ~/types)是每个系统的共同基础 XxxOptions数字 : name, (中文(简体) ), title?, (中文(简体) ), description?, (中文(简体) ),
category?, (中文(简体) ), allowedBlocks?, (中文(简体) ), template?, (中文(简体) ), blockClassName?, (中文(简体) ), containerClassName?, (中文(简体) ), icon?, (中文(简体) ), parent?。 。 。 .
SelectOption (单位:千美元){value, label}也生活在一个 ~/types 永远不要在街区里重新宣布.
属性结合来源于 as const 数组,从未用手写 :
// constants.ts
export const MEDIA_POSITIONS = [
{value: 'left', label: __('Vlevo', 'brilo-blocks')},
{value: 'right', label: __('Vpravo', 'brilo-blocks')},
] as const
export const HEADING_LEVELS = [1, 2, 3] as const
// types.ts
export type MediaPosition = (typeof MEDIA_POSITIONS)[number]['value'] // 'left' | 'right'
export type HeadingLevel = (typeof HEADING_LEVELS)[number] // 1 | 2 | 3
对属性也使用导出类型( E)headingLevel: HeadingLevel没有 number所以铸造像
tagName={`h${headingLevel}` as `h${HeadingLevel}`} 跟随常数。 仅允许一个子集
标题级别定义自己的 HEADING_LEVELS; 否则再出口共享的 ~/constants。 。 。 .
选项模式
每个房客的可支配价值都有 DEFAULT_* 内 constants.ts,解决一次 ??确定的价值是:
绝不是原始的默认——输入两个属性 enum 和编辑用户界面, 或租户控制被悄悄地删除 :
// ✓ reflects tenant override
const variants = options.variants ?? DEFAULT_VARIANTS
attributes: {variant: {type: 'string', default: variants[0].value, enum: variants.map((v) => v.value)}}
// ✗ ignores tenant override
attributes: {variant: {enum: DEFAULT_VARIANTS.map((v) => v.value)}}
强制性选项( 如 name)没有默认,在界面中需要.
一般工厂
其选项包含可压倒性的 enum 阵列的工厂是通用的,所以 TypeScript 将属性字缩入
这正是房客通过。 只有可压倒性的阵列成为类型参数——固定的阵列保持硬码.
usp/usp-group/factory.tsx 这是最充分的例子.
// factory.tsx
export function createBasicButtonBlock<
TVariants extends OptionArray = typeof DEFAULT_VARIANTS,
TSizes extends OptionArray = typeof DEFAULT_SIZES,
>(options: BasicButtonOptions<TVariants, TSizes>): BlockConfiguration<BasicButtonAttributes<TVariants[number]['value'], TSizes[number]['value']>>
// edit.tsx stays non-generic; factory casts when calling it
edit: createBasicButtonEdit(options as unknown as BasicButtonOptions),
约束类型从 ~/types数字 : OptionArray (单位:千美元)ReadonlyArray<{value; label}>, (中文(简体) ), NumberArray, (中文(简体) ), StringArray。 。 。 .
租户一方—— as const 文字推断需要:
createBasicButtonBlock({...basicButtonDefaults}) // variant: 'primary' | 'secondary'
const MY_VARIANTS = [
{value: 'primary', label: 'Primární'},
{value: 'brand', label: 'Brand'},
] as const
createBasicButtonBlock({...basicButtonDefaults, variants: MY_VARIANTS}) // variant: 'primary' | 'brand'
编辑组件
组块使用 useGroupBlock (包装) useBlockProps + 键 useInnerBlocksProps,接受 templateLock, (中文(简体) ),
orientation, (中文(简体) ), layout, (中文(简体) ), renderAppender);项目/原子块使用平原 useBlockProps。 。 。 .
const {blockProps, innerBlocksProps} = useGroupBlock({
blockClassName: options.blockClassName ?? 'g-usp',
containerClassName: 'g-usp__list',
allowedBlocks: options.allowedBlocks,
template: options.template,
})
return (
<div {...blockProps}>
<div {...innerBlocksProps} />
</div>
)
班级总是通过 clsx, BEM, 与它制成的树枝组分相同的根类(g- 组, i- 项目,
base- (第2款) editor.scss 常设委员会同意:
const blockProps = useBlockProps({
className: clsx(options.blockClassName ?? 'i-button', `--variant-${variant}`, outline && '--outline'),
})
所有用户可见的字符串 : __('…', 'brilo-blocks')。 。 。 .
共享组件和钩子
使用这些选项而不是在块内重新执行 UI :
PaletteColorControl- 贴有标签的租户-帕莱特取色器(label, (中文(简体) ),help?, (中文(简体) ),id?, (中文(简体) ),value, (中文(简体) ),onChange, (中文(简体) ),enableAlpha?, (中文(简体) ),clearable?) (中文(简体) ). 带走和返回''用于"无色". 使用每个颜色属性代替BaseControl+ 键ColorPalette+ 键useTenantColorPalette。 。 。 .IconControl——预选SVG图标网格.ItemIconControl+ 键ItemIconPreview——带有"预选对媒体"切换的图标控件(anchor-item, (中文(简体) ),usp-item) (中文(简体) ).ImagePickerControl(边栏上传/选择)+ImagePickerBody(canvas预览),useMediaUrl(id)。 。 。 .useTenantColorPalette——租户paletteColors+ 键resolveHex(计:ContrastChecker) (中文(简体) ).
新的块清单
- 选择域文件夹 + 后缀(参见 结构) (中文(简体) ).
types.ts数字 :XxxAttributes, (中文(简体) ),XxxOptions。 。 。 .constants.ts如果有任何选项数组.factory.tsx: 用??,构建attributesưμ㼯aBlockConfiguration。 。 。 .edit.tsx数字 :createXxxEdit(options)中,控件InspectorControls→PanelBody。 。 。 .icon.tsx只有在需要的时候.index.ts枪管+xxxDefaults。 。 。 .editor.scss, (中文(简体) ),@forward从src/editor.scss。 。 。 .- 导出自
src/index.ts数字 :export type {XxxAttributes, XxxOptions}+ 键export {createXxxBlock, xxxDefaults}。 。 。 . bun run build,然后在租户登记(以下).
最小模板 :
// factory.tsx
import type {BlockConfiguration} from '@wordpress/blocks'
import {createXxxEdit} from './edit'
import type {XxxAttributes, XxxOptions} from './types'
export type {XxxAttributes, XxxOptions}
export function createXxxBlock(options: XxxOptions): BlockConfiguration<XxxAttributes> {
return {
name: options.name,
title: options.title ?? 'TODO',
description: options.description,
category: options.category ?? 'common',
...(options.parent && {parent: options.parent}),
supports: {html: false, customClassName: false},
attributes: {},
edit: createXxxEdit(options),
save: () => null,
} as unknown as BlockConfiguration<XxxAttributes>
}
// index.ts
export type {XxxAttributes, XxxOptions} from './types'
export {createXxxBlock} from './factory'
export {createXxxEdit} from './edit'
import type {XxxOptions} from './types'
export const xxxDefaults: XxxOptions = {
name: 'brilo/xxx',
parent: ['brilo/xxx-group'],
}
租户使用
import {createUspItemBlock, uspItemDefaults} from "@brilo/base-blocks"
import {registerBlockType} from "@wordpress/blocks"
import metadata from "./block.json"
import {ICONS, ICONS_SRC} from "./icons"
const config = createUspItemBlock({
...uspItemDefaults,
name: metadata.name,
parent: metadata.parent as string[],
icons: ICONS,
iconsSrc: ICONS_SRC,
})
registerBlockType(config.name as string, config)
每个租户区都需要一个 block.json 旁边 index.tsx:建立元数据($schema, (中文(简体) ), apiVersion, (中文(简体) ), name, (中文(简体) ),
editorScript, (中文(简体) ), editorStyle+) 加上 (中文(简体) ) title, (中文(简体) ), description, (中文(简体) ), parent编号 :allowedBlocks, (中文(简体) ), attributes (与 enum 页:1
选项集)和一个 example工厂里的镜子 块目录读取他们通过
/wp/v2/block-types/brilo。 。 。 .
支持它所需的块 extraAttributes (租户在基数之上的属性)和 extraControls (预算外)
基点以下的检查员控制; createBaseSectionBlock 还要 exclude 以删除基准属性 :
type ExtraAttrs = {overlap: boolean}
const config = createBaseSectionBlock<ExtraAttrs>({
name: "my-tenant/base-section",
allowedBlocks: ["my-tenant/basic-header-group", "my-tenant/usp-group"],
blockClassName: "s-base",
containerClassName: "s-base__inner",
extraAttributes: {overlap: {type: "boolean", default: false}},
extraControls: ({attributes, setAttributes}) => (
<ToggleControl
label={__("Překrytí sekce", "brilo-blocks")}
checked={attributes.overlap}
onChange={(value) => setAttributes({overlap: value})}
/>
),
// exclude: ["background"],
})
样式( 租户)
租户 index.scss数字 :
@use "@brilo/base-blocks/src/editor"; /* block styles, mostly in @layer base */
@import "@brilo/gutenberg-toolkit/build/index.css";
@layer base, tenant; /* tenant layer always wins */
取代租户SSCSS中的基础样式 @layer tenant { } ——只用于其风格坐落的文件
@layer base。一些块 editor.scss 文件还在 无层:他们依靠击打未上层的WP编辑器
缺省数(h*编号 :p编号 :hr 边距和字体大小, .wp-block (边际)和压倒性 .i-item-icon分层 CSS
输给任何没有层次的CSS, 所以压倒那些没有层次的。 移动到层里需要每个文件检查
编辑.