@panneau/core 5.0.0-alpha.1 → 5.0.0-alpha.2
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/README.md +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/plugins.d.ts +10 -9
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +19 -1
- package/dist/plugins.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -30,6 +30,8 @@ function EditPage({ item, onSave }) {
|
|
|
30
30
|
|
|
31
31
|
`definePlugin()` declares what a plugin adds, keyed by the names the definition uses: `fields`, `displays`, `listLayouts`, `actions` (handlers of `client` actions), `pages`, `widgets`, `components` (layout nodes), `locales` and `themes`.
|
|
32
32
|
|
|
33
|
+
`resolveTheme(definition.theme, registry.themes)` returns the theme of the admin: the themes of plugins that the definition's theme `extends`, by id, then its own tokens, tones and variants. `Theme` is the theme of `@panneau/ui` as plain data, the `Theme` schema of `@panneau/protocol`.
|
|
34
|
+
|
|
33
35
|
`PanneauProvider` takes plugins, the definition and a router. Nested providers add their plugins to those of their parent, and later plugins override earlier ones, so a project can replace a built-in field. `usePlugins()` returns the merged registry, and `loadMessages(registry, locale)` the merged messages of a locale.
|
|
34
36
|
|
|
35
37
|
## Definition engine
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { selectErrorCount, selectErrors, selectValue, selectVisible } from './fo
|
|
|
9
9
|
export { type FormStore, createLocalStore } from './form/store';
|
|
10
10
|
export { type List, type ListDefaults, type ListOptions, type ListSelection, type ListState, createList, } from './list/list';
|
|
11
11
|
export { type MemoryRouter, type Router, createHistoryRouter, createMemoryRouter, } from './list/router';
|
|
12
|
-
export { type Messages, type MessagesLoader, type PanneauPlugin, type PluginComponent, type PluginComponentKind, type PluginRegistry, type Theme, createPluginRegistry, definePlugin, loadMessages, } from './plugins';
|
|
12
|
+
export { type Messages, type MessagesLoader, type PanneauPlugin, type PluginComponent, type PluginComponentKind, type PluginRegistry, type Theme, createPluginRegistry, definePlugin, loadMessages, resolveTheme, } from './plugins';
|
|
13
13
|
export { PanneauProvider, type PanneauContextValue, type PanneauProviderProps, usePanneau, usePlugins, useResource, } from './react/provider';
|
|
14
14
|
export { type UseFormFieldResult, type UseFormResult, useForm, useFormField, } from './react/useForm';
|
|
15
15
|
export { type UseListResult, useList } from './react/useList';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,GAAG,EACH,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,mBAAmB,EACnB,aAAa,EACb,WAAW,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,YAAY,EACZ,WAAW,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,YAAY,EACZ,eAAe,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACH,KAAK,IAAI,EACT,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,UAAU,EACV,gBAAgB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAE,KAAK,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EACH,KAAK,IAAI,EACT,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,UAAU,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,KAAK,EACV,oBAAoB,EACpB,YAAY,EACZ,YAAY,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACH,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,UAAU,EACV,UAAU,EACV,WAAW,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,OAAO,EACP,YAAY,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,aAAa,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,KAAK,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,GAAG,EACH,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,mBAAmB,EACnB,aAAa,EACb,WAAW,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,YAAY,EACZ,WAAW,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,YAAY,EACZ,eAAe,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACH,KAAK,IAAI,EACT,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,UAAU,EACV,gBAAgB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAE,KAAK,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EACH,KAAK,IAAI,EACT,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,UAAU,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,KAAK,EACV,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,YAAY,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACH,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,UAAU,EACV,UAAU,EACV,WAAW,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,OAAO,EACP,YAAY,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,aAAa,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,KAAK,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,8 +10,8 @@ import { createLocalStore } from "./form/store.js";
|
|
|
10
10
|
import { createForm, getDefaultValues } from "./form/form.js";
|
|
11
11
|
import { createList } from "./list/list.js";
|
|
12
12
|
import { createHistoryRouter, createMemoryRouter } from "./list/router.js";
|
|
13
|
-
import { createPluginRegistry, definePlugin, loadMessages } from "./plugins.js";
|
|
13
|
+
import { createPluginRegistry, definePlugin, loadMessages, resolveTheme } from "./plugins.js";
|
|
14
14
|
import { PanneauProvider, usePanneau, usePlugins, useResource } from "./react/provider.js";
|
|
15
15
|
import { useForm, useFormField } from "./react/useForm.js";
|
|
16
16
|
import { useList } from "./react/useList.js";
|
|
17
|
-
export { DEFAULT_PER_PAGE, PanneauProvider, can, canRunAction, createForm, createHistoryRouter, createList, createLocalStore, createMemoryRouter, createPluginRegistry, definePlugin, findResource, formatRuleFailure, getActionPlacements, getDefaultValues, getItemValues, getLayoutFieldNames, getProblem, groupActions, isActionAllowedOn, isEqual, isItem, loadMessages, partitionByAction, resolveFields, resolveForm, resolveList, resolveResource, selectErrorCount, selectErrors, selectValue, selectVisible, setValue, useForm, useFormField, useList, usePanneau, usePlugins, useResource };
|
|
17
|
+
export { DEFAULT_PER_PAGE, PanneauProvider, can, canRunAction, createForm, createHistoryRouter, createList, createLocalStore, createMemoryRouter, createPluginRegistry, definePlugin, findResource, formatRuleFailure, getActionPlacements, getDefaultValues, getItemValues, getLayoutFieldNames, getProblem, groupActions, isActionAllowedOn, isEqual, isItem, loadMessages, partitionByAction, resolveFields, resolveForm, resolveList, resolveResource, resolveTheme, selectErrorCount, selectErrors, selectValue, selectVisible, setValue, useForm, useFormField, useList, usePanneau, usePlugins, useResource };
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { ComponentType } from 'react';
|
|
2
|
+
import type { DefinitionTheme, Theme } from '@panneau/protocol';
|
|
3
|
+
/** A theme of `@panneau/ui`, as plain data: what plugins register (decision 0024). */
|
|
4
|
+
export type { Theme };
|
|
2
5
|
/**
|
|
3
6
|
* A component provided by a plugin. Its props are defined by the package that renders it (fields,
|
|
4
7
|
* lists, app), so the registry stores it as given.
|
|
@@ -10,14 +13,6 @@ export type Messages = Record<string, string>;
|
|
|
10
13
|
export type MessagesLoader = Messages | (() => Promise<Messages | {
|
|
11
14
|
default: Messages;
|
|
12
15
|
}>);
|
|
13
|
-
/** A theme: design tokens (CSS variables without `--`), with optional dark scheme overrides. */
|
|
14
|
-
export interface Theme {
|
|
15
|
-
label?: string;
|
|
16
|
-
/** Tokens of the light scheme, or of both schemes without `dark`: `{ 'panneau-color-accent': '#05f' }`. */
|
|
17
|
-
tokens: Record<string, string>;
|
|
18
|
-
/** Tokens that change in the dark scheme. */
|
|
19
|
-
dark?: Record<string, string>;
|
|
20
|
-
}
|
|
21
16
|
/** What a plugin adds to Panneau. Every part is keyed by the name the definition uses. */
|
|
22
17
|
export interface PanneauPlugin {
|
|
23
18
|
/** Unique id of the plugin. */
|
|
@@ -38,7 +33,7 @@ export interface PanneauPlugin {
|
|
|
38
33
|
components?: Record<string, PluginComponent>;
|
|
39
34
|
/** UI messages, by locale. Messages of later plugins override earlier ones. */
|
|
40
35
|
locales?: Record<string, MessagesLoader>;
|
|
41
|
-
/** Themes, by id. */
|
|
36
|
+
/** Themes, by id, that the theme of the definition can extend. */
|
|
42
37
|
themes?: Record<string, Theme>;
|
|
43
38
|
}
|
|
44
39
|
/** The kinds of components a plugin can provide. */
|
|
@@ -70,4 +65,10 @@ export declare function createPluginRegistry(plugins: readonly PanneauPlugin[]):
|
|
|
70
65
|
* regional locale (`fr-CA`) falls back to its language (`fr`) for missing messages.
|
|
71
66
|
*/
|
|
72
67
|
export declare function loadMessages(registry: PluginRegistry, locale: string): Promise<Messages>;
|
|
68
|
+
/**
|
|
69
|
+
* The theme of the admin: the themes of plugins that the definition's theme extends, in order, then
|
|
70
|
+
* the definition's own tokens, tones and variants. An id no plugin registers is skipped, with a
|
|
71
|
+
* warning.
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveTheme(theme: DefinitionTheme | undefined, themes: ReadonlyMap<string, Theme>): Theme;
|
|
73
74
|
//# sourceMappingURL=plugins.d.ts.map
|
package/dist/plugins.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C;;;GAGG;AAEH,MAAM,MAAM,eAAe,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;AAEjD,oDAAoD;AACpD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9C,kFAAkF;AAClF,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,CAAC,MAAM,OAAO,CAAC,QAAQ,GAAG;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC,CAAC;AAE1F,
|
|
1
|
+
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}
|
package/dist/plugins.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mergeThemes } from "@panneau/protocol/runtime";
|
|
1
2
|
//#region src/plugins.ts
|
|
2
3
|
var COMPONENT_KINDS = [
|
|
3
4
|
"fields",
|
|
@@ -48,7 +49,24 @@ async function loadMessages(registry, locale) {
|
|
|
48
49
|
}));
|
|
49
50
|
return Object.assign({}, ...loaded);
|
|
50
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The theme of the admin: the themes of plugins that the definition's theme extends, in order, then
|
|
54
|
+
* the definition's own tokens, tones and variants. An id no plugin registers is skipped, with a
|
|
55
|
+
* warning.
|
|
56
|
+
*/
|
|
57
|
+
function resolveTheme(theme, themes) {
|
|
58
|
+
const { colorScheme: _colorScheme, extends: ids, ...own } = theme ?? {};
|
|
59
|
+
const extended = (typeof ids === "string" ? [ids] : ids ?? []).flatMap((id) => {
|
|
60
|
+
const found = themes.get(id);
|
|
61
|
+
if (found === void 0) {
|
|
62
|
+
console.warn(`[panneau] No plugin registers the theme "${id}".`);
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
return [found];
|
|
66
|
+
});
|
|
67
|
+
return mergeThemes(...extended, own);
|
|
68
|
+
}
|
|
51
69
|
//#endregion
|
|
52
|
-
export { createPluginRegistry, definePlugin, loadMessages };
|
|
70
|
+
export { createPluginRegistry, definePlugin, loadMessages, resolveTheme };
|
|
53
71
|
|
|
54
72
|
//# sourceMappingURL=plugins.js.map
|
package/dist/plugins.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.js","names":[],"sources":["../src/plugins.ts"],"sourcesContent":["import type { ComponentType } from 'react';\n\n/**\n * A component provided by a plugin. Its props are defined by the package that renders it (fields,\n * lists, app), so the registry stores it as given.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- see above\nexport type PluginComponent = ComponentType<any>;\n\n/** UI messages of a locale, keyed by message id. */\nexport type Messages = Record<string, string>;\n\n/** Messages, or a function that loads them (`() => import('./lang/fr.json')`). */\nexport type MessagesLoader = Messages | (() => Promise<Messages | { default: Messages }>);\n\n/**
|
|
1
|
+
{"version":3,"file":"plugins.js","names":[],"sources":["../src/plugins.ts"],"sourcesContent":["import type { ComponentType } from 'react';\n\nimport type { DefinitionTheme, Theme } from '@panneau/protocol';\nimport { mergeThemes } from '@panneau/protocol/runtime';\n\n/** A theme of `@panneau/ui`, as plain data: what plugins register (decision 0024). */\nexport type { Theme };\n\n/**\n * A component provided by a plugin. Its props are defined by the package that renders it (fields,\n * lists, app), so the registry stores it as given.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- see above\nexport type PluginComponent = ComponentType<any>;\n\n/** UI messages of a locale, keyed by message id. */\nexport type Messages = Record<string, string>;\n\n/** Messages, or a function that loads them (`() => import('./lang/fr.json')`). */\nexport type MessagesLoader = Messages | (() => Promise<Messages | { default: Messages }>);\n\n/** What a plugin adds to Panneau. Every part is keyed by the name the definition uses. */\nexport interface PanneauPlugin {\n /** Unique id of the plugin. */\n id: string;\n /** Field components, by field type (`text`, `page-slug`). */\n fields?: Record<string, PluginComponent>;\n /** Components that display a value in lists, by display (`date`, `page-slug`). */\n displays?: Record<string, PluginComponent>;\n /** List layouts, by id (`table`, `cards`). */\n listLayouts?: Record<string, PluginComponent>;\n /** Handlers of `client` actions, by the action's `component`. */\n actions?: Record<string, PluginComponent>;\n /** Pages, by component name (`dashboard`). */\n pages?: Record<string, PluginComponent>;\n /** Dashboard widgets, by widget type (`stat`). */\n widgets?: Record<string, PluginComponent>;\n /** Layout node components, for `component` nodes of form layouts. */\n components?: Record<string, PluginComponent>;\n /** UI messages, by locale. Messages of later plugins override earlier ones. */\n locales?: Record<string, MessagesLoader>;\n /** Themes, by id, that the theme of the definition can extend. */\n themes?: Record<string, Theme>;\n}\n\n/** The kinds of components a plugin can provide. */\nexport type PluginComponentKind =\n 'fields' | 'displays' | 'listLayouts' | 'actions' | 'pages' | 'widgets' | 'components';\n\nconst COMPONENT_KINDS: PluginComponentKind[] = [\n 'fields',\n 'displays',\n 'listLayouts',\n 'actions',\n 'pages',\n 'widgets',\n 'components',\n];\n\n/** Everything the plugins provide, merged. A later plugin overrides an earlier one. */\nexport interface PluginRegistry {\n /** The plugins, in order. */\n plugins: readonly PanneauPlugin[];\n fields: ReadonlyMap<string, PluginComponent>;\n displays: ReadonlyMap<string, PluginComponent>;\n listLayouts: ReadonlyMap<string, PluginComponent>;\n actions: ReadonlyMap<string, PluginComponent>;\n pages: ReadonlyMap<string, PluginComponent>;\n widgets: ReadonlyMap<string, PluginComponent>;\n components: ReadonlyMap<string, PluginComponent>;\n /** Message loaders of each locale, in plugin order. */\n locales: ReadonlyMap<string, readonly MessagesLoader[]>;\n themes: ReadonlyMap<string, Theme>;\n}\n\n/** Declares a plugin. It returns the plugin as is, with its type checked. */\nexport function definePlugin(plugin: PanneauPlugin): PanneauPlugin {\n return plugin;\n}\n\n/**\n * Merges plugins into a registry. Later plugins override the components and themes of earlier\n * ones, so a project can replace a built-in field. Plugin ids must be unique.\n */\nexport function createPluginRegistry(plugins: readonly PanneauPlugin[]): PluginRegistry {\n const ids = new Set<string>();\n plugins.forEach((plugin) => {\n if (ids.has(plugin.id)) {\n throw new Error(`Two plugins have the id \\`${plugin.id}\\`.`);\n }\n ids.add(plugin.id);\n });\n const components = Object.fromEntries(\n COMPONENT_KINDS.map((kind) => [\n kind,\n new Map(plugins.flatMap((plugin) => Object.entries(plugin[kind] ?? {}))),\n ]),\n ) as Record<PluginComponentKind, Map<string, PluginComponent>>;\n const locales = new Map<string, MessagesLoader[]>();\n plugins.forEach((plugin) =>\n Object.entries(plugin.locales ?? {}).forEach(([locale, loader]) => {\n locales.set(locale, [...(locales.get(locale) ?? []), loader]);\n }),\n );\n return {\n plugins: [...plugins],\n ...components,\n locales,\n themes: new Map(plugins.flatMap((plugin) => Object.entries(plugin.themes ?? {}))),\n };\n}\n\n/**\n * Loads the messages of a locale from every plugin that provides it, merged in plugin order. A\n * regional locale (`fr-CA`) falls back to its language (`fr`) for missing messages.\n */\nexport async function loadMessages(registry: PluginRegistry, locale: string): Promise<Messages> {\n const language = locale.split('-')[0] ?? locale;\n const loaders = [\n ...(language !== locale ? (registry.locales.get(language) ?? []) : []),\n ...(registry.locales.get(locale) ?? []),\n ];\n const loaded = await Promise.all(\n loaders.map(async (loader) => {\n if (typeof loader !== 'function') {\n return loader;\n }\n const result = await loader();\n return 'default' in result && typeof result.default === 'object'\n ? (result.default as Messages)\n : (result as Messages);\n }),\n );\n return Object.assign({}, ...loaded) as Messages;\n}\n\n/**\n * The theme of the admin: the themes of plugins that the definition's theme extends, in order, then\n * the definition's own tokens, tones and variants. An id no plugin registers is skipped, with a\n * warning.\n */\nexport function resolveTheme(\n theme: DefinitionTheme | undefined,\n themes: ReadonlyMap<string, Theme>,\n): Theme {\n const { colorScheme: _colorScheme, extends: ids, ...own } = theme ?? {};\n const extended = (typeof ids === 'string' ? [ids] : (ids ?? [])).flatMap((id) => {\n const found = themes.get(id);\n if (found === undefined) {\n console.warn(`[panneau] No plugin registers the theme \"${id}\".`);\n return [];\n }\n return [found];\n });\n return mergeThemes(...extended, own);\n}\n"],"mappings":";;AAiDA,IAAM,kBAAyC;CAC3C;CACA;CACA;CACA;CACA;CACA;CACA;AAAY;;AAoBhB,SAAgB,aAAa,QAAsC;CAC/D,OAAO;AACX;;;;;AAMA,SAAgB,qBAAqB,SAAmD;CACpF,MAAM,sBAAM,IAAI,IAAY;CAC5B,QAAQ,SAAS,WAAW;EACxB,IAAI,IAAI,IAAI,OAAO,EAAE,GACjB,MAAM,IAAI,MAAM,6BAA6B,OAAO,GAAE,IAAK;EAE/D,IAAI,IAAI,OAAO,EAAE;CACrB,CAAC;CACD,MAAM,aAAa,OAAO,YACtB,gBAAgB,KAAK,SAAS,CAC1B,MACA,IAAI,IAAI,QAAQ,SAAS,WAAW,OAAO,QAAQ,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAC3E,CACL;CACA,MAAM,0BAAU,IAAI,IAA8B;CAClD,QAAQ,SAAS,WACb,OAAO,QAAQ,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,YAAY;EAC/D,QAAQ,IAAI,QAAQ,CAAC,GAAI,QAAQ,IAAI,MAAM,KAAK,CAAA,GAAK,MAAM,CAAC;CAChE,CAAC,CACL;CACA,OAAO;EACH,SAAS,CAAC,GAAG,OAAO;EACpB,GAAG;EACH;EACA,QAAQ,IAAI,IAAI,QAAQ,SAAS,WAAW,OAAO,QAAQ,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;CACpF;AACJ;;;;;AAMA,eAAsB,aAAa,UAA0B,QAAmC;CAC5F,MAAM,WAAW,OAAO,MAAM,GAAG,CAAC,CAAC,MAAM;CACzC,MAAM,UAAU,CACZ,GAAI,aAAa,SAAU,SAAS,QAAQ,IAAI,QAAQ,KAAK,CAAA,IAAM,CAAA,GACnE,GAAI,SAAS,QAAQ,IAAI,MAAM,KAAK,CAAA,CAAG;CAE3C,MAAM,SAAS,MAAM,QAAQ,IACzB,QAAQ,IAAI,OAAO,WAAW;EAC1B,IAAI,OAAO,WAAW,YAClB,OAAO;EAEX,MAAM,SAAS,MAAM,OAAO;EAC5B,OAAO,aAAa,UAAU,OAAO,OAAO,YAAY,WACjD,OAAO,UACP;CACX,CAAC,CACL;CACA,OAAO,OAAO,OAAO,CAAC,GAAG,GAAG,MAAM;AACtC;;;;;;AAOA,SAAgB,aACZ,OACA,QACK;CACL,MAAM,EAAE,aAAa,cAAc,SAAS,KAAK,GAAG,QAAQ,SAAS,CAAC;CACtE,MAAM,YAAY,OAAO,QAAQ,WAAW,CAAC,GAAG,IAAK,OAAO,CAAA,EAAA,CAAK,SAAS,OAAO;EAC7E,MAAM,QAAQ,OAAO,IAAI,EAAE;EAC3B,IAAI,UAAU,KAAA,GAAW;GACrB,QAAQ,KAAK,4CAA4C,GAAE,GAAI;GAC/D,OAAO,CAAA;EACX;EACA,OAAO,CAAC,KAAK;CACjB,CAAC;CACD,OAAO,YAAY,GAAG,UAAU,GAAG;AACvC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panneau/core",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.2",
|
|
4
4
|
"description": "The engine of Panneau: plugin registry, definition to forms and lists, form and list state, with React hooks. No UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"react": "^19.2.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@panneau/protocol": "5.0.0-alpha.
|
|
36
|
+
"@panneau/protocol": "5.0.0-alpha.2"
|
|
37
37
|
}
|
|
38
38
|
}
|