mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-14 02:56:36 +00:00
feat(element-style): adopt hand-written customization blocks, and widen the font list
Nineteen plugins spell their style elements out longhand instead of declaring them -- football's block is 701 lines for seven elements -- and predate this system entirely. Core now recognises that shape, so they pick up the row-per-element editor and the real font picker on a core update rather than on a plugin release. Checked against every published schema: 21 plugins adopt, and the defaults of each still validate against the schema generated for it. Detection requires *every* field in a block to be one this system understands. A looser "has at least one style field" rule sweeps in baseball's `count`, which carries a text_color beside geometry that means nothing here. That distinction took three attempts to test: the first two assertions passed under both rules, because an over-eager rule leaves a fontless block looking untouched and only surfaces as an extra row in the editor. The hardcoded font enum is replaced rather than extended. Football lists five of the thirty-five installed fonts, which is why a font a user uploads can never appear in one. It is not a curated safe set -- it omits some twenty other faces that fit the declared size cap just as well -- it is the fonts that happened to exist when it was written. Widening it does need a guard, though, and not the one the schema already has: a bitmap font ignores font_size and renders at its size baked into the file, so `maximum: 16` cannot stop a 27px face. The picker now filters out fixed-size fonts taller than the element's own declared ceiling, which drops exactly the four that would overflow a 32px panel and keeps the other thirty. Per-mode overrides stay opt-in: core cannot invent a plugin's display modes, so `x-style-modes` remains the one line that unlocks them. Their layout half covers every positionable element rather than only those with a style block -- the two namespaces do not line up in a hand-written schema, and football positions six things (logos, timeouts, possession) that have no style block at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -174,6 +174,12 @@
|
||||
const xOptions = config['x-options'] || config['x_options'] || {};
|
||||
const placeholder = xOptions.placeholder || 'Select a font...';
|
||||
const filterTypes = xOptions.filterTypes || null; // e.g., ['ttf', 'bdf']
|
||||
// Bitmap (BDF) fonts render at the one size baked into the file
|
||||
// and ignore the size setting entirely, so a field that caps size
|
||||
// at 16 can still be handed a 27px face. maxFixedSize hides the
|
||||
// ones that cannot honour the cap, rather than offering a choice
|
||||
// that silently overflows the panel.
|
||||
const maxFixedSize = Number(xOptions.maxFixedSize) || null;
|
||||
const showPreview = xOptions.showPreview === true;
|
||||
const disabled = xOptions.disabled === true;
|
||||
const required = xOptions.required === true;
|
||||
@@ -204,6 +210,16 @@
|
||||
return filterTypes.some(t => t.toLowerCase() === fontType);
|
||||
});
|
||||
}
|
||||
if (maxFixedSize) {
|
||||
filteredFonts = filteredFonts.filter(font => {
|
||||
// A scalable face can always meet the cap.
|
||||
if (font.scalable !== false) { return true; }
|
||||
// An unknown native size is not evidence it is too
|
||||
// big; keep it rather than hiding a usable font.
|
||||
if (!font.native_size) { return true; }
|
||||
return font.native_size <= maxFixedSize;
|
||||
});
|
||||
}
|
||||
|
||||
// Build select HTML
|
||||
let html = `<div id="${fieldId}_widget" class="font-selector-widget" data-field-id="${fieldId}">`;
|
||||
|
||||
@@ -127,6 +127,27 @@
|
||||
|
||||
// ---- individual controls -------------------------------------------
|
||||
|
||||
/**
|
||||
* Fonts this field can actually honour.
|
||||
*
|
||||
* A bitmap (BDF) face renders at the one size baked into the file and
|
||||
* ignores the size setting, so an element that caps size at 16 can
|
||||
* still be handed a 27px face and overflow a 32px panel. The cap comes
|
||||
* from the element's own font_size.maximum, so this hides exactly the
|
||||
* faces that cannot meet the limit the plugin already declared --
|
||||
* rather than a list curated by hand, which is what these fields used
|
||||
* to carry and why an uploaded font could never appear in one.
|
||||
*/
|
||||
function usableFonts(fonts, maxFixedSize) {
|
||||
if (!maxFixedSize) { return fonts; }
|
||||
return fonts.filter(function (f) {
|
||||
if (f.scalable !== false) { return true; }
|
||||
// An unknown native size is not evidence it is too big.
|
||||
if (!f.nativeSize) { return true; }
|
||||
return f.nativeSize <= maxFixedSize;
|
||||
});
|
||||
}
|
||||
|
||||
function fontControl(name, current, fonts, optional, onChange) {
|
||||
var select = el('select', {
|
||||
name: name,
|
||||
@@ -334,7 +355,10 @@
|
||||
var types = Array.isArray(declared) ? declared : [declared];
|
||||
|
||||
if (opts.key === 'font' || prop['x-widget'] === 'font-selector') {
|
||||
return fontControl(opts.name, opts.current, opts.fonts,
|
||||
var xOptions = prop['x-options'] || prop['x_options'] || {};
|
||||
var cap = Number(xOptions.maxFixedSize) || opts.maxFixedSize || null;
|
||||
return fontControl(opts.name, opts.current,
|
||||
usableFonts(opts.fonts, cap),
|
||||
opts.optional, opts.onFontChange);
|
||||
}
|
||||
if (types.indexOf('boolean') !== -1) {
|
||||
@@ -411,6 +435,9 @@
|
||||
current: effective(value, path, prop, optional),
|
||||
optional: optional,
|
||||
fonts: opts.fonts,
|
||||
// The element's declared size ceiling is what a fixed-size
|
||||
// font has to fit under.
|
||||
maxFixedSize: (props.font_size || {}).maximum || null,
|
||||
onFontChange: function () { syncSize(fontSelect); }
|
||||
});
|
||||
if (col.key === 'font') { fontSelect = node; }
|
||||
|
||||
Reference in New Issue
Block a user