Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
> v0.4.1 ~ "Resource identity: pills, one-line identity cells, hover summaries and select options"
> v0.4.2 ~ "Restore the hidden state of tooltips and popovers in production builds"

---
## Highlights

- **Resource descriptor registry** — `utils/resource-registry` stores one descriptor per kind of record (title, identifier, image, status, badges, facts, how it opens) in the shared `universe/registry-service`, so the host and every engine read one set. `resolveResourceKey` accepts a record, an identity stub, a model name or alias, a `prefix:key` string, a PHP class name or a polymorphic type; `openResource` unwraps proxies and stubs, swaps a subtype for its canonical record and never throws. The `resource-type`, `resource-component` and `resource-relation` helpers and the `resource-registry` service expose it to templates and engines.
- **Resource::Pill, Resource::Summary, Resource::HoverCard** — a descriptor-driven pill that opens its record and shows a compact summary card on hover (photo or icon, name and identifier, status and online state, a handful of facts and one View action). The card is lazy: nothing renders until the pointer has rested on the target, and it hydrates only then.
- **Table::Cell::Identity** — a one-line identity cell: a small image with the status dot, the name and up to two inline badges, no status badge. It opens the record on click, disables on `column.permission`, and never fires the row action as well.
- **Resource::SelectOption** — the option row for record pickers, with a compact variant for the closed trigger. `filter/model` renders options through it and the new `filter/model-multiple` filter selects several records.
- **Core resource families** — pills, summaries, select options and identity cells for user, company, group, role, file and category, registered by an instance-initializer in the host.
- **Fixes** — `Attach::Popover` applies `@class`, keeps an interactive popover enterable while shown, follows later changes to `@isShown` and removes its listeners on destroy; `Attach::Tooltip` forwards `hideDelay`, `hideDuration`, `@class`, `@style`, `floatingTarget`, `floatingContainer` and `onChange`; `Pill` renders a static span when it has nothing to do and hands its tooltip component the resource; `MultiSelect` forwards `@selectedItemComponent`, `@searchField` and `@searchPlaceholder`; `table/cell/resource-identity` no longer renders an empty meta row.
- **Dummy app** — `@fleetbase/ember-core` is declared as a dependency so the components that import it can render in tests.
- **Fix: every tooltip and popover rendered visible in production** — v0.4.1 started forwarding the host's browser targets to `postcss-preset-env`, which then skipped flattening CSS nesting for browsers that support it natively. The attacher styles that hold an `Attach::Tooltip` or `Attach::Popover` at `opacity: 0` until it is shown are written nested, and ember-cli's production minifier (clean-css) cannot parse nesting: it emitted those rules as top-level `& > …` selectors that match nothing, so every attachment appeared at full opacity without a hover. Development builds were unaffected because the browser parsed the nested block itself. The preset now always flattens nesting, whatever the targets.
- **Regression test** — `tests/node/postcss-build-test.cjs` compiles the attacher styles for the console's targets, asserts the flat hide rule is present, and minifies the result with clean-css to prove it survives a production build.

---
## Need help?
Expand Down
8 changes: 6 additions & 2 deletions lib/postcss-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ module.exports = function buildPostcssOptions(browsers) {
}),
postcssMixins,
// Ember CLI's targets are not automatically forwarded to an
// instantiated preset. Avoid polyfilling selectors the host supports.
postcssPresetEnv({ stage: 1, browsers, autoprefixer: false }),
// instantiated preset. Avoid polyfilling selectors the host supports,
// but always flatten nesting: the addon styles nest freely, and the
// production minifier (clean-css) cannot parse native nesting, so an
// unflattened block loses every nested rule, including the ones
// that hide a tooltip until it is shown.
postcssPresetEnv({ stage: 1, browsers, autoprefixer: false, features: { 'nesting-rules': true } }),
postcssEach,
tailwind(tailwindConfigPath),
autoprefixer({ overrideBrowserslist: browsers }),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fleetbase/ember-ui",
"version": "0.4.1",
"version": "0.4.2",
"description": "Fleetbase UI provides all the interface components, helpers, services and utilities for building a Fleetbase extension into the Console.",
"keywords": [
"fleetbase-ui",
Expand Down
18 changes: 18 additions & 0 deletions tests/node/postcss-build-test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,21 @@ test('JavaScript utility changes invalidate the Broccoli CSS cache', async () =>
fs.rmSync(directory, { recursive: true, force: true });
}
});

test('tooltip hide rules are flattened for modern targets and survive the production minifier', async () => {
// postcss-preset-env skips nesting for browsers that support it natively, but
// ember-cli's clean-css minifier cannot parse nesting, and a nested attacher
// block loses every rule that hides a tooltip until it is shown.
const from = path.resolve(__dirname, '../../addon/styles/components/attacher.css');
const { filtered } = await compile(fs.readFileSync(from, 'utf8'), from);
assert.doesNotMatch(filtered.css, /&/);
assert.match(filtered.css, /\.ember-attacher\[x-placement\^=['"]?top['"]?\]\s*>\s*\.ember-attacher-fill\s*\{[^}]*opacity:\s*0/);

const emberCli = path.dirname(require.resolve('ember-cli/package.json'));
const CleanCSS = require(require.resolve('clean-css', { paths: [emberCli] }));
const minified = new CleanCSS({}).minify(filtered.css);
assert.deepEqual(minified.errors, []);
assert.deepEqual(minified.warnings, []);
assert.match(minified.styles, /\.ember-attacher\[x-placement\^=['"]?top['"]?\]>\.ember-attacher-fill\{[^}]*opacity:0/);
assert.doesNotMatch(minified.styles, /\}&/);
});
Loading