Options
All
  • Public
  • Public/Protected
  • All
Menu

Package @css-blocks/glimmer

CSS Blocks Integration for Glimmer Applications

The css-blocks Rewriter and Analyzer for Glimmer templates.

Installation

yarn add @css-blocks/glimmer

or

npm install --save-dev @css-blocks/glimmer

Usage

This integration for css-blocks with Glimmer creates a convention where every component has an associated css-block. The classes and states of that block are exposed by default to the template. Other blocks are exposed to the template using the @block-reference at-rule from within the stylesheet.

Template Syntax

Given the following CSS Block definition:

@block-reference grid from "./grid.block.css";
:scope {
  block-name: my-component;
  / ... /
}
[state|loading] { / ... / }
.sidebar { / ... / }
.sidebar[state|collapsed] { / ... / }
.main { / ... / }
.recommended { / ... / }

.one-fifth { / ... / }
.one-fifth[state|gutter-right] { / ... / }
.four-fifths { / ... / }

We can style a glimmer template like so:

<div state:loading={{isLoading}}>
  <aside class="sidebar grid.one-fifth" state:collapsed state:grid.gutter-right>
  </aside>
  <article class="{{style-if isRecommended 'recommended' 'main'}} grid.four-fifths">
  </article>
</div>

Of note here:

  • Templates with a corresponding Block file must have a root single DOM node as the base of its template.
  • The styles for the :scope class are automatically applied to the root element of the component (in this case: div).
  • Classes and states from referenced blocks are prefixed with the name of the block (in this case: grid)
  • The only expressions allowed in class attributes are the CSS Blocks specific {{style-if}} and {{style-unless}} helpers. Otherwise, a build time error is thrown.

Creating an Analyzer

The default Analyzer performs a transitive analysis by traversing the component hierarchy as well as the block's dependencies on other blocks. This analysis can be provided to the css-blocks compiler and optimizer to remove dead css and enable powerful optimizations.

import  as path from "path";
import {
  Project,
  Rewriter,
  HandlebarsTransitiveStyleAnalyzer as Analyzer
} from "@css-blocks/glimmer";
import projectConfig from "./projectConfig";
let projectDir = path.resolve(__dirname, "..");
let project = new Project(projectDir, projectConfig);
let analyzer = new Analyzer(project, "my-app-component");
analyzer.analyze().then((analysis) => {
  console.log(analysis.serialize(projectDir));
});

Glimmer Project Layout for CSS Blocks

You must add a new stylesheet type to your project so that every component has an associated CSS block. This means you must declare a new type in the types section and add "stylesheet" to the component types.

Example:

const glimmerProjectConfiguration = {
  types: {
    application: { definitiveCollection: 'main' },
    component: { definitiveCollection: 'components' },
    helper: { definitiveCollection: 'components' },
    renderer: { definitiveCollection: 'main' },
    template: { definitiveCollection: 'components' },
    stylesheet: { definitiveCollection: 'components' }
  },
  collections: {
    main: {
      types: ['application', 'renderer']
    },
    components: {
      group: 'ui',
      types: ['component', 'template', 'helper', 'stylesheet'],
      defaultType: 'component',
      privateCollections: ['utils']
    }
  }
}

Note: at this time the default block file for a component must be named stylesheet.css -- the standard naming convention of .block.css does not work.

Rewriting Templates

After analyzing templates and compiling & optimizing the CSS blocks that are used, the glimmer template must be rewritten to use the right classnames. Glimmer accepts AST plugins during the precompilation step.

Here's an example script for how to analyze and rewrite a single template. Integration with your specific build system will be required.

