best-lowcode-runtime 0.2.2 → 0.2.4

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/dev.js CHANGED
@@ -188,6 +188,14 @@ function validateCrudPageSchema(schema, registry) {
188
188
  if (!schema.table?.columns?.length)
189
189
  push(diagnostics, "/table/columns", "table.columns", "\u81F3\u5C11\u9700\u8981\u4E00\u5217");
190
190
  schema.table?.columns?.forEach((column, index) => {
191
+ if (column.fixed !== void 0 && column.fixed !== "left" && column.fixed !== "right") {
192
+ push(
193
+ diagnostics,
194
+ `/table/columns/${index}/fixed`,
195
+ "column.fixed",
196
+ `\u4E0D\u652F\u6301\u7684\u56FA\u5B9A\u4F4D\u7F6E\uFF1A${column.fixed}`
197
+ );
198
+ }
191
199
  if (column.format && !columnFormats.has(column.format)) {
192
200
  push(
193
201
  diagnostics,
package/dist/dev.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/lowcode/schema.ts", "../src/lowcode/validate.ts", "../src/lowcode/dev.ts"],
4
- "sourcesContent": ["import type { BestFieldComponent, BestFieldRule } from '../ui/types'\n\nexport const CRUD_SCHEMA_ID = 'https://best.dev/schema/crud/v1' as const\nexport const CRUD_SCHEMA_VERSION = 1 as const\n\nexport type Condition =\n | { operator: 'equals'; field: string; value: string | number | boolean | null }\n | { operator: 'notEmpty'; field: string }\n | { operator: 'modeEquals'; value: FormMode }\n | { operator: 'and' | 'or'; conditions: Condition[] }\n | { operator: 'not'; condition: Condition }\n\nexport type FormMode = 'create' | 'edit' | 'detail'\n\nexport type FieldSchema = {\n field: string\n label: string\n component: BestFieldComponent\n placeholder?: string\n dict?: string\n required?: boolean\n disabled?: boolean\n hidden?: boolean\n maxDate?: 'today'\n span?: number\n defaultValue?: string | number | boolean | null\n rules?: BestFieldRule[]\n /** Application-specific form control registered in the BestProvider registry. */\n slot?: string\n remoteService?: string\n searchField?: string\n labelField?: string\n valueField?: string\n debounceMs?: number\n pageSize?: number\n visibleWhen?: Condition\n disabledWhen?: Condition\n /** Clears stale dependent values when this field becomes hidden. */\n clearWhenHidden?: boolean\n /** Repeated object fields, for rules such as tiered pricing. */\n itemFields?: Omit<FieldSchema, 'itemFields'>[]\n minItems?: number\n maxItems?: number\n}\n\nexport type TableColumnSchema = {\n field: string\n title: string\n dict?: string\n width?: number\n format?: 'date' | 'datetime' | 'money' | 'text'\n slot?: string\n}\n\nexport type DetailFieldSchema = {\n field: string\n label: string\n dict?: string\n span?: number\n slot?: string\n}\n\nexport type PageActionSchema = {\n id: string\n label: string\n effect: 'openCreate' | 'openDetail' | 'openEdit' | 'remove' | 'runAction' | 'slot'\n action?: string\n slot?: string\n access?: string\n confirm?: string\n}\n\nexport type CrudPageSchema = {\n $schema: typeof CRUD_SCHEMA_ID\n version: typeof CRUD_SCHEMA_VERSION\n id: string\n kind: 'crud'\n title: string\n dataSource: {\n list: string\n detail?: string\n create?: string\n update?: string\n remove?: string\n }\n search?: FieldSchema[]\n searchMode?: 'proTable' | 'bestSearch'\n form?: FieldSchema[]\n table: {\n rowKey: string | string[]\n columns: TableColumnSchema[]\n actions?: PageActionSchema[]\n scrollX?: number\n pageSize?: number\n }\n detail?: { fields: DetailFieldSchema[] }\n toolbar?: PageActionSchema[]\n meta?: {\n generatedBy?: string\n generatedAt?: string\n }\n}\n", "import type { BestRegistry } from '../runtime'\nimport {\n type Condition,\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n type CrudPageSchema,\n type FieldSchema,\n type PageActionSchema\n} from './schema'\n\nexport type SchemaDiagnostic = {\n path: string\n code: string\n message: string\n}\n\nexport type SchemaValidationResult = {\n valid: boolean\n diagnostics: SchemaDiagnostic[]\n}\n\nconst fieldComponents = new Set([\n 'input',\n 'number',\n 'select',\n 'remoteSelect',\n 'date',\n 'dateRange',\n 'textarea',\n 'slot',\n 'repeatable'\n])\nconst builtInEffects = new Set([\n 'openCreate',\n 'openDetail',\n 'openEdit',\n 'remove',\n 'runAction',\n 'slot'\n])\nconst columnFormats = new Set(['date', 'datetime', 'money', 'text'])\n\nfunction push(diagnostics: SchemaDiagnostic[], path: string, code: string, message: string) {\n diagnostics.push({ path, code, message })\n}\n\nfunction validateCondition(condition: Condition, path: string, diagnostics: SchemaDiagnostic[]) {\n if (!condition || typeof condition !== 'object') {\n push(diagnostics, path, 'condition.type', '\u6761\u4EF6\u5FC5\u987B\u662F\u5BF9\u8C61')\n return\n }\n if (condition.operator === 'equals') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'equals \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'notEmpty') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'notEmpty \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'modeEquals') {\n return\n }\n if (\n (condition.operator === 'and' || condition.operator === 'or') &&\n !Array.isArray(condition.conditions)\n ) {\n push(diagnostics, path, 'condition.conditions', '\u7EC4\u5408\u6761\u4EF6\u5FC5\u987B\u6307\u5B9A conditions \u6570\u7EC4')\n return\n }\n if (condition.operator === 'and' || condition.operator === 'or') {\n if (condition.conditions.length === 0) {\n push(diagnostics, path, 'condition.empty', '\u7EC4\u5408\u6761\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u6761\u4EF6')\n }\n condition.conditions.forEach((item, index) => {\n validateCondition(item, `${path}/conditions/${index}`, diagnostics)\n })\n return\n }\n if (condition.operator === 'not') {\n if (!condition.condition) {\n push(diagnostics, path, 'condition.missing', 'not \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A condition')\n return\n }\n validateCondition(condition.condition, `${path}/condition`, diagnostics)\n return\n }\n push(diagnostics, path, 'condition.operator', `\u4E0D\u652F\u6301\u7684\u6761\u4EF6\uFF1A${(condition as { operator?: unknown }).operator}`)\n}\n\nfunction validateFields(\n fields: FieldSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n diagnostics: SchemaDiagnostic[]\n) {\n const seen = new Set<string>()\n fields?.forEach((field, index) => {\n const fieldPath = `${path}/${index}`\n if (!field.field) push(diagnostics, fieldPath, 'field.missing', '\u5B57\u6BB5\u540D\u4E0D\u80FD\u4E3A\u7A7A')\n if (seen.has(field.field))\n push(diagnostics, fieldPath, 'field.duplicate', `\u5B57\u6BB5\u91CD\u590D\uFF1A${field.field}`)\n seen.add(field.field)\n if (!fieldComponents.has(field.component))\n push(diagnostics, fieldPath, 'field.component', `\u4E0D\u652F\u6301\u7684\u7EC4\u4EF6\uFF1A${field.component}`)\n if (field.dict && registry && !registry.dictionaries[field.dict]) {\n push(diagnostics, fieldPath, 'registry.dictionary', `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${field.dict}`)\n }\n if (field.component === 'remoteSelect' && !field.remoteService)\n push(diagnostics, fieldPath, 'field.remoteService', 'remoteSelect \u5FC5\u987B\u6307\u5B9A remoteService')\n if (field.remoteService && registry && !registry.services[field.remoteService])\n push(diagnostics, fieldPath, 'registry.service', `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${field.remoteService}`)\n if (field.component === 'slot' && !field.slot)\n push(diagnostics, fieldPath, 'field.slot', 'slot \u7EC4\u4EF6\u5FC5\u987B\u6307\u5B9A slot key')\n if (field.component === 'repeatable' && !field.itemFields?.length)\n push(\n diagnostics,\n fieldPath,\n 'field.repeatable',\n 'repeatable \u7EC4\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A itemFields \u5B57\u6BB5'\n )\n if (field.itemFields?.length)\n validateFields(\n field.itemFields as FieldSchema[],\n `${fieldPath}/itemFields`,\n registry,\n diagnostics\n )\n if (\n field.minItems !== undefined &&\n field.maxItems !== undefined &&\n field.minItems > field.maxItems\n )\n push(diagnostics, fieldPath, 'field.repeatable.range', 'minItems \u4E0D\u80FD\u5927\u4E8E maxItems')\n if (field.slot && registry && !registry.slots[field.slot])\n push(diagnostics, fieldPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`)\n if (field.visibleWhen)\n validateCondition(field.visibleWhen, `${fieldPath}/visibleWhen`, diagnostics)\n if (field.disabledWhen)\n validateCondition(field.disabledWhen, `${fieldPath}/disabledWhen`, diagnostics)\n })\n}\n\nfunction validateActions(\n actions: PageActionSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n hasRemoveService: boolean,\n diagnostics: SchemaDiagnostic[]\n) {\n actions?.forEach((action, index) => {\n const actionPath = `${path}/${index}`\n if (!action.id) push(diagnostics, actionPath, 'action.missing', '\u52A8\u4F5C id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!builtInEffects.has(action.effect))\n push(diagnostics, actionPath, 'action.effect', `\u4E0D\u652F\u6301\u7684\u52A8\u4F5C\uFF1A${action.effect}`)\n if (action.effect === 'runAction' && !action.action)\n push(diagnostics, actionPath, 'action.key', 'runAction \u5FC5\u987B\u6307\u5B9A action key')\n if (action.effect === 'remove' && !hasRemoveService)\n push(diagnostics, actionPath, 'action.removeService', 'remove \u52A8\u4F5C\u5FC5\u987B\u914D\u7F6E dataSource.remove')\n if (action.effect === 'slot' && !action.slot)\n push(diagnostics, actionPath, 'action.slot', 'slot \u52A8\u4F5C\u5FC5\u987B\u6307\u5B9A slot key')\n if (action.action && registry && !registry.actions[action.action]) {\n push(diagnostics, actionPath, 'registry.action', `\u672A\u6CE8\u518C\u52A8\u4F5C\uFF1A${action.action}`)\n }\n if (action.slot && registry && !registry.slots[action.slot]) {\n push(diagnostics, actionPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${action.slot}`)\n }\n })\n}\n\nexport function validateCrudPageSchema(\n schema: CrudPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== CRUD_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${CRUD_SCHEMA_ID}`)\n if (schema.version !== CRUD_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${CRUD_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.title) push(diagnostics, '/title', 'page.title', '\u9875\u9762\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.dataSource?.list)\n push(diagnostics, '/dataSource/list', 'service.list', '\u5217\u8868\u670D\u52A1\u4E0D\u80FD\u4E3A\u7A7A')\n if (schema.dataSource?.list && registry && !registry.listServices[schema.dataSource.list]) {\n push(\n diagnostics,\n '/dataSource/list',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.list}`\n )\n }\n if (schema.dataSource?.detail && registry && !registry.services[schema.dataSource.detail]) {\n push(\n diagnostics,\n '/dataSource/detail',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.detail}`\n )\n }\n if (schema.dataSource?.create && registry && !registry.services[schema.dataSource.create]) {\n push(\n diagnostics,\n '/dataSource/create',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.create}`\n )\n }\n if (schema.dataSource?.update && registry && !registry.services[schema.dataSource.update]) {\n push(\n diagnostics,\n '/dataSource/update',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.update}`\n )\n }\n if (schema.dataSource?.remove && registry && !registry.services[schema.dataSource.remove]) {\n push(\n diagnostics,\n '/dataSource/remove',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.remove}`\n )\n }\n validateFields(schema.search, '/search', registry, diagnostics)\n validateFields(schema.form, '/form', registry, diagnostics)\n if (!schema.table?.rowKey) push(diagnostics, '/table/rowKey', 'table.rowKey', 'rowKey \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.table?.columns?.length)\n push(diagnostics, '/table/columns', 'table.columns', '\u81F3\u5C11\u9700\u8981\u4E00\u5217')\n schema.table?.columns?.forEach((column, index) => {\n if (column.format && !columnFormats.has(column.format)) {\n push(\n diagnostics,\n `/table/columns/${index}/format`,\n 'column.format',\n `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${column.format}`\n )\n }\n if (column.dict && registry && !registry.dictionaries[column.dict]) {\n push(\n diagnostics,\n `/table/columns/${index}/dict`,\n 'registry.dictionary',\n `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${column.dict}`\n )\n }\n if (column.slot && registry && !registry.slots[column.slot]) {\n push(\n diagnostics,\n `/table/columns/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${column.slot}`\n )\n }\n })\n if (schema.detail !== undefined) {\n if (\n !schema.detail ||\n typeof schema.detail !== 'object' ||\n !Array.isArray(schema.detail.fields)\n ) {\n push(diagnostics, '/detail', 'detail.type', 'detail \u5FC5\u987B\u5305\u542B fields \u5BF9\u8C61\u6570\u7EC4')\n } else {\n schema.detail.fields.forEach((field, index) => {\n if (field.slot && registry && !registry.slots[field.slot])\n push(\n diagnostics,\n `/detail/fields/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`\n )\n })\n }\n }\n validateActions(\n schema.table?.actions,\n '/table/actions',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n validateActions(\n schema.toolbar,\n '/toolbar',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidCrudPageSchema(schema: CrudPageSchema, registry?: BestRegistry) {\n const result = validateCrudPageSchema(schema, registry)\n if (!result.valid) {\n const message = result.diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n')\n throw new Error(`Schema \u6821\u9A8C\u5931\u8D25\uFF1A\\n${message}`)\n }\n}\n", "import type {\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n CrudPageSchema,\n FieldSchema,\n PageActionSchema\n} from './schema'\nimport type { SchemaDiagnostic, SchemaValidationResult } from './validate'\nimport { validateCrudPageSchema } from './validate'\n\nconst builtInCapabilities = [\n 'builtin.effect.openCreate',\n 'builtin.effect.openDetail',\n 'builtin.effect.openEdit',\n 'builtin.effect.remove',\n 'builtin.effect.runAction',\n 'builtin.effect.slot',\n 'builtin.format.date',\n 'builtin.format.datetime',\n 'builtin.format.money',\n 'builtin.format.text',\n 'builtin.field.input',\n 'builtin.field.number',\n 'builtin.field.select',\n 'builtin.field.remoteSelect',\n 'builtin.field.date',\n 'builtin.field.dateRange',\n 'builtin.field.textarea',\n 'builtin.field.slot',\n 'builtin.field.repeatable'\n] as const\n\ntype JsonRecord = Record<string, unknown>\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction arrayOfRecords(value: unknown): JsonRecord[] | undefined {\n return Array.isArray(value) && value.every(isRecord) ? value : undefined\n}\n\nfunction diagnostic(path: string, code: string, message: string): SchemaDiagnostic {\n return { path, code, message }\n}\n\nfunction validateUnknownShape(candidate: unknown): SchemaDiagnostic[] {\n if (!isRecord(candidate)) return [diagnostic('', 'schema.type', 'Schema \u5FC5\u987B\u662F JSON \u5BF9\u8C61')]\n const diagnostics: SchemaDiagnostic[] = []\n if (!isRecord(candidate.dataSource))\n diagnostics.push(diagnostic('/dataSource', 'dataSource.type', 'dataSource \u5FC5\u987B\u662F\u5BF9\u8C61'))\n if (!isRecord(candidate.table))\n diagnostics.push(diagnostic('/table', 'table.type', 'table \u5FC5\u987B\u662F\u5BF9\u8C61'))\n for (const key of ['search', 'form'] as const) {\n if (candidate[key] !== undefined && !arrayOfRecords(candidate[key])) {\n diagnostics.push(diagnostic(`/${key}`, 'field.list', `${key} \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4`))\n }\n }\n if (isRecord(candidate.table)) {\n if (!arrayOfRecords(candidate.table.columns)) {\n diagnostics.push(diagnostic('/table/columns', 'column.list', 'columns \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n if (candidate.table.actions !== undefined && !arrayOfRecords(candidate.table.actions)) {\n diagnostics.push(diagnostic('/table/actions', 'action.list', 'actions \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n }\n if (candidate.toolbar !== undefined && !arrayOfRecords(candidate.toolbar)) {\n diagnostics.push(diagnostic('/toolbar', 'action.list', 'toolbar \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n return diagnostics\n}\n\nfunction toRuntimeSchema(candidate: JsonRecord): CrudPageSchema {\n return {\n $schema: candidate.$schema as typeof CRUD_SCHEMA_ID,\n version: candidate.version as typeof CRUD_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'crud',\n title: candidate.title as string,\n dataSource: candidate.dataSource as CrudPageSchema['dataSource'],\n search: candidate.search as FieldSchema[] | undefined,\n searchMode: candidate.searchMode as CrudPageSchema['searchMode'],\n form: candidate.form as FieldSchema[] | undefined,\n table: candidate.table as CrudPageSchema['table'],\n detail: candidate.detail as CrudPageSchema['detail'],\n toolbar: candidate.toolbar as PageActionSchema[] | undefined,\n meta: candidate.meta as CrudPageSchema['meta']\n }\n}\n\n/**\n * Server-safe development entry. It accepts unknown JSON from CLI/MCP before delegating to the\n * runtime validator, so untrusted candidates cannot trigger assumptions in typed runtime code.\n */\nexport function validateUnknownCrudPageSchema(candidate: unknown): SchemaValidationResult {\n const shapeDiagnostics = validateUnknownShape(candidate)\n if (shapeDiagnostics.length || !isRecord(candidate)) {\n return { valid: false, diagnostics: shapeDiagnostics }\n }\n return validateCrudPageSchema(toRuntimeSchema(candidate))\n}\n\n/** Serializable capabilities supplied by the current runtime without application Manifest entries. */\nexport function getBuiltinCapabilities(): string[] {\n return [...builtInCapabilities]\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { BestFieldComponent, BestFieldRule } from '../ui/types'\n\nexport const CRUD_SCHEMA_ID = 'https://best.dev/schema/crud/v1' as const\nexport const CRUD_SCHEMA_VERSION = 1 as const\n\nexport type Condition =\n | { operator: 'equals'; field: string; value: string | number | boolean | null }\n | { operator: 'notEmpty'; field: string }\n | { operator: 'modeEquals'; value: FormMode }\n | { operator: 'and' | 'or'; conditions: Condition[] }\n | { operator: 'not'; condition: Condition }\n\nexport type FormMode = 'create' | 'edit' | 'detail'\n\nexport type FieldSchema = {\n field: string\n label: string\n component: BestFieldComponent\n placeholder?: string\n dict?: string\n required?: boolean\n disabled?: boolean\n hidden?: boolean\n maxDate?: 'today'\n span?: number\n defaultValue?: string | number | boolean | null\n rules?: BestFieldRule[]\n /** Application-specific form control registered in the BestProvider registry. */\n slot?: string\n remoteService?: string\n searchField?: string\n labelField?: string\n valueField?: string\n debounceMs?: number\n pageSize?: number\n visibleWhen?: Condition\n disabledWhen?: Condition\n /** Clears stale dependent values when this field becomes hidden. */\n clearWhenHidden?: boolean\n /** Repeated object fields, for rules such as tiered pricing. */\n itemFields?: Omit<FieldSchema, 'itemFields'>[]\n minItems?: number\n maxItems?: number\n}\n\nexport type TableColumnSchema = {\n field: string\n title: string\n dict?: string\n width?: number\n fixed?: 'left' | 'right'\n format?: 'date' | 'datetime' | 'money' | 'text'\n slot?: string\n}\n\nexport type DetailFieldSchema = {\n field: string\n label: string\n dict?: string\n span?: number\n slot?: string\n}\n\nexport type PageActionButtonType = 'primary' | 'default' | 'link' | 'text' | 'dashed'\n\nexport type PageActionSchema = {\n id: string\n label: string\n effect: 'openCreate' | 'openDetail' | 'openEdit' | 'remove' | 'runAction' | 'slot'\n action?: string\n slot?: string\n access?: string\n confirm?: string\n /** Visual button style; omitted actions use the runtime area default. */\n buttonType?: PageActionButtonType\n}\n\nexport type CrudPageSchema = {\n $schema: typeof CRUD_SCHEMA_ID\n version: typeof CRUD_SCHEMA_VERSION\n id: string\n kind: 'crud'\n title: string\n dataSource: {\n list: string\n detail?: string\n create?: string\n update?: string\n remove?: string\n }\n search?: FieldSchema[]\n searchMode?: 'proTable' | 'bestSearch'\n form?: FieldSchema[]\n table: {\n rowKey: string | string[]\n columns: TableColumnSchema[]\n actions?: PageActionSchema[]\n scrollX?: number\n pageSize?: number\n }\n detail?: { fields: DetailFieldSchema[] }\n toolbar?: PageActionSchema[]\n meta?: {\n generatedBy?: string\n generatedAt?: string\n }\n}\n", "import type { BestRegistry } from '../runtime'\nimport {\n type Condition,\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n type CrudPageSchema,\n type FieldSchema,\n type PageActionSchema\n} from './schema'\n\nexport type SchemaDiagnostic = {\n path: string\n code: string\n message: string\n}\n\nexport type SchemaValidationResult = {\n valid: boolean\n diagnostics: SchemaDiagnostic[]\n}\n\nconst fieldComponents = new Set([\n 'input',\n 'number',\n 'select',\n 'remoteSelect',\n 'date',\n 'dateRange',\n 'textarea',\n 'slot',\n 'repeatable'\n])\nconst builtInEffects = new Set([\n 'openCreate',\n 'openDetail',\n 'openEdit',\n 'remove',\n 'runAction',\n 'slot'\n])\nconst columnFormats = new Set(['date', 'datetime', 'money', 'text'])\n\nfunction push(diagnostics: SchemaDiagnostic[], path: string, code: string, message: string) {\n diagnostics.push({ path, code, message })\n}\n\nfunction validateCondition(condition: Condition, path: string, diagnostics: SchemaDiagnostic[]) {\n if (!condition || typeof condition !== 'object') {\n push(diagnostics, path, 'condition.type', '\u6761\u4EF6\u5FC5\u987B\u662F\u5BF9\u8C61')\n return\n }\n if (condition.operator === 'equals') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'equals \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'notEmpty') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'notEmpty \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'modeEquals') {\n return\n }\n if (\n (condition.operator === 'and' || condition.operator === 'or') &&\n !Array.isArray(condition.conditions)\n ) {\n push(diagnostics, path, 'condition.conditions', '\u7EC4\u5408\u6761\u4EF6\u5FC5\u987B\u6307\u5B9A conditions \u6570\u7EC4')\n return\n }\n if (condition.operator === 'and' || condition.operator === 'or') {\n if (condition.conditions.length === 0) {\n push(diagnostics, path, 'condition.empty', '\u7EC4\u5408\u6761\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u6761\u4EF6')\n }\n condition.conditions.forEach((item, index) => {\n validateCondition(item, `${path}/conditions/${index}`, diagnostics)\n })\n return\n }\n if (condition.operator === 'not') {\n if (!condition.condition) {\n push(diagnostics, path, 'condition.missing', 'not \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A condition')\n return\n }\n validateCondition(condition.condition, `${path}/condition`, diagnostics)\n return\n }\n push(diagnostics, path, 'condition.operator', `\u4E0D\u652F\u6301\u7684\u6761\u4EF6\uFF1A${(condition as { operator?: unknown }).operator}`)\n}\n\nfunction validateFields(\n fields: FieldSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n diagnostics: SchemaDiagnostic[]\n) {\n const seen = new Set<string>()\n fields?.forEach((field, index) => {\n const fieldPath = `${path}/${index}`\n if (!field.field) push(diagnostics, fieldPath, 'field.missing', '\u5B57\u6BB5\u540D\u4E0D\u80FD\u4E3A\u7A7A')\n if (seen.has(field.field))\n push(diagnostics, fieldPath, 'field.duplicate', `\u5B57\u6BB5\u91CD\u590D\uFF1A${field.field}`)\n seen.add(field.field)\n if (!fieldComponents.has(field.component))\n push(diagnostics, fieldPath, 'field.component', `\u4E0D\u652F\u6301\u7684\u7EC4\u4EF6\uFF1A${field.component}`)\n if (field.dict && registry && !registry.dictionaries[field.dict]) {\n push(diagnostics, fieldPath, 'registry.dictionary', `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${field.dict}`)\n }\n if (field.component === 'remoteSelect' && !field.remoteService)\n push(diagnostics, fieldPath, 'field.remoteService', 'remoteSelect \u5FC5\u987B\u6307\u5B9A remoteService')\n if (field.remoteService && registry && !registry.services[field.remoteService])\n push(diagnostics, fieldPath, 'registry.service', `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${field.remoteService}`)\n if (field.component === 'slot' && !field.slot)\n push(diagnostics, fieldPath, 'field.slot', 'slot \u7EC4\u4EF6\u5FC5\u987B\u6307\u5B9A slot key')\n if (field.component === 'repeatable' && !field.itemFields?.length)\n push(\n diagnostics,\n fieldPath,\n 'field.repeatable',\n 'repeatable \u7EC4\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A itemFields \u5B57\u6BB5'\n )\n if (field.itemFields?.length)\n validateFields(\n field.itemFields as FieldSchema[],\n `${fieldPath}/itemFields`,\n registry,\n diagnostics\n )\n if (\n field.minItems !== undefined &&\n field.maxItems !== undefined &&\n field.minItems > field.maxItems\n )\n push(diagnostics, fieldPath, 'field.repeatable.range', 'minItems \u4E0D\u80FD\u5927\u4E8E maxItems')\n if (field.slot && registry && !registry.slots[field.slot])\n push(diagnostics, fieldPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`)\n if (field.visibleWhen)\n validateCondition(field.visibleWhen, `${fieldPath}/visibleWhen`, diagnostics)\n if (field.disabledWhen)\n validateCondition(field.disabledWhen, `${fieldPath}/disabledWhen`, diagnostics)\n })\n}\n\nfunction validateActions(\n actions: PageActionSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n hasRemoveService: boolean,\n diagnostics: SchemaDiagnostic[]\n) {\n actions?.forEach((action, index) => {\n const actionPath = `${path}/${index}`\n if (!action.id) push(diagnostics, actionPath, 'action.missing', '\u52A8\u4F5C id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!builtInEffects.has(action.effect))\n push(diagnostics, actionPath, 'action.effect', `\u4E0D\u652F\u6301\u7684\u52A8\u4F5C\uFF1A${action.effect}`)\n if (action.effect === 'runAction' && !action.action)\n push(diagnostics, actionPath, 'action.key', 'runAction \u5FC5\u987B\u6307\u5B9A action key')\n if (action.effect === 'remove' && !hasRemoveService)\n push(diagnostics, actionPath, 'action.removeService', 'remove \u52A8\u4F5C\u5FC5\u987B\u914D\u7F6E dataSource.remove')\n if (action.effect === 'slot' && !action.slot)\n push(diagnostics, actionPath, 'action.slot', 'slot \u52A8\u4F5C\u5FC5\u987B\u6307\u5B9A slot key')\n if (action.action && registry && !registry.actions[action.action]) {\n push(diagnostics, actionPath, 'registry.action', `\u672A\u6CE8\u518C\u52A8\u4F5C\uFF1A${action.action}`)\n }\n if (action.slot && registry && !registry.slots[action.slot]) {\n push(diagnostics, actionPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${action.slot}`)\n }\n })\n}\n\nexport function validateCrudPageSchema(\n schema: CrudPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== CRUD_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${CRUD_SCHEMA_ID}`)\n if (schema.version !== CRUD_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${CRUD_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.title) push(diagnostics, '/title', 'page.title', '\u9875\u9762\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.dataSource?.list)\n push(diagnostics, '/dataSource/list', 'service.list', '\u5217\u8868\u670D\u52A1\u4E0D\u80FD\u4E3A\u7A7A')\n if (schema.dataSource?.list && registry && !registry.listServices[schema.dataSource.list]) {\n push(\n diagnostics,\n '/dataSource/list',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.list}`\n )\n }\n if (schema.dataSource?.detail && registry && !registry.services[schema.dataSource.detail]) {\n push(\n diagnostics,\n '/dataSource/detail',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.detail}`\n )\n }\n if (schema.dataSource?.create && registry && !registry.services[schema.dataSource.create]) {\n push(\n diagnostics,\n '/dataSource/create',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.create}`\n )\n }\n if (schema.dataSource?.update && registry && !registry.services[schema.dataSource.update]) {\n push(\n diagnostics,\n '/dataSource/update',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.update}`\n )\n }\n if (schema.dataSource?.remove && registry && !registry.services[schema.dataSource.remove]) {\n push(\n diagnostics,\n '/dataSource/remove',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.remove}`\n )\n }\n validateFields(schema.search, '/search', registry, diagnostics)\n validateFields(schema.form, '/form', registry, diagnostics)\n if (!schema.table?.rowKey) push(diagnostics, '/table/rowKey', 'table.rowKey', 'rowKey \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.table?.columns?.length)\n push(diagnostics, '/table/columns', 'table.columns', '\u81F3\u5C11\u9700\u8981\u4E00\u5217')\n schema.table?.columns?.forEach((column, index) => {\n if (column.fixed !== undefined && column.fixed !== 'left' && column.fixed !== 'right') {\n push(\n diagnostics,\n `/table/columns/${index}/fixed`,\n 'column.fixed',\n `\u4E0D\u652F\u6301\u7684\u56FA\u5B9A\u4F4D\u7F6E\uFF1A${column.fixed}`\n )\n }\n if (column.format && !columnFormats.has(column.format)) {\n push(\n diagnostics,\n `/table/columns/${index}/format`,\n 'column.format',\n `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${column.format}`\n )\n }\n if (column.dict && registry && !registry.dictionaries[column.dict]) {\n push(\n diagnostics,\n `/table/columns/${index}/dict`,\n 'registry.dictionary',\n `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${column.dict}`\n )\n }\n if (column.slot && registry && !registry.slots[column.slot]) {\n push(\n diagnostics,\n `/table/columns/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${column.slot}`\n )\n }\n })\n if (schema.detail !== undefined) {\n if (\n !schema.detail ||\n typeof schema.detail !== 'object' ||\n !Array.isArray(schema.detail.fields)\n ) {\n push(diagnostics, '/detail', 'detail.type', 'detail \u5FC5\u987B\u5305\u542B fields \u5BF9\u8C61\u6570\u7EC4')\n } else {\n schema.detail.fields.forEach((field, index) => {\n if (field.slot && registry && !registry.slots[field.slot])\n push(\n diagnostics,\n `/detail/fields/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`\n )\n })\n }\n }\n validateActions(\n schema.table?.actions,\n '/table/actions',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n validateActions(\n schema.toolbar,\n '/toolbar',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidCrudPageSchema(schema: CrudPageSchema, registry?: BestRegistry) {\n const result = validateCrudPageSchema(schema, registry)\n if (!result.valid) {\n const message = result.diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n')\n throw new Error(`Schema \u6821\u9A8C\u5931\u8D25\uFF1A\\n${message}`)\n }\n}\n", "import type {\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n CrudPageSchema,\n FieldSchema,\n PageActionSchema\n} from './schema'\nimport type { SchemaDiagnostic, SchemaValidationResult } from './validate'\nimport { validateCrudPageSchema } from './validate'\n\nconst builtInCapabilities = [\n 'builtin.effect.openCreate',\n 'builtin.effect.openDetail',\n 'builtin.effect.openEdit',\n 'builtin.effect.remove',\n 'builtin.effect.runAction',\n 'builtin.effect.slot',\n 'builtin.format.date',\n 'builtin.format.datetime',\n 'builtin.format.money',\n 'builtin.format.text',\n 'builtin.field.input',\n 'builtin.field.number',\n 'builtin.field.select',\n 'builtin.field.remoteSelect',\n 'builtin.field.date',\n 'builtin.field.dateRange',\n 'builtin.field.textarea',\n 'builtin.field.slot',\n 'builtin.field.repeatable'\n] as const\n\ntype JsonRecord = Record<string, unknown>\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction arrayOfRecords(value: unknown): JsonRecord[] | undefined {\n return Array.isArray(value) && value.every(isRecord) ? value : undefined\n}\n\nfunction diagnostic(path: string, code: string, message: string): SchemaDiagnostic {\n return { path, code, message }\n}\n\nfunction validateUnknownShape(candidate: unknown): SchemaDiagnostic[] {\n if (!isRecord(candidate)) return [diagnostic('', 'schema.type', 'Schema \u5FC5\u987B\u662F JSON \u5BF9\u8C61')]\n const diagnostics: SchemaDiagnostic[] = []\n if (!isRecord(candidate.dataSource))\n diagnostics.push(diagnostic('/dataSource', 'dataSource.type', 'dataSource \u5FC5\u987B\u662F\u5BF9\u8C61'))\n if (!isRecord(candidate.table))\n diagnostics.push(diagnostic('/table', 'table.type', 'table \u5FC5\u987B\u662F\u5BF9\u8C61'))\n for (const key of ['search', 'form'] as const) {\n if (candidate[key] !== undefined && !arrayOfRecords(candidate[key])) {\n diagnostics.push(diagnostic(`/${key}`, 'field.list', `${key} \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4`))\n }\n }\n if (isRecord(candidate.table)) {\n if (!arrayOfRecords(candidate.table.columns)) {\n diagnostics.push(diagnostic('/table/columns', 'column.list', 'columns \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n if (candidate.table.actions !== undefined && !arrayOfRecords(candidate.table.actions)) {\n diagnostics.push(diagnostic('/table/actions', 'action.list', 'actions \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n }\n if (candidate.toolbar !== undefined && !arrayOfRecords(candidate.toolbar)) {\n diagnostics.push(diagnostic('/toolbar', 'action.list', 'toolbar \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n return diagnostics\n}\n\nfunction toRuntimeSchema(candidate: JsonRecord): CrudPageSchema {\n return {\n $schema: candidate.$schema as typeof CRUD_SCHEMA_ID,\n version: candidate.version as typeof CRUD_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'crud',\n title: candidate.title as string,\n dataSource: candidate.dataSource as CrudPageSchema['dataSource'],\n search: candidate.search as FieldSchema[] | undefined,\n searchMode: candidate.searchMode as CrudPageSchema['searchMode'],\n form: candidate.form as FieldSchema[] | undefined,\n table: candidate.table as CrudPageSchema['table'],\n detail: candidate.detail as CrudPageSchema['detail'],\n toolbar: candidate.toolbar as PageActionSchema[] | undefined,\n meta: candidate.meta as CrudPageSchema['meta']\n }\n}\n\n/**\n * Server-safe development entry. It accepts unknown JSON from CLI/MCP before delegating to the\n * runtime validator, so untrusted candidates cannot trigger assumptions in typed runtime code.\n */\nexport function validateUnknownCrudPageSchema(candidate: unknown): SchemaValidationResult {\n const shapeDiagnostics = validateUnknownShape(candidate)\n if (shapeDiagnostics.length || !isRecord(candidate)) {\n return { valid: false, diagnostics: shapeDiagnostics }\n }\n return validateCrudPageSchema(toRuntimeSchema(candidate))\n}\n\n/** Serializable capabilities supplied by the current runtime without application Manifest entries. */\nexport function getBuiltinCapabilities(): string[] {\n return [...builtInCapabilities]\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.css CHANGED
@@ -1,16 +1,67 @@
1
+ /* src/ui/BestSearch.module.less */
2
+ .best-lowcode-search {
3
+ margin-bottom: 16px;
4
+ padding: 16px;
5
+ background: #fff;
6
+ border: 1px solid #f0f0f0;
7
+ border-radius: 8px;
8
+ }
9
+ .best-lowcode-search .ant-form-item {
10
+ margin-bottom: 16px;
11
+ }
12
+ .best-lowcode-search .ant-form-item-label > label {
13
+ color: rgba(0, 0, 0, 0.88);
14
+ font-size: 14px;
15
+ }
16
+ .best-lowcode-search .ant-form-item-control-input {
17
+ min-height: 32px;
18
+ }
19
+
1
20
  /* src/ui/BestTable.module.less */
2
- .root {
3
- :global(.ant-pro-card-body) {
4
- padding: 12px;
5
- }
6
- :global(.ant-pro-query-filter-actions .ant-form-item-label) {
7
- display: none;
8
- }
9
- :global(.ant-pro-query-filter-actions) {
10
- height: 100%;
11
- display: flex;
12
- flex-direction: column;
13
- justify-content: flex-end;
14
- }
21
+ .best-lowcode-table .ant-table-wrapper {
22
+ border: 1px solid #f0f0f0;
23
+ border-radius: 4px;
24
+ overflow: hidden;
25
+ }
26
+ .best-lowcode-table .ant-table-wrapper .ant-table.ant-table-medium .ant-table-thead > tr > th {
27
+ background: #fafafa;
28
+ color: rgba(0, 0, 0, 0.88);
29
+ font-weight: 600;
30
+ white-space: nowrap !important;
31
+ padding: 6px 16px;
32
+ line-height: 28px;
33
+ border-bottom: 0;
34
+ box-shadow: inset 0 -1px #f0f0f0;
35
+ }
36
+ .best-lowcode-table .ant-table-wrapper .ant-table.ant-table-medium .ant-table-tbody > tr > td.ant-table-cell {
37
+ padding: 6px 16px;
38
+ line-height: 28px;
39
+ height: 40px;
40
+ box-sizing: border-box;
41
+ white-space: normal;
42
+ overflow-wrap: break-word;
43
+ border-bottom: 0;
44
+ box-shadow: inset 0 -1px #f0f0f0;
45
+ }
46
+ .best-lowcode-table .ant-table-tbody > tr > td .ant-btn {
47
+ height: 28px;
48
+ min-height: 28px;
49
+ padding-block: 0;
50
+ line-height: 26px;
51
+ }
52
+ .best-lowcode-table .ant-table-cell-fix-right-first::after {
53
+ box-shadow: inset -8px 0 8px -8px rgba(0, 0, 0, 0.15);
54
+ }
55
+ .best-lowcode-table .ant-pro-card-body {
56
+ padding: 12px;
57
+ }
58
+ .best-lowcode-table .ant-pro-query-filter-actions .ant-form-item-label {
59
+ display: none;
60
+ }
61
+ .best-lowcode-table .ant-pro-query-filter-actions {
62
+ height: 100%;
63
+ display: flex;
64
+ flex-direction: column;
65
+ justify-content: flex-end;
15
66
  }
16
67
  /*# sourceMappingURL=index.css.map */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/ui/BestTable.module.less"],
4
- "sourcesContent": [".root {\n :global(.ant-pro-card-body) {\n padding: 12px;\n }\n\n :global(.ant-pro-query-filter-actions .ant-form-item-label) {\n display: none;\n }\n\n :global(.ant-pro-query-filter-actions) {\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n }\n}\n"],
5
- "mappings": ";AAAA,CAAC;AACC,UAAQ,CAAC;AACP,aAAS;AACX;AAEA,UAAQ,CAAC,6BAA6B,CAAC;AACrC,aAAS;AACX;AAEA,UAAQ,CAJC;AAKP,YAAQ;AACR,aAAS;AACT,oBAAgB;AAChB,qBAAiB;AACnB;AACF;",
3
+ "sources": ["../src/ui/BestSearch.module.less", "../src/ui/BestTable.module.less"],
4
+ "sourcesContent": [".best-lowcode-search {\n margin-bottom: 16px;\n padding: 16px;\n background: #fff;\n border: 1px solid #f0f0f0;\n border-radius: 8px;\n}\n\n.best-lowcode-search .ant-form-item {\n margin-bottom: 16px;\n}\n\n.best-lowcode-search .ant-form-item-label > label {\n color: rgba(0, 0, 0, 0.88);\n font-size: 14px;\n}\n\n.best-lowcode-search .ant-form-item-control-input {\n min-height: 32px;\n}\n", ".best-lowcode-table .ant-table-wrapper {\n border: 1px solid #f0f0f0;\n border-radius: 4px;\n overflow: hidden;\n}\n\n.best-lowcode-table .ant-table-wrapper .ant-table.ant-table-medium .ant-table-thead > tr > th {\n background: #fafafa;\n color: rgba(0, 0, 0, 0.88);\n font-weight: 600;\n white-space: nowrap !important;\n padding: 6px 16px;\n line-height: 28px;\n border-bottom: 0;\n box-shadow: inset 0 -1px #f0f0f0;\n}\n\n.best-lowcode-table .ant-table-wrapper .ant-table.ant-table-medium .ant-table-tbody > tr > td.ant-table-cell {\n padding: 6px 16px;\n line-height: 28px;\n height: 40px;\n box-sizing: border-box;\n white-space: normal;\n overflow-wrap: break-word;\n border-bottom: 0;\n box-shadow: inset 0 -1px #f0f0f0;\n}\n\n/* Keep action controls from increasing the table row beyond the compact 40px rhythm. */\n.best-lowcode-table .ant-table-tbody > tr > td .ant-btn {\n height: 28px;\n min-height: 28px;\n padding-block: 0;\n line-height: 26px;\n}\n\n.best-lowcode-table .ant-table-cell-fix-right-first::after {\n box-shadow: inset -8px 0 8px -8px rgba(0, 0, 0, 0.15);\n}\n\n.best-lowcode-table .ant-pro-card-body {\n padding: 12px;\n}\n\n.best-lowcode-table .ant-pro-query-filter-actions .ant-form-item-label {\n display: none;\n}\n\n.best-lowcode-table .ant-pro-query-filter-actions {\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n}\n"],
5
+ "mappings": ";AAAA,CAAC;AACC,iBAAe;AACf,WAAS;AACT,cAAY;AACZ,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACjB;AAEA,CARC,oBAQoB,CAAC;AACpB,iBAAe;AACjB;AAEA,CAZC,oBAYoB,CAAC,oBAAoB,EAAE;AAC1C,SAAO,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACrB,aAAW;AACb;AAEA,CAjBC,oBAiBoB,CAAC;AACpB,cAAY;AACd;;;ACnBA,CAAC,mBAAmB,CAAC;AACjB,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,YAAU;AACd;AAEA,CANC,mBAMmB,CANC,kBAMkB,CAAC,SAAS,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,GAAG,EAAE;AACvF,cAAY;AACZ,SAAO,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACrB,eAAa;AACb,eAAa;AACb,WAAS,IAAI;AACb,eAAa;AACb,iBAAe;AACf,cAAY,MAAM,EAAE,KAAK;AAC7B;AAEA,CAjBC,mBAiBmB,CAjBC,kBAiBkB,CAXC,SAWS,CAXC,iBAWiB,CAAC,gBAAgB,EAAE,GAAG,EAAE,EAAE,CAAC;AAC1F,WAAS,IAAI;AACb,eAAa;AACb,UAAQ;AACR,cAAY;AACZ,eAAa;AACb,iBAAe;AACf,iBAAe;AACf,cAAY,MAAM,EAAE,KAAK;AAC7B;AAGA,CA7BC,mBA6BmB,CAZgD,gBAY/B,EAAE,GAAG,EAAE,GAAG,CAAC;AAC5C,UAAQ;AACR,cAAY;AACZ,iBAAe;AACf,eAAa;AACjB;AAEA,CApCC,mBAoCmB,CAAC,8BAA8B;AAC/C,cAAY,MAAM,KAAK,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACpD;AAEA,CAxCC,mBAwCmB,CAAC;AACjB,WAAS;AACb;AAEA,CA5CC,mBA4CmB,CAAC,6BAA6B,CAAC;AAC/C,WAAS;AACb;AAEA,CAhDC,mBAgDmB,CAJC;AAKjB,UAAQ;AACR,WAAS;AACT,kBAAgB;AAChB,mBAAiB;AACrB;",
6
6
  "names": []
7
7
  }
package/dist/index.js CHANGED
@@ -57,15 +57,34 @@ var defaultTheme = {
57
57
  }
58
58
  };
59
59
  var BestRuntimeContext = createContext(emptyRegistry);
60
- function createBestRegistry(registry = {}) {
61
- return {
62
- listServices: registry.listServices ?? {},
63
- services: registry.services ?? {},
64
- dictionaries: registry.dictionaries ?? {},
65
- actions: registry.actions ?? {},
66
- slots: registry.slots ?? {},
67
- access: registry.access ?? emptyRegistry.access
60
+ function composeBestRegistry(...layers) {
61
+ const result = {
62
+ listServices: {},
63
+ services: {},
64
+ dictionaries: {},
65
+ actions: {},
66
+ slots: {},
67
+ access: emptyRegistry.access
68
68
  };
69
+ const groups = ["listServices", "services", "dictionaries", "actions", "slots"];
70
+ for (const layer of layers) {
71
+ for (const group of groups) {
72
+ for (const [key, value] of Object.entries(layer[group] ?? {})) {
73
+ if (Object.hasOwn(result[group], key)) {
74
+ throw new Error(`Registry key \u91CD\u590D\uFF1A${group}.${key}`);
75
+ }
76
+ result[group][key] = value;
77
+ }
78
+ }
79
+ if (layer.access) {
80
+ const previousAccess = result.access;
81
+ result.access = (key) => previousAccess(key) && layer.access?.(key) !== false;
82
+ }
83
+ }
84
+ return result;
85
+ }
86
+ function createBestRegistry(registry = {}) {
87
+ return composeBestRegistry(registry);
69
88
  }
70
89
  function BestProvider({ children, registry, theme }) {
71
90
  const value = useMemo(() => createBestRegistry(registry), [registry]);
@@ -309,12 +328,7 @@ function FormControl({
309
328
  {
310
329
  ...controlProps,
311
330
  value,
312
- onChange: (nextValue) => {
313
- onChange?.(nextValue);
314
- const fieldPath = namePath ?? field.field;
315
- form.setFieldValue(fieldPath, nextValue);
316
- void form.validateFields([fieldPath]).catch(() => void 0);
317
- },
331
+ onChange,
318
332
  disabled: field.disabled,
319
333
  placeholder: field.placeholder,
320
334
  style: { width: "100%" }
@@ -523,18 +537,23 @@ function FormFields({ fields, form, initialValues, mode = "create" }) {
523
537
  }) });
524
538
  }
525
539
  function toAntRules(rules) {
526
- return rules?.map((rule) => ({
527
- required: rule.required,
528
- type: rule.type === "string" ? void 0 : rule.type,
529
- min: rule.min ?? rule.minLength,
530
- max: rule.max ?? rule.maxLength,
531
- pattern: safeRegExp(rule.pattern),
532
- message: rule.message,
533
- validator: rule.type === "integer" ? async (_, value) => {
534
- if (value === void 0 || value === null || value === "") return;
535
- if (!Number.isInteger(Number(value))) throw new Error(rule.message ?? "\u8BF7\u8F93\u5165\u6574\u6570");
536
- } : void 0
537
- }));
540
+ return rules?.map(
541
+ (rule) => Object.fromEntries(
542
+ Object.entries({
543
+ required: rule.required,
544
+ type: rule.type === "string" ? void 0 : rule.type,
545
+ min: rule.min ?? rule.minLength,
546
+ max: rule.max ?? rule.maxLength,
547
+ pattern: safeRegExp(rule.pattern),
548
+ message: rule.message,
549
+ validator: rule.type === "integer" ? async (_, value) => {
550
+ if (value === void 0 || value === null || value === "") return;
551
+ if (!Number.isInteger(Number(value)))
552
+ throw new Error(rule.message ?? "\u8BF7\u8F93\u5165\u6574\u6570");
553
+ } : void 0
554
+ }).filter(([, value]) => value !== void 0)
555
+ )
556
+ );
538
557
  }
539
558
  function safeRegExp(pattern) {
540
559
  if (!pattern) return void 0;
@@ -993,7 +1012,7 @@ function BestSearchBody({
993
1012
  layout: "vertical",
994
1013
  onFinish: (values) => onSearch(values),
995
1014
  onValuesChange: (_, values) => onChange?.(values),
996
- style: { marginBottom: 16 },
1015
+ className: "best-lowcode-search",
997
1016
  children: /* @__PURE__ */ jsxs3(Row, { gutter: 16, align: "bottom", children: [
998
1017
  fields.filter((field) => !field.hidden).map((field) => /* @__PURE__ */ jsx8(Col, { span: field.span ?? 6, children: /* @__PURE__ */ jsx8(Form2.Item, { label: field.label, name: field.field, rules: toAntRules(field.rules), children: /* @__PURE__ */ jsx8(FieldControl, { field }) }) }, field.field)),
999
1018
  /* @__PURE__ */ jsx8(Col, { children: /* @__PURE__ */ jsxs3(Form2.Item, { children: [
@@ -1002,10 +1021,10 @@ function BestSearchBody({
1002
1021
  Button3,
1003
1022
  {
1004
1023
  onClick: () => {
1005
- syncValues(form, {}, fields);
1006
- valueSignatureRef.current = JSON.stringify({});
1007
- onChange?.({});
1008
- onReset?.();
1024
+ syncValues(form, initialValues, fields);
1025
+ valueSignatureRef.current = JSON.stringify(initialValues);
1026
+ onChange?.(initialValues);
1027
+ onReset?.(initialValues);
1009
1028
  },
1010
1029
  style: { marginInlineStart: 8 },
1011
1030
  children: "\u91CD\u7F6E"
@@ -1035,11 +1054,6 @@ function BestError({ description = "\u52A0\u8F7D\u5931\u8D25" }) {
1035
1054
  import {
1036
1055
  ProTable
1037
1056
  } from "@ant-design/pro-components";
1038
-
1039
- // src/ui/BestTable.module.less
1040
- var BestTable_module_default = {};
1041
-
1042
- // src/ui/BestTable.tsx
1043
1057
  import { jsx as jsx10 } from "react/jsx-runtime";
1044
1058
  var defaultSearch = {
1045
1059
  layout: "vertical",
@@ -1064,7 +1078,7 @@ function BestTable({
1064
1078
  ProTable,
1065
1079
  {
1066
1080
  ...props,
1067
- className: [BestTable_module_default.root, className].filter(Boolean).join(" "),
1081
+ className: ["best-lowcode-table", className].filter(Boolean).join(" "),
1068
1082
  columns,
1069
1083
  options: false,
1070
1084
  search: mergeSearch(defaultSearch, search),
@@ -1357,6 +1371,14 @@ function validateCrudPageSchema(schema, registry) {
1357
1371
  if (!schema.table?.columns?.length)
1358
1372
  push(diagnostics, "/table/columns", "table.columns", "\u81F3\u5C11\u9700\u8981\u4E00\u5217");
1359
1373
  schema.table?.columns?.forEach((column, index) => {
1374
+ if (column.fixed !== void 0 && column.fixed !== "left" && column.fixed !== "right") {
1375
+ push(
1376
+ diagnostics,
1377
+ `/table/columns/${index}/fixed`,
1378
+ "column.fixed",
1379
+ `\u4E0D\u652F\u6301\u7684\u56FA\u5B9A\u4F4D\u7F6E\uFF1A${column.fixed}`
1380
+ );
1381
+ }
1360
1382
  if (column.format && !columnFormats.has(column.format)) {
1361
1383
  push(
1362
1384
  diagnostics,
@@ -1519,6 +1541,7 @@ function toTableColumn(column, dictionary, slots) {
1519
1541
  search: false,
1520
1542
  title: column.title,
1521
1543
  width: column.width,
1544
+ fixed: column.fixed,
1522
1545
  valueEnum,
1523
1546
  renderText: column.format && !slot && !column.dict ? (value) => formatCrudValue(value, column.format) : void 0,
1524
1547
  render: slot ? (_value, record) => slots[slot]?.({
@@ -1691,9 +1714,12 @@ function BestCrudPage({ adapter, className, schema }) {
1691
1714
  });
1692
1715
  configuredColumns.push(...searchColumns.values());
1693
1716
  if (!schema.table.actions?.length) return configuredColumns;
1717
+ const actionColumnWidth = Math.max(160, schema.table.actions.length * 80 + 32);
1694
1718
  configuredColumns.push({
1695
1719
  title: "\u64CD\u4F5C",
1696
1720
  valueType: "option",
1721
+ fixed: "right",
1722
+ width: actionColumnWidth,
1697
1723
  render: (_, record) => schema.table.actions?.map((action) => /* @__PURE__ */ jsx11(ActionButton, { action, record, onExecute: handleAction }, action.id))
1698
1724
  });
1699
1725
  return configuredColumns;
@@ -1784,10 +1810,10 @@ function BestCrudPage({ adapter, className, schema }) {
1784
1810
  fields: searchFields,
1785
1811
  value: query,
1786
1812
  defaultValues: searchDefaultValues,
1787
- onReset: () => {
1788
- queryRef.current = {};
1813
+ onReset: (values) => {
1814
+ queryRef.current = values;
1789
1815
  queryStateRef.current = { ...queryStateRef.current, userTouched: true };
1790
- setQuery({});
1816
+ setQuery(values);
1791
1817
  actionRef.current?.reload();
1792
1818
  },
1793
1819
  onSearch: (values) => {
@@ -1858,7 +1884,7 @@ function BestCrudPage({ adapter, className, schema }) {
1858
1884
  return /* @__PURE__ */ jsx11(
1859
1885
  Button4,
1860
1886
  {
1861
- type: "link",
1887
+ type: action.buttonType ?? "link",
1862
1888
  onClick: () => {
1863
1889
  void onExecute(action, record);
1864
1890
  },
@@ -1886,6 +1912,7 @@ export {
1886
1912
  CRUD_SCHEMA_ID,
1887
1913
  CRUD_SCHEMA_VERSION,
1888
1914
  assertValidCrudPageSchema,
1915
+ composeBestRegistry,
1889
1916
  createBestCrudAdapter,
1890
1917
  createBestRegistry,
1891
1918
  normalizeBestValues,