Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Readme
P69 allows compile time tokens to be used for CSS within Node based projects.
It scans CSS for placeholder tokens which are substituted for user defined values. It's just a glorified string.replace
.
This tool is straight up optimised for my tastes which means taking the light touch. In general, the design trade-offs lean towards simplicity, readability, and changability.
export default {
color: {
normal: 'burlywood',
highlight: 'crimson ',
},
font: {
size: {
sm: '0.8rem',
md: '1rem',
lg: '1.2rem',
},
},
hello: (name = 'Joe') => {
return '"Hello ' + name + '"'
},
}
.random-class {
color: $color.normal;
font-size: $font.size.md;
&:hover {
color: &color.highlight;
}
&:after {
content: $hello(); // "Hello Joe"
content: $hello("Jenny"); // "Hello Jenny"
}
}
See sveltekit-minimalist-template for example project usage.
{
"devDependencies": {
"p69": "3.x.x"
}
}
First create a map of your tokens in JavaScript. I recommend creating a file and exporting. Call it whatever you like.
There are no standards or conventions on how one should organise their tokens. Do what works, not what just happens to be trending!
Here's a rough example:
// tokens.js
import myColors from './my-colors.js'
export default {
// Used for creating string literals such as those
// containing '$'.
toString: (s = '') => s.toString(),
// Split out parts into meaningfully named files.
color: myColors,
// Create hierarchies to meaningfully structure tokens.
//
// However, if you employ a design system or design tokens
// then you should probably derive your structure from there.
font: {
family: {
helvetica: ['Helvetica', 'Arial', 'Verdana'], // $font.family.helvetica;
verdana: ['Verdana', 'Arial', 'Helvetica'], // $font.family.verdana;
},
size: {
sm: 12, // $font.size.sm;
md: 16, // $font.size.md;
lg: 20, // $font.size.lg;
xl: 24, // $font.size.xl;
},
},
}
Definition:
p69([...])
. Each map is checked in turn when attempting to resolve a token.Usage:
$
.$func(1, 2, 3)
.$func
== $func()
.Interesting useless side effect: you can pass arguments to a non-function; it's pointless however since they're not used in processing.
There's no escape character for the $
symbol. It's easy enough to write a token for it. A few possibilities:
export const escapeMethods = {
// The simplest approach is to just to use $$, $$$, $$$$, etc.
// Add more as you need.
$: '$',
$$: '$$',
$$$: '$$$',
// We can create a single function that handles all unbroken
// series of $.
//
// $$ => $
// $$(2) => $$
// $$(3) => $$$
$: (n = 1) => '$'.repeat(n),
// literal accepts a value and returns it. This allows values
// containing $ anywhere within to be escaped easily.
//
// $literal("$$$") => $$$
// $literal("$ one $$ two $$$ three") => $ one $$ two $$$ three
literal: (v = '') => v.toString(),
// The world's your Mollusc. You can create any kind of
// function to escape however you please. Here's a quotation
// function.
//
// $quote('Lots of $$$') => "Lots of $$$"
// $quote('Lots of $$$', '`') => `Lots of $$$`
quote: (v, glyph = '"') => glyph + v.toString() + glyph,
}
import { stringP69 } from 'p69'
const tokens = {
font: {
family: {
verdana: ['Verdana', 'Arial', 'Helvetica'],
},
},
}
const before = 'main { font-family: $font.family.verdana; }'
const after = stringP69(tokens, before)
// after: "main { font-family: Verdana, Arial, Helvetica; }"
stringP69(tokens, css, {
// ref is a useful identifer for when onError
// is called. The default onError will print it out.
// Typically a filename but any identifer you find
// meaningful will do.
ref: '¯\\_(ツ)_/¯',
// throwIfMissing will throw an error, after onError
// is called, if a style token can't be found in the
// provided mappings.
throwIfMissing: true,
// onError is called when an error occurs.
// If the error isn't thrown then processing will
// continue for the remaining tokens.
// By default, logs the error and carries on.
onError: (err, token, options) => {},
})
P69 files are CSS files containing P69 tokens.
import { filesP69 } from 'p69'
const tokens = {
theme: {
strong: 'burlywood',
},
font: {
family: {
verdana: ['Verdana', 'Arial', 'Helvetica'],
},
},
}
await filesP69(tokens)
await filesP69(tokens, {
// See stringP69 options.
...stringP69.options,
// src directory containing .p69 files that need
// to be converted to CSS. If null then .p69 file
// processing is skipped.
src: './src',
// out is the file path to merge all processed .p69
// files into. This does not include style content from
// framework files. If null, a .css file will be
// created for each .p69 file in the same directory as it.
//
// There are virtues and vices to each approach but
// amalgamation works better for smaller projects while
// big projects usually benefit from more rigorous
// modularisation.
out: './src/app.css',
})
/* styles.p69 */
.text-strong {
color: $theme.strong;
font-weight: bold;
}
.text-fancy {
font-family: $font.family.spectral;
font-style: italic;
}
Unfortunatly, I've had little success in getting a JavaScript token file and its dependencies to reload on change. I can get a single file and I can reload a whole directory, albeit a little leaky. ECMAScript modules were designed to load once and once only. I may apply the directory approach in a future update.
import { watchP69 } from 'p69'
const tokens = {
theme: {
strong: 'burlywood',
},
font: {
family: {
verdana: ['Verdana', 'Arial', 'Helvetica'],
},
},
}
// Does not block.
// Currently uses chokidar.
const terminateWatcher = watchP69(tokens)
await terminateWatcher()
watchP69(tokens, {
// See filesP69 options.
...filesP69.options,
// chokidar is passed to chokidar as options.
// See https://github.com/paulmillr/chokidar.
chokidar: {},
})
// svelte.config.js
import { svelteP69, watchP69, filesP69 } from 'p69'
import tokens from './src/tokens.js'
// Only needed if you're using .p69 files.
// Compiles all into ./src/app.css by default.
if (process.env.NODE_ENV === 'development') {
watchP69(tokens)
} else {
await filesP69(tokens)
}
export default {
...,
preprocess: [svelteP69(tokens)],
...,
}
svelteP69(tokens, {
// See svelteP69 options.
...filesP69.options,
// langs is a list of accepted lang attibute values.
// Undefined means any style tag with no lang set
// will assumed to be P69 parsable.
langs: [undefined, 'p69', 'text/p69'],
})
<!-- StyledSection.svelte -->
<script>
export let title
</script>
<section>
<h2>{title}</h2>
<slot />
</section>
<style>
section {
background: $color.base;
border-radius: 4px;
overflow: hidden;
}
section h2 {
font-size: $font.size.lg.rem;
color: $color.strong;
}
@media $screen.larger_devices {
section h2 {
font-size: $font.size.xl.rem;
}
}
section :global(p) {
font-family: $font.family.helvetica;
font-size: $font.size.md.rem;
color: $color.text;
margin-top: $space.md.em;
}
section :global(strong) {
color: $color.strong;
}
</style>
Optional utility functions to use in your token maps. Don't be limited by what I've done. Write your own if you want.
import { rgbsToColors, themeVariables, colorSchemes, sizer } from 'p69/util'
Converts a map of RGB and RGBA arrays to CSS RGB and RGBA values.
rgbsToColors(rgbMap) cssColorMap
import { rgbsToColors } from 'p69/util'
const colors = rgbsToColors({
burly_wood: [222, 184, 135],
burly_wood_lucid: [222, 184, 135, 0.5],
ice_cream: [250, 250, 250],
jet_blue: [30, 85, 175],
dark_navy_grey: [5, 10, 60],
dark_navy_grey_lucid: [5, 10, 60, 0.5],
})
console.log(colors) // Use console.table for easy reading
/*
{
burly_wood: "rgb(222, 184, 135)",
burly_wood_lucid: "rgba(222, 184, 135, 0.5)",
ice_cream: "rgb(250, 250, 250)",
jet_blue: "rgb(30, 85, 175)",
dark_navy_grey: "rgb(5, 10, 60)",
dark_navy_grey_lucid: "rgba(5, 10, 60, 0.5)",
}
*/
Generates CSS color scheme media queries from a set of themes; goes hand-in-hand with themeVariables.
themeVariables(themes, prefix) mediaQueries
import { colorSchemes } from 'p69/util'
const themes = {
// P69 doesn't care what the theme names are but browsers do!
light: {
base: [250, 250, 250],
text: [5, 10, 60],
},
dark: {
base: [5, 10, 35],
text: [231, 245, 255],
},
}
const scheme = colorSchemes(themes, 'theme-primary')
console.log(scheme)
/*
`@media (prefers-color-scheme: light) {
:root {
--theme-primary-base: rgb(250, 250, 250);
--theme-primary-text: rgb(5, 10, 60);
}
}
@media (prefers-color-scheme: dark) {
:root {
--theme-primary-base: rgb(5, 10, 35);
--theme-primary-text: rgb(231, 245, 255);
}
}`
*/
Generates a set of CSS variables from a set of themes; goes hand-in-hand with colorSchemes.
colorSchemes(themes, prefix) varMap
import { themeVariables } from 'p69/util'
const themes = {
// P69 doesn't care what the theme names are but browsers do!
light: {
base: [250, 250, 250],
text: [5, 10, 60],
},
dark: {
base: [5, 10, 35],
text: [231, 245, 255],
meh: [0, 0, 0],
},
}
const theme = themeVariables(themes, 'theme-primary')
console.log(theme)
/*
{
base: "var(--theme-primary-base)",
text: "var(--theme-primary-text)",
meh: "var(--theme-primary-meh)",
}
*/
Generates a set of size maps mapping a pixel value to other units.
sizer(tokens, base) sizeMap
Everything is in reference to 96 DPI. sizeMap schema:
{
token_name: {
px, // 1dp
em, // 2dp
rem, // 2dp
pt, // 2dp
pc, // 1dp
in, // 3dp
cm, // 2dp
mm, // 1dp
}
}
Example:
import { sizer } from 'p69/util'
const tokens = {
width: sizer(
{
min: 320,
sm: 720,
md: 920,
lg: 1200,
xl: 1600,
}
// base: 16,
),
}
const css = `
main {
/* width: 45rem (720px at 16px per rem) */
width: $width.sm.rem;
}
/* min-width: 920px */
@media (min-width: $width.md.px) {
main {
/* max-width: 1600px */
max-width: $width.xl.px;
}
}
`
FAQs
A minimalist CSS preprocessing tool using simple search and replace.
The npm package p69 receives a total of 3 weekly downloads. As such, p69 popularity was classified as not popular.
We found that p69 demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.