import * as path from "path";
import {
  StyleMapping
} from "@css-blocks/core";
import {
  Project,
  Rewriter,
  RewriterOptions,
  HandlebarsStyleAnalyzer as Analyzer,
} from "@css-blocks/glimmer";
import {
  precompile
} from "@glimmer/compiler";
import projectConfig from "./projectConfig";
let projectDir = path.resolve(__dirname, "..");
let project = new Project(projectDir, projectConfig);
let analyzer = new Analyzer(project, "my-app-component");
analyzer.analyze().then((analysis) => {
  let template = project.templateFor("my-app-component");
  let options = {
    meta: {},
    plugins: {
      ast: [Rewriter]
    },
    cssBlocks: {
      styleMapping: StyleMapping.fromAnalysis(analysis)
    }
  };
  let compiledFile = precompile(template.string, options);
});

To Do

  • Default the name for a component's main block stylesheet to the name of the component so that :scope { block-name: name-of-component; } is not required.

Index

Type aliases

Abort

Abort: function

Type declaration

    • (): false
    • Returns false

AnalysisElement

AnalysisElement: ElementAnalysis<null, null, null>

AttributeContainer

AttributeContainer: Block | BlockClass

BooleanExpression

BooleanExpression: AST.Expression | MustacheStatement

BranchStyles

BranchStyles: Array<BlockClass> | undefined

Builders

Builders: object

