mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] tags: reintroduce inline css tag
The CSS tag is useful to define a css stylesheet in the javascript file:
```js
class MyComponent extends Component {
static template = xml`
<div class="my-component">some template</div>
`;
static style = css`
.my-component {
color: red;
}
`;
}
```
The `css` tag registers internally the css information. Then, whenever the first instance of the component is created, will add a <style> tag to the document <head>.
Original commit in Owl v1: 953778dc5
This commit is contained in:
committed by
Géry Debongnie
parent
4e4b85e2a9
commit
ee5ad354ff
+158
-142
@@ -1,159 +1,175 @@
|
||||
// import { Component, Env } from "../../src/component/component";
|
||||
// import { processSheet } from "../../src/component/styles";
|
||||
// import { xml, css } from "../../src/tags";
|
||||
// import { makeTestFixture, makeTestEnv } from "../helpers";
|
||||
import { Component, css, mount, xml } from "../../src";
|
||||
import { makeTestFixture } from "../helpers";
|
||||
|
||||
// //------------------------------------------------------------------------------
|
||||
// // Setup and helpers
|
||||
// //------------------------------------------------------------------------------
|
||||
let fixture: HTMLElement;
|
||||
beforeEach(() => {
|
||||
fixture = makeTestFixture();
|
||||
document.head.innerHTML = "";
|
||||
});
|
||||
|
||||
// // We create before each test:
|
||||
// // - fixture: a div, appended to the DOM, intended to be the target of dom
|
||||
// // manipulations. Note that it is removed after each test.
|
||||
// // - env: an Env, necessary to create new components
|
||||
|
||||
// let fixture: HTMLElement;
|
||||
// let env: Env;
|
||||
|
||||
// beforeEach(() => {
|
||||
// fixture = makeTestFixture();
|
||||
// env = makeTestEnv();
|
||||
// Component.env = env;
|
||||
// document.head.innerHTML = "";
|
||||
// });
|
||||
|
||||
// afterEach(() => {
|
||||
// fixture.remove();
|
||||
// });
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tests
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
describe.skip("styles and component", () => {
|
||||
describe("styles and component", () => {
|
||||
test("can define an inline stylesheet", async () => {
|
||||
// class App extends Component {
|
||||
// static template = xml`<div class="app">text</div>`;
|
||||
// static style = css`
|
||||
// .app {
|
||||
// color: red;
|
||||
// }
|
||||
// `;
|
||||
// }
|
||||
// expect(document.head.innerHTML).toBe("");
|
||||
// const app = new App();
|
||||
// expect(document.head.innerHTML).toBe(`<style component=\"App\">.app {
|
||||
// color: red;
|
||||
// }</style>`);
|
||||
// await app.mount(fixture);
|
||||
// const style = getComputedStyle(app.el!);
|
||||
// expect(style.color).toBe("red");
|
||||
// expect(fixture.innerHTML).toBe('<div class="app">text</div>');
|
||||
class App extends Component {
|
||||
static template = xml`<div class="app">text</div>`;
|
||||
static style = css`
|
||||
.app {
|
||||
color: red;
|
||||
}
|
||||
`;
|
||||
}
|
||||
expect(document.head.innerHTML).toBe("");
|
||||
const app = await mount(App, fixture);
|
||||
expect(document.head.innerHTML).toBe(`<style data-component=\"App\">.app {
|
||||
color: red;
|
||||
}</style>`);
|
||||
const style = getComputedStyle(app.el as HTMLElement);
|
||||
expect(style.color).toBe("red");
|
||||
expect(fixture.innerHTML).toBe('<div class="app">text</div>');
|
||||
});
|
||||
|
||||
test("inherited components properly apply css", async () => {
|
||||
// class App extends Component {
|
||||
// static template = xml`<div class="app">text</div>`;
|
||||
// static style = css`
|
||||
// .app {
|
||||
// color: red;
|
||||
// }
|
||||
// `;
|
||||
// }
|
||||
// class SubApp extends App {
|
||||
// static style = css`
|
||||
// .app {
|
||||
// font-weight: bold;
|
||||
// }
|
||||
// `;
|
||||
// }
|
||||
// expect(document.head.innerHTML).toBe("");
|
||||
// const app = new SubApp();
|
||||
// expect(document.head.innerHTML).toBe(`<style component=\"SubApp\">.app {
|
||||
// font-weight: bold;
|
||||
// }</style><style component=\"App\">.app {
|
||||
// color: red;
|
||||
// }</style>`);
|
||||
// await app.mount(fixture);
|
||||
// const style = getComputedStyle(app.el!);
|
||||
// expect(style.color).toBe("red");
|
||||
// expect(style.fontWeight).toBe("bold");
|
||||
// expect(fixture.innerHTML).toBe('<div class="app">text</div>');
|
||||
class App extends Component {
|
||||
static template = xml`<div class="app">text</div>`;
|
||||
static style = css`
|
||||
.app {
|
||||
color: red;
|
||||
}
|
||||
`;
|
||||
}
|
||||
class SubApp extends App {
|
||||
static style = css`
|
||||
.app {
|
||||
font-weight: bold;
|
||||
}
|
||||
`;
|
||||
}
|
||||
expect(document.head.innerHTML).toBe("");
|
||||
const app = await mount(SubApp, fixture);
|
||||
expect(document.head.innerHTML).toBe(`<style data-component=\"App\">.app {
|
||||
color: red;
|
||||
}</style><style data-component=\"SubApp\">.app {
|
||||
font-weight: bold;
|
||||
}</style>`);
|
||||
const style = getComputedStyle(app.el as HTMLElement);
|
||||
expect(style.color).toBe("red");
|
||||
expect(style.fontWeight).toBe("bold");
|
||||
expect(fixture.innerHTML).toBe('<div class="app">text</div>');
|
||||
});
|
||||
|
||||
test("inherited components properly apply css, part 2", async () => {
|
||||
class App extends Component {
|
||||
static template = xml`<div class="app"/>`;
|
||||
static style = css`
|
||||
.app {
|
||||
color: tomato;
|
||||
}
|
||||
`;
|
||||
}
|
||||
class BetterApp extends App {}
|
||||
class EvenBetterApp extends BetterApp {
|
||||
static style = css`
|
||||
.app {
|
||||
background-color: papayawhip;
|
||||
}
|
||||
`;
|
||||
}
|
||||
expect(document.head.innerHTML).toBe("");
|
||||
await mount(EvenBetterApp, fixture);
|
||||
expect(document.head.innerHTML).toBe(`<style data-component=\"App\">.app {
|
||||
color: tomato;
|
||||
}</style><style data-component=\"EvenBetterApp\">.app {
|
||||
background-color: papayawhip;
|
||||
}</style>`);
|
||||
});
|
||||
|
||||
test("get a meaningful error message if css helper is missing", async () => {
|
||||
// class App extends Component {
|
||||
// static template = xml`<div class="app">text</div>`;
|
||||
// static style = `.app {color: red;}`;
|
||||
// }
|
||||
// let error;
|
||||
// try {
|
||||
// new App();
|
||||
// } catch (e) {
|
||||
// error = e;
|
||||
// }
|
||||
// expect(error).toBeDefined();
|
||||
// expect(error.message).toBe(
|
||||
// "Invalid css stylesheet for component 'App'. Did you forget to use the 'css' tag helper?"
|
||||
// );
|
||||
// });
|
||||
// test("inline stylesheets are processed", async () => {
|
||||
// class App extends Component {
|
||||
// static template = xml`<div class="app">text</div>`;
|
||||
// static style = css`
|
||||
// .app {
|
||||
// color: red;
|
||||
// .some-class {
|
||||
// font-weight: bold;
|
||||
// width: 40px;
|
||||
// }
|
||||
// display: block;
|
||||
// }
|
||||
// `;
|
||||
// }
|
||||
// new App();
|
||||
// expect(document.head.querySelector("style")!.innerHTML).toBe(`.app {
|
||||
// color: red;
|
||||
// }
|
||||
// .app .some-class {
|
||||
// font-weight: bold;
|
||||
// width: 40px;
|
||||
// }
|
||||
// .app {
|
||||
// display: block;
|
||||
// }`);
|
||||
class App extends Component {
|
||||
static template = xml`<div class="app">text</div>`;
|
||||
static style = `.app {color: red;}`;
|
||||
}
|
||||
let error;
|
||||
try {
|
||||
await mount(App, fixture);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
expect(error.message).toBe(
|
||||
"Invalid css stylesheet for component 'App'. Did you forget to use the 'css' tag helper?"
|
||||
);
|
||||
});
|
||||
|
||||
test("inline stylesheets are processed", async () => {
|
||||
class App extends Component {
|
||||
static template = xml`<div class="app">text</div>`;
|
||||
static style = css`
|
||||
.app {
|
||||
color: red;
|
||||
.some-class {
|
||||
font-weight: bold;
|
||||
width: 40px;
|
||||
}
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
}
|
||||
await mount(App, fixture);
|
||||
expect(document.head.querySelector("style")!.innerHTML).toBe(`.app {
|
||||
color: red;
|
||||
}
|
||||
.app .some-class {
|
||||
font-weight: bold;
|
||||
width: 40px;
|
||||
}
|
||||
.app {
|
||||
display: block;
|
||||
}`);
|
||||
});
|
||||
|
||||
test("properly handle rules with commas", async () => {
|
||||
// const sheet = processSheet(`.parent-a, .parent-b {
|
||||
// .child-a, .child-b {
|
||||
// color: red;
|
||||
// }
|
||||
// }`);
|
||||
// expect(sheet)
|
||||
// .toBe(`.parent-a .child-a, .parent-a .child-b, .parent-b .child-a, .parent-b .child-b {
|
||||
// color: red;
|
||||
// }`);
|
||||
class App extends Component {
|
||||
static template = xml`<div/>`;
|
||||
static style = css`
|
||||
.parent-a,
|
||||
.parent-b {
|
||||
.child-a,
|
||||
.child-b {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
await mount(App, fixture);
|
||||
expect(document.head.querySelector("style")!.innerHTML)
|
||||
.toBe(`.parent-a .child-a, .parent-a .child-b, .parent-b .child-a, .parent-b .child-b {
|
||||
color: red;
|
||||
}`);
|
||||
});
|
||||
|
||||
test("handle & selector", async () => {
|
||||
// let sheet = processSheet(`.btn {
|
||||
// &.danger {
|
||||
// color: red;
|
||||
// }
|
||||
// }`);
|
||||
// expect(sheet).toBe(`.btn.danger {
|
||||
// color: red;
|
||||
// }`);
|
||||
// sheet = processSheet(`.some-class {
|
||||
// &.btn {
|
||||
// .other-class ~ & {
|
||||
// color: red;
|
||||
// }
|
||||
// }
|
||||
// }`);
|
||||
// expect(sheet).toBe(`.other-class ~ .some-class.btn {
|
||||
// color: red;
|
||||
// }`);
|
||||
class App extends Component {
|
||||
static template = xml`<div/>`;
|
||||
static style = css`
|
||||
.btn {
|
||||
&.danger {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
.some-class {
|
||||
&.btn {
|
||||
.other-class ~ & {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
await mount(App, fixture);
|
||||
expect(document.head.querySelector("style")!.innerHTML).toBe(`.btn.danger {
|
||||
color: red;
|
||||
}
|
||||
.other-class ~ .some-class.btn {
|
||||
color: red;
|
||||
}`);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user