Type declaration

  • attr: function
      • (name: string, value: MustacheStatement | TextNode | ConcatStatement, loc?: SourceLocation | undefined): AttrNode
      • Parameters

        • name: string
        • value: MustacheStatement | TextNode | ConcatStatement
        • Optional loc: SourceLocation | undefined

        Returns AttrNode

  • block: function
      • (path: BuilderPath, params: Option<AST.Expression[]>, hash: Option<Hash>, program: Program, inverse?: Program | null | undefined, loc?: SourceLocation | undefined): BlockStatement
      • Parameters

        • path: BuilderPath
        • params: Option<AST.Expression[]>
        • hash: Option<Hash>
        • program: Program
        • Optional inverse: Program | null | undefined
        • Optional loc: SourceLocation | undefined

        Returns BlockStatement

  • boolean: function
      • (value: string | number | boolean | null | undefined): AST.Literal
      • Parameters

        • value: string | number | boolean | null | undefined

        Returns AST.Literal

  • comment: function
      • (value: string, loc?: SourceLocation | undefined): CommentStatement
      • Parameters

        • value: string
        • Optional loc: SourceLocation | undefined

        Returns CommentStatement

  • concat: function
      • (parts: (TextNode | MustacheStatement)[], loc?: SourceLocation | undefined): ConcatStatement
      • Parameters

        • parts: (TextNode | MustacheStatement)[]
        • Optional loc: SourceLocation | undefined

        Returns ConcatStatement

  • element: function
      • (tag: string, attributes?: AttrNode[] | undefined, modifiers?: ElementModifierStatement[] | undefined, children?: AST.Statement[] | undefined, loc?: SourceLocation | undefined): ElementNode
      • (tag: string, attributes?: AttrNode[] | undefined, modifiers?: ElementModifierStatement[] | undefined, children?: AST.Statement[] | undefined, comments?: MustacheCommentStatement[] | undefined, loc?: SourceLocation | undefined): ElementNode
      • Parameters

        • tag: string
        • Optional attributes: AttrNode[] | undefined
        • Optional modifiers: ElementModifierStatement[] | undefined
        • Optional children: AST.Statement[] | undefined
        • Optional loc: SourceLocation | undefined

        Returns ElementNode

      • Parameters

        • tag: string
        • Optional attributes: AttrNode[] | undefined
        • Optional modifiers: ElementModifierStatement[] | undefined
        • Optional children: AST.Statement[] | undefined
        • Optional comments: MustacheCommentStatement[] | undefined
        • Optional loc: SourceLocation | undefined

        Returns ElementNode

  • elementModifier: function
      • (path: BuilderPath, params?: AST.Expression[] | undefined, hash?: Hash | undefined, loc?: SourceLocation | null | undefined): ElementModifierStatement
      • Parameters

        • path: BuilderPath
        • Optional params: AST.Expression[] | undefined
        • Optional hash: Hash | undefined
        • Optional loc: SourceLocation | null | undefined

        Returns ElementModifierStatement

  • hash: function
      • (pairs?: HashPair[] | undefined, loc?: SourceLocation | undefined): Hash
      • Parameters

        • Optional pairs: HashPair[] | undefined
        • Optional loc: SourceLocation | undefined

        Returns Hash

  • literal: function
      • <T>(type: T["type"], value: T["value"], loc?: SourceLocation | undefined): AST.Literal
      • Type parameters

        • T: AST.Literal

        Parameters

        • type: T["type"]
        • value: T["value"]
        • Optional loc: SourceLocation | undefined

        Returns AST.Literal

  • loc: function
      • (loc: Option<SourceLocation>): SourceLocation
      • (startLine: number, startColumn: number, endLine?: number | undefined, endColumn?: number | undefined, source?: string | undefined): SourceLocation
      • Parameters

        • loc: Option<SourceLocation>

        Returns SourceLocation

      • Parameters

        • startLine: number
        • startColumn: number
        • Optional endLine: number | undefined
        • Optional endColumn: number | undefined
        • Optional source: string | undefined

        Returns SourceLocation

  • mustache: function
      • (path: string | PathExpression | StringLiteral | BooleanLiteral | NumberLiteral | UndefinedLiteral | NullLiteral, params?: AST.Expression[] | undefined, hash?: Hash | undefined, raw?: boolean | undefined, loc?: SourceLocation | undefined): MustacheStatement
      • Parameters

        • path: string | PathExpression | StringLiteral | BooleanLiteral | NumberLiteral | UndefinedLiteral | NullLiteral
        • Optional params: AST.Expression[] | undefined
        • Optional hash: Hash | undefined
        • Optional raw: boolean | undefined
        • Optional loc: SourceLocation | undefined

        Returns MustacheStatement

  • mustacheComment: function
      • (value: string, loc?: SourceLocation | undefined): MustacheCommentStatement
      • Parameters

        • value: string
        • Optional loc: SourceLocation | undefined

        Returns MustacheCommentStatement

  • number: function
      • (value: string | number | boolean | null | undefined): AST.Literal
      • Parameters

        • value: string | number | boolean | null | undefined

        Returns AST.Literal

  • pair: function
      • (key: string, value: AST.Expression, loc?: SourceLocation | undefined): HashPair
      • Parameters

        • key: string
        • value: AST.Expression
        • Optional loc: SourceLocation | undefined

        Returns HashPair

  • partial: function
      • (name: PathExpression, params?: AST.Expression[] | undefined, hash?: Hash | undefined, indent?: string | undefined, loc?: SourceLocation | undefined): PartialStatement
      • Parameters

        • name: PathExpression
        • Optional params: AST.Expression[] | undefined
        • Optional hash: Hash | undefined
        • Optional indent: string | undefined
        • Optional loc: SourceLocation | undefined

        Returns PartialStatement

  • path: function
      • (original: BuilderPath, loc?: SourceLocation | undefined): PathExpression
      • Parameters

        • original: BuilderPath
        • Optional loc: SourceLocation | undefined

        Returns PathExpression

  • pos: function
      • (line: number, column: number): object
      • Parameters

        • line: number
        • column: number

        Returns object

        • column: number
        • line: number
  • program: function
      • (body?: AST.Statement[] | undefined, blockParams?: string[] | undefined, loc?: SourceLocation | undefined): Program
      • Parameters

        • Optional body: AST.Statement[] | undefined
        • Optional blockParams: string[] | undefined
        • Optional loc: SourceLocation | undefined

        Returns Program

  • sexpr: function
      • (path: PathExpression, params?: AST.Expression[] | undefined, hash?: Hash | undefined, loc?: SourceLocation | undefined): SubExpression
      • Parameters

        • path: PathExpression
        • Optional params: AST.Expression[] | undefined
        • Optional hash: Hash | undefined
        • Optional loc: SourceLocation | undefined

        Returns SubExpression

  • string: function
      • (value: string | number | boolean | null | undefined): AST.Literal
      • Parameters

        • value: string | number | boolean | null | undefined

        Returns AST.Literal

  • text: function
      • (chars?: string | undefined, loc?: SourceLocation | undefined): TextNode
      • Parameters

        • Optional chars: string | undefined
        • Optional loc: SourceLocation | undefined

        Returns TextNode

  • null: function
    • null(): AST.Literal
    • Returns AST.Literal

  • undefined: function
    • undefined(): AST.Literal
    • Returns AST.Literal

ConditionalArg

ConditionalArg: number | BooleanExpression<number>

GlimmerAnalysis

GlimmerAnalysis: Analysis<TEMPLATE_TYPE>

GlimmerStyleMapping

GlimmerStyleMapping: StyleMapping<TEMPLATE_TYPE>

IsSourceSet

IsSourceSet: function

Type declaration

    • (n: number): boolean
    • Parameters

      • n: number

      Returns boolean

RewriteAnalysis

RewriteAnalysis: object | object

SetSource

SetSource: function

Type declaration

    • (n: number): void
    • Parameters

      • n: number

      Returns void

StringExpression

StringExpression: MustacheStatement | ConcatStatement

TEMPLATE_TYPE

TEMPLATE_TYPE: "GlimmerTemplates.ResolvedFile"

TemplateElement

TemplateElement: ElementAnalysis<BooleanExpression, StringExpression, TernaryExpression>

TernaryExpression

TernaryExpression: AST.Expression

Variables

Const DEBUG

DEBUG: IDebugger = debugGenerator("css-blocks:glimmer")

Const STATE

STATE: RegExp = /^state:(?:([^.]+)\.)?([^.]+)$/

Const STYLE_ATTR

STYLE_ATTR: RegExp = /^(class$|state:)/

Const STYLE_IF

STYLE_IF: "style-if" = "style-if"

Const STYLE_UNLESS

STYLE_UNLESS: "style-unless" = "style-unless"

Const buildResolutionMap

buildResolutionMap: buildResolutionMap = resMapBuilder.buildResolutionMap

Const debug

debug: IDebugger = debugGenerator("css-blocks:glimmer:analyzer")

Const debug

debug: IDebugger = debugGenerator("css-blocks:glimmer")

Const glimmerImportIdentifier

glimmerImportIdentifier: RegExp = /^glimmer:(.+)$/

Functions

_blockConcat

  • _blockConcat(args: any[]): string

Const bool

boolExpr

classnames

classnamesHelper

  • classnamesHelper(rewrite: IndexedClassRewrite<Style>, element: TemplateElement): MustacheStatement

constructAndExpression

  • constructAndExpression(bool: AndExpression<number>): AST.Expression[]

constructArgs

  • constructArgs(rewrite: IndexedClassRewrite<any>, element: TemplateElement): AST.Expression[]

constructBoolean

constructConditional

  • constructConditional(stateExpr: Conditional<BooleanAST> & HasAttrValue, _rewrite: IndexedClassRewrite<Style>): AST.Expression[]

constructConditionalExpression

constructDependency

  • constructDependency(stateExpr: Dependency, rewrite: IndexedClassRewrite<Style>): AST.Expression[]

constructNotExpression

  • constructNotExpression(bool: NotExpression<number>): AST.Expression[]

constructOrExpression

  • constructOrExpression(bool: OrExpression<number>): AST.Expression[]

constructOutputArgs

  • constructOutputArgs(rewrite: IndexedClassRewrite<any>): AST.Expression[]

constructSourceArgs

  • constructSourceArgs(rewrite: IndexedClassRewrite<any>, element: TemplateElement): AST.Expression[]

constructStateReferences

  • constructStateReferences(stateExpr: HasAttrValue, rewrite: IndexedClassRewrite<Style>): AST.Expression[]

constructSwitch

  • constructSwitch(stateExpr: Switch<StringAST> & HasGroup, rewrite: IndexedClassRewrite<Style>): AST.Expression[]

constructTernary

  • constructTernary(classes: DynamicClasses<TernaryAST>, rewrite: IndexedClassRewrite<Style>): AST.Expression[]
  • Boolean Ternary: 1: expression to evaluate as truthy 2: number (t) of source styles set if true 3..(3+t-1): indexes of source styles set if true (3+t): number (f) of source styles set if false (4+t)..(4+t+f-1): indexes of source styles set if false

    Parameters

    Returns AST.Expression[]

cssBlockError

  • cssBlockError(message: string, node: AST.Node, template: TemplateInfo<"GlimmerTemplates.ResolvedFile">): CssBlockError
  • Parameters

    • message: string
    • node: AST.Node
    • template: TemplateInfo<"GlimmerTemplates.ResolvedFile">

    Returns CssBlockError

dynamicClasses

Const e

  • e(m: string): never

isConcatStatement

  • isConcatStatement(value: TextNode | MustacheStatement | ConcatStatement): boolean

isMustacheStatement

  • isMustacheStatement(value: TextNode | MustacheStatement | ConcatStatement): boolean

isStringLiteral

  • isStringLiteral(value: AST.Node | undefined): boolean

isStyleIfHelper

  • isStyleIfHelper(node: MustacheStatement): "style-if" | "style-unless" | undefined

isTextNode

  • isTextNode(value: TextNode | MustacheStatement | ConcatStatement): boolean

moustacheToBooleanExpression

  • moustacheToBooleanExpression(booleanExpression: BooleanAST): AST.Expression

moustacheToExpression

  • moustacheToExpression(expr: MustacheStatement): AST.Expression

moustacheToStringExpression

  • moustacheToStringExpression(stringExpression: StringAST): AST.Expression

nodeLocation

  • nodeLocation(node: AST.Node): SourceLocation

Const num

parseSpecifier

  • parseSpecifier(specifier: string): object | null

pathFromSpecifier

  • pathFromSpecifier(specifier: string): string

resolveInheritance

  • resolveInheritance(classes: Array<BlockClass>, rewrite: IndexedClassRewrite<Style>): BlockClass[]

selectorCount

  • selectorCount(result: ClassifiedParsedSelectors): number

sourceExpr

Const str

Const toStr

Const truthyString

  • truthyString(v: whatever[]): string | undefined

Object literals

Const MODULE_CONFIG

MODULE_CONFIG: object

app

app: object

name

name: string = "glimmer-test"

rootName

rootName: string = "glimmer-test"

collections

collections: object

components

components: object

defaultType

defaultType: string = "component"

group

group: string = "ui"

privateCollections

privateCollections: string[] = ["utils"]

types

types: string[] = ["component", "component-test", "template", "helper", "helper-test", "stylesheet"]

main

main: object

types

types: string[] = ["application", "renderer"]

styles

styles: object

group

group: string = "ui"

unresolvable

unresolvable: true = true

utils

utils: object

unresolvable

unresolvable: true = true

types

types: object

application

application: object

definitiveCollection

definitiveCollection: string = "main"

component

component: object

definitiveCollection

definitiveCollection: string = "components"

component-test

component-test: object

unresolvable

unresolvable: true = true

helper

helper: object

definitiveCollection

definitiveCollection: string = "components"

helper-test

helper-test: object

unresolvable

unresolvable: true = true

renderer

renderer: object

definitiveCollection

definitiveCollection: string = "main"

stylesheet

stylesheet: object

definitiveCollection

definitiveCollection: string = "components"

template

template: object

definitiveCollection

definitiveCollection: string = "components"

Const cssBlocksHelpers

cssBlocksHelpers: object

/css-blocks/components/classnames

/css-blocks/components/classnames: object

kind

kind: string = "helper"

module

module: string = "@css-blocks/glimmer/dist/src/helpers"

name

name: string = "classnames"

meta

meta: object

factory

factory: boolean = false

/css-blocks/components/concat

/css-blocks/components/concat: object

kind

kind: string = "helper"

module

module: string = "@css-blocks/glimmer/dist/src/helpers"

name

name: string = "concat"

meta

meta: object

factory

factory: boolean = false

Generated using TypeDoc