Resolve TS errors and warnings

TODO: Use StyleTree types to remove `any`s from styleTrees.
This commit is contained in:
Nate Butler 2023-06-28 17:54:36 -04:00
parent 1177980172
commit bfdd0824e2
53 changed files with 224 additions and 1010 deletions

View file

@ -1,58 +1,57 @@
module.exports = {
'env': {
"node": true
env: {
node: true,
},
'extends': [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/typescript",
],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 'latest',
'sourceType': 'module'
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
'plugins': [
'@typescript-eslint', 'import'
],
plugins: ["@typescript-eslint", "import"],
globals: {
module: true
module: true,
},
"settings": {
settings: {
"import/parsers": {
"@typescript-eslint/parser": [".ts"]
"@typescript-eslint/parser": [".ts"],
},
"import/resolver": {
"typescript": {
"alwaysTryTypes": true,
}
}
typescript: true,
node: true,
},
"import/extensions": [".ts"],
},
'rules': {
'indent': [
'error',
4
],
'linebreak-style': [
'error',
'unix'
],
'semi': [
'error',
'never'
],
rules: {
"linebreak-style": ["error", "unix"],
semi: ["error", "never"],
"import/no-restricted-paths": [
'error',
"error",
{
'zones': [
zones: [
{
"target": "./src/types/*",
"from": "./src",
"except": [
"./src/types/index.ts"
]
}
]
}
]
}
target: [
"./src/component/*",
"./src/element/*",
"./src/styleTree/*",
"./src/system/*",
"./src/theme/*",
"./src/themes/*",
"./src/utils/*",
],
from: [
"./src/types/styleTree.ts",
"./src/types/element.ts",
"./src/types/property.ts",
],
message: "Import from `@types` instead",
},
],
},
],
},
}

View file

@ -7,9 +7,9 @@ const ACCEPTED_LICENSES_FILE = `${__dirname}/../../script/licenses/zed-licenses.
// Use the cargo-about configuration file as the source of truth for supported licenses.
function parseAcceptedToml(file: string): string[] {
let buffer = fs.readFileSync(file).toString()
const buffer = fs.readFileSync(file).toString()
let obj = toml.parse(buffer)
const obj = toml.parse(buffer)
if (!Array.isArray(obj.accepted)) {
throw Error("Accepted license source is malformed")

View file

@ -9,22 +9,22 @@ const BANNER = `/*
const dirname = __dirname
async function main() {
let schemasPath = path.join(dirname, "../../", "crates/theme/schemas")
let schemaFiles = (await fs.readdir(schemasPath)).filter((x) =>
const schemasPath = path.join(dirname, "../../", "crates/theme/schemas")
const schemaFiles = (await fs.readdir(schemasPath)).filter((x) =>
x.endsWith(".json")
)
let compiledTypes = new Set()
const compiledTypes = new Set()
for (let filename of schemaFiles) {
let filePath = path.join(schemasPath, filename)
for (const filename of schemaFiles) {
const filePath = path.join(schemasPath, filename)
const fileContents = await fs.readFile(filePath)
let schema = JSON.parse(fileContents.toString())
let compiled = await compile(schema, schema.title, {
const schema = JSON.parse(fileContents.toString())
const compiled = await compile(schema, schema.title, {
bannerComment: "",
})
let eachType = compiled.split("export")
for (let type of eachType) {
const eachType = compiled.split("export")
for (const type of eachType) {
if (!type) {
continue
}
@ -32,19 +32,18 @@ async function main() {
}
}
let output = BANNER + Array.from(compiledTypes).join("\n\n")
let outputPath = path.join(dirname, "../../styles/src/types/zed.ts")
const output = BANNER + Array.from(compiledTypes).join("\n\n")
const outputPath = path.join(dirname, "../../styles/src/types/zed.ts")
try {
let existing = await fs.readFile(outputPath)
const existing = await fs.readFile(outputPath)
if (existing.toString() == output) {
// Skip writing if it hasn't changed
console.log("Schemas are up to date")
return
}
} catch (e) {
// It's fine if there's no output from a previous run.
// @ts-ignore
// @ts-expect-error - It's fine if there's no output from a previous run.
if (e.code !== "ENOENT") {
throw e
}

View file

@ -37,7 +37,7 @@ interface InteractiveProps<T> {
* @param state Object containing optional modified fields to be included in the resulting object for each state.
* @returns Interactive<T> object with fields from `base` and `state`.
*/
export function interactive<T extends Object>({
export function interactive<T extends object>({
base,
state,
}: InteractiveProps<T>): Interactive<T> {
@ -51,7 +51,7 @@ export function interactive<T extends Object>({
defaultState = base ? base : (state.default as T)
}
let interactiveObj: Interactive<T> = {
const interactiveObj: Interactive<T> = {
default: defaultState,
}

View file

@ -25,7 +25,7 @@ import copilot from "./copilot"
import assistant from "./assistant"
import { titlebar } from "./titlebar"
export default function app(colorScheme: ColorScheme): Object {
export default function app(colorScheme: ColorScheme): any {
return {
meta: {
name: colorScheme.name,

View file

@ -3,7 +3,7 @@ import { text, border, background, foreground } from "./components"
import editor from "./editor"
import { interactive } from "../element"
export default function assistant(colorScheme: ColorScheme) {
export default function assistant(colorScheme: ColorScheme): any {
const layer = colorScheme.highest
return {
container: {

View file

@ -3,8 +3,8 @@ import { withOpacity } from "../theme/color"
import { text, background } from "./components"
import { toggleable } from "../element"
export default function commandPalette(colorScheme: ColorScheme) {
let layer = colorScheme.highest
export default function commandPalette(colorScheme: ColorScheme): any {
const layer = colorScheme.highest
const key = toggleable({
base: {

View file

@ -211,7 +211,7 @@ export function text(
styleOrProperties?: Styles | TextProperties,
properties?: TextProperties
) {
let style = getStyle(layer, styleSetStyleOrProperties, styleOrProperties)
const style = getStyle(layer, styleSetStyleOrProperties, styleOrProperties)
if (typeof styleSetStyleOrProperties === "object") {
properties = styleSetStyleOrProperties
@ -220,8 +220,8 @@ export function text(
properties = styleOrProperties
}
let size = fontSizes[properties?.size || "sm"]
let color = properties?.color || style.foreground
const size = fontSizes[properties?.size || "sm"]
const color = properties?.color || style.foreground
return {
family: fontFamilies[fontFamily],
@ -273,7 +273,7 @@ export function border(
styleOrProperties?: Styles | BorderProperties,
properties?: BorderProperties
): Border {
let style = getStyle(layer, styleSetStyleOrProperties, styleOrProperties)
const style = getStyle(layer, styleSetStyleOrProperties, styleOrProperties)
if (typeof styleSetStyleOrProperties === "object") {
properties = styleSetStyleOrProperties
@ -291,9 +291,9 @@ export function border(
export function svg(
color: string,
asset: String,
width: Number,
height: Number
asset: string,
width: number,
height: number
) {
return {
color,

View file

@ -3,7 +3,7 @@ import { ColorScheme } from "../theme/colorScheme"
import { background, border, foreground, text } from "./components"
export default function contactFinder(colorScheme: ColorScheme): any {
let layer = colorScheme.middle
const layer = colorScheme.middle
const sideMargin = 6
const contactButton = {

View file

@ -1,11 +1,11 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, borderColor, foreground, text } from "./components"
import { interactive, toggleable } from "../element"
export default function contactsPanel(colorScheme: ColorScheme) {
export default function contactsPanel(colorScheme: ColorScheme): any {
const nameMargin = 8
const sidePadding = 12
let layer = colorScheme.middle
const layer = colorScheme.middle
const contactButton = {
background: background(layer, "on"),

View file

@ -4,8 +4,8 @@ import { interactive } from "../element"
const avatarSize = 12
const headerPadding = 8
export default function contactNotification(colorScheme: ColorScheme): Object {
let layer = colorScheme.lowest
export default function contactNotification(colorScheme: ColorScheme): any {
const layer = colorScheme.lowest
return {
headerAvatar: {
height: avatarSize,

View file

@ -1,9 +1,8 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, text } from "./components"
import { background, border } from "./components"
export default function contactsPopover(colorScheme: ColorScheme) {
let layer = colorScheme.middle
const sidePadding = 12
export default function contactsPopover(colorScheme: ColorScheme): any {
const layer = colorScheme.middle
return {
background: background(layer),
cornerRadius: 6,

View file

@ -2,8 +2,8 @@ import { ColorScheme } from "../theme/colorScheme"
import { background, border, borderColor, text } from "./components"
import { interactive, toggleable } from "../element"
export default function contextMenu(colorScheme: ColorScheme) {
let layer = colorScheme.middle
export default function contextMenu(colorScheme: ColorScheme): any {
const layer = colorScheme.middle
return {
background: background(layer),
cornerRadius: 10,

View file

@ -1,12 +1,12 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, foreground, svg, text } from "./components"
import { interactive } from "../element"
export default function copilot(colorScheme: ColorScheme) {
let layer = colorScheme.middle
export default function copilot(colorScheme: ColorScheme): any {
const layer = colorScheme.middle
let content_width = 264
const content_width = 264
let ctaButton =
const ctaButton =
// Copied from welcome screen. FIXME: Move this into a ZDS component
interactive({
base: {

View file

@ -6,10 +6,10 @@ import hoverPopover from "./hoverPopover"
import { buildSyntax } from "../theme/syntax"
import { interactive, toggleable } from "../element"
export default function editor(colorScheme: ColorScheme) {
export default function editor(colorScheme: ColorScheme): any {
const { isLight } = colorScheme
let layer = colorScheme.highest
const layer = colorScheme.highest
const autocompleteItem = {
cornerRadius: 6,

View file

@ -2,8 +2,8 @@ import { ColorScheme } from "../theme/colorScheme"
import { background, border, text } from "./components"
import { interactive } from "../element"
export default function feedback(colorScheme: ColorScheme) {
let layer = colorScheme.highest
export default function feedback(colorScheme: ColorScheme): any {
const layer = colorScheme.highest
return {
submit_button: interactive({

View file

@ -1,9 +1,9 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, foreground, text } from "./components"
export default function HoverPopover(colorScheme: ColorScheme) {
let layer = colorScheme.middle
let baseContainer = {
export default function HoverPopover(colorScheme: ColorScheme): any {
const layer = colorScheme.middle
const baseContainer = {
background: background(layer),
cornerRadius: 8,
padding: {

View file

@ -3,8 +3,8 @@ import { background, border, text } from "./components"
export default function incomingCallNotification(
colorScheme: ColorScheme
): Object {
let layer = colorScheme.middle
): unknown {
const layer = colorScheme.middle
const avatarSize = 48
return {
windowHeight: 74,

View file

@ -4,7 +4,7 @@ import { background, border, text } from "./components"
import { interactive, toggleable } from "../element"
export default function picker(colorScheme: ColorScheme): any {
let layer = colorScheme.lowest
const layer = colorScheme.lowest
const container = {
background: background(layer),
border: border(layer),

View file

@ -1,8 +1,8 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, text } from "./components"
export default function projectDiagnostics(colorScheme: ColorScheme) {
let layer = colorScheme.highest
export default function projectDiagnostics(colorScheme: ColorScheme): any {
const layer = colorScheme.highest
return {
background: background(layer),
tabIconSpacing: 4,

View file

@ -10,10 +10,10 @@ import {
} from "./components"
import { interactive, toggleable } from "../element"
import merge from "ts-deepmerge"
export default function projectPanel(colorScheme: ColorScheme) {
export default function projectPanel(colorScheme: ColorScheme): any {
const { isLight } = colorScheme
let layer = colorScheme.middle
const layer = colorScheme.middle
type EntryStateProps = {
background?: string

View file

@ -3,8 +3,8 @@ import { background, border, text } from "./components"
export default function projectSharedNotification(
colorScheme: ColorScheme
): Object {
let layer = colorScheme.middle
): unknown {
const layer = colorScheme.middle
const avatarSize = 48
return {

View file

@ -3,7 +3,7 @@ import { withOpacity } from "../theme/color"
import { background, border, foreground, text } from "./components"
import { interactive, toggleable } from "../element"
export default function search(colorScheme: ColorScheme): unknown {
export default function search(colorScheme: ColorScheme): any {
const layer = colorScheme.highest
// Search input

View file

@ -2,8 +2,10 @@ import { ColorScheme } from "../theme/colorScheme"
import { StyleTree } from "../types"
import { background } from "./components"
export default function sharedScreen(colorScheme: ColorScheme): StyleTree.SharedScreen {
let layer = colorScheme.highest
export default function sharedScreen(
colorScheme: ColorScheme
): StyleTree.SharedScreen {
const layer = colorScheme.highest
return {
background: background(layer),
}

View file

@ -6,8 +6,8 @@ const headerPadding = 8
export default function simpleMessageNotification(
colorScheme: ColorScheme
): Object {
let layer = colorScheme.middle
): unknown {
const layer = colorScheme.middle
return {
message: {
...text(layer, "sans", { size: "xs" }),

View file

@ -1,8 +1,8 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, foreground, text } from "./components"
import { interactive, toggleable } from "../element"
export default function statusBar(colorScheme: ColorScheme) {
let layer = colorScheme.lowest
export default function statusBar(colorScheme: ColorScheme): any {
const layer = colorScheme.lowest
const statusContainer = {
cornerRadius: 6,

View file

@ -3,11 +3,11 @@ import { withOpacity } from "../theme/color"
import { text, border, background, foreground } from "./components"
import { interactive, toggleable } from "../element"
export default function tabBar(colorScheme: ColorScheme) {
export default function tabBar(colorScheme: ColorScheme): any {
const height = 32
let activeLayer = colorScheme.highest
let layer = colorScheme.middle
const activeLayer = colorScheme.highest
const layer = colorScheme.middle
const tab = {
height,

View file

@ -155,7 +155,7 @@ function user_menu(theme: ColorScheme) {
}
}
export function titlebar(theme: ColorScheme) {
export function titlebar(theme: ColorScheme): any {
const avatarWidth = 15
const avatarOuterWidth = avatarWidth + 4
const followerAvatarWidth = 14

View file

@ -1,47 +0,0 @@
import merge from "ts-deepmerge"
type ToggleState = "inactive" | "active"
type Toggleable<T> = Record<ToggleState, T>
const NO_INACTIVE_OR_BASE_ERROR =
"A toggleable object must have an inactive state, or a base property."
const NO_ACTIVE_ERROR = "A toggleable object must have an active state."
interface ToggleableProps<T> {
base?: T
state: Partial<Record<ToggleState, T>>
}
/**
* Helper function for creating Toggleable objects.
* @template T The type of the object being toggled.
* @param props Object containing the base (inactive) state and state modifications to create the active state.
* @returns A Toggleable object containing both the inactive and active states.
* @example
* ```
* toggleable({
* base: { background: "#000000", text: "#CCCCCC" },
* state: { active: { text: "#CCCCCC" } },
* })
* ```
*/
export function toggleable<T extends object>(
props: ToggleableProps<T>
): Toggleable<T> {
const { base, state } = props
if (!base && !state.inactive) throw new Error(NO_INACTIVE_OR_BASE_ERROR)
if (!state.active) throw new Error(NO_ACTIVE_ERROR)
const inactiveState = base
? ((state.inactive ? merge(base, state.inactive) : base) as T)
: (state.inactive as T)
const toggleObj: Toggleable<T> = {
inactive: inactiveState,
active: merge(base ?? {}, state.active) as T,
}
return toggleObj
}

View file

@ -1,8 +1,8 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, text } from "./components"
import { interactive, toggleable } from "../element"
export default function dropdownMenu(colorScheme: ColorScheme) {
let layer = colorScheme.middle
export default function dropdownMenu(colorScheme: ColorScheme): any {
const layer = colorScheme.middle
return {
rowHeight: 30,

View file

@ -1,8 +1,8 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, text } from "./components"
export default function tooltip(colorScheme: ColorScheme) {
let layer = colorScheme.middle
export default function tooltip(colorScheme: ColorScheme): any {
const layer = colorScheme.middle
return {
background: background(layer),
border: border(layer),

View file

@ -4,8 +4,8 @@ import { interactive } from "../element"
const headerPadding = 8
export default function updateNotification(colorScheme: ColorScheme): Object {
let layer = colorScheme.middle
export default function updateNotification(colorScheme: ColorScheme): any {
const layer = colorScheme.middle
return {
message: {
...text(layer, "sans", { size: "xs" }),

View file

@ -10,7 +10,7 @@ import {
} from "./components"
import { interactive } from "../element"
export default function welcome(colorScheme: ColorScheme) {
export default function welcome(colorScheme: ColorScheme): any {
const layer = colorScheme.highest
const checkboxBase = {

View file

@ -13,7 +13,7 @@ import tabBar from "./tabBar"
import { interactive } from "../element"
import { titlebar } from "./titlebar"
export default function workspace(colorScheme: ColorScheme) {
export default function workspace(colorScheme: ColorScheme): any {
const layer = colorScheme.lowest
const isLight = colorScheme.isLight

View file

@ -1,11 +0,0 @@
/** Converts a percentage scale value (0-100) to normalized scale (0-1) value. */
export function percentageToNormalized(value: number) {
const normalized = value / 100
return normalized
}
/** Converts a normalized scale (0-1) value to a percentage scale (0-100) value. */
export function normalizedToPercetage(value: number) {
const percentage = value * 100
return percentage
}

View file

@ -1,26 +0,0 @@
import bezier from "bezier-easing"
import { Curve } from "../ref/curves"
/**
* Formats our Curve data structure into a bezier easing function.
* @param {Curve} curve - The curve to format.
* @param {Boolean} inverted - Whether or not to invert the curve.
* @returns {EasingFunction} The formatted easing function.
*/
export function curve(curve: Curve, inverted?: Boolean) {
if (inverted) {
return bezier(
curve.value[3],
curve.value[2],
curve.value[1],
curve.value[0]
)
}
return bezier(
curve.value[0],
curve.value[1],
curve.value[2],
curve.value[3]
)
}

View file

@ -1,159 +0,0 @@
import bezier from "bezier-easing"
import chroma from "chroma-js"
import { Color, ColorFamily, ColorFamilyConfig, ColorScale } from "../types"
import { percentageToNormalized } from "./convert"
import { curve } from "./curve"
// Re-export interface in a more standard format
export type EasingFunction = bezier.EasingFunction
/**
* Generates a color, outputs it in multiple formats, and returns a variety of useful metadata.
*
* @param {EasingFunction} hueEasing - An easing function for the hue component of the color.
* @param {EasingFunction} saturationEasing - An easing function for the saturation component of the color.
* @param {EasingFunction} lightnessEasing - An easing function for the lightness component of the color.
* @param {ColorFamilyConfig} family - Configuration for the color family.
* @param {number} step - The current step.
* @param {number} steps - The total number of steps in the color scale.
*
* @returns {Color} The generated color, with its calculated contrast against black and white, as well as its LCH values, RGBA array, hexadecimal representation, and a flag indicating if it is light or dark.
*/
function generateColor(
hueEasing: EasingFunction,
saturationEasing: EasingFunction,
lightnessEasing: EasingFunction,
family: ColorFamilyConfig,
step: number,
steps: number
) {
const { hue, saturation, lightness } = family.color
const stepHue = hueEasing(step / steps) * (hue.end - hue.start) + hue.start
const stepSaturation =
saturationEasing(step / steps) * (saturation.end - saturation.start) +
saturation.start
const stepLightness =
lightnessEasing(step / steps) * (lightness.end - lightness.start) +
lightness.start
const color = chroma.hsl(
stepHue,
percentageToNormalized(stepSaturation),
percentageToNormalized(stepLightness)
)
const contrast = {
black: {
value: chroma.contrast(color, "black"),
aaPass: chroma.contrast(color, "black") >= 4.5,
aaaPass: chroma.contrast(color, "black") >= 7,
},
white: {
value: chroma.contrast(color, "white"),
aaPass: chroma.contrast(color, "white") >= 4.5,
aaaPass: chroma.contrast(color, "white") >= 7,
},
}
const lch = color.lch()
const rgba = color.rgba()
const hex = color.hex()
// 55 is a magic number. It's the lightness value at which we consider a color to be "light".
// It was picked by eye with some testing. We might want to use a more scientific approach in the future.
const isLight = lch[0] > 55
const result: Color = {
step,
lch,
hex,
rgba,
contrast,
isLight,
}
return result
}
/**
* Generates a color scale based on a color family configuration.
*
* @param {ColorFamilyConfig} config - The configuration for the color family.
* @param {Boolean} inverted - Specifies whether the color scale should be inverted or not.
*
* @returns {ColorScale} The generated color scale.
*
* @example
* ```ts
* const colorScale = generateColorScale({
* name: "blue",
* color: {
* hue: {
* start: 210,
* end: 240,
* curve: "easeInOut"
* },
* saturation: {
* start: 100,
* end: 100,
* curve: "easeInOut"
* },
* lightness: {
* start: 50,
* end: 50,
* curve: "easeInOut"
* }
* }
* });
* ```
*/
export function generateColorScale(
config: ColorFamilyConfig,
inverted: Boolean = false
) {
const { hue, saturation, lightness } = config.color
// 101 steps means we get values from 0-100
const NUM_STEPS = 101
const hueEasing = curve(hue.curve, inverted)
const saturationEasing = curve(saturation.curve, inverted)
const lightnessEasing = curve(lightness.curve, inverted)
let scale: ColorScale = {
colors: [],
values: [],
}
for (let i = 0; i < NUM_STEPS; i++) {
const color = generateColor(
hueEasing,
saturationEasing,
lightnessEasing,
config,
i,
NUM_STEPS
)
scale.colors.push(color)
scale.values.push(color.hex)
}
return scale
}
/** Generates a color family with a scale and an inverted scale. */
export function generateColorFamily(config: ColorFamilyConfig) {
const scale = generateColorScale(config, false)
const invertedScale = generateColorScale(config, true)
const family: ColorFamily = {
name: config.name,
scale,
invertedScale,
}
return family
}

View file

@ -1,445 +0,0 @@
import { generateColorFamily } from "../lib/generate"
import { curve } from "./curves"
// These are the source colors for the color scales in the system.
// These should never directly be used directly in components or themes as they generate thousands of lines of code.
// Instead, use the outputs from the reference palette which exports a smaller subset of colors.
// Token or user-facing colors should use short, clear names and a 100-900 scale to match the font weight scale.
// Light Gray ======================================== //
export const lightgray = generateColorFamily({
name: "lightgray",
color: {
hue: {
start: 210,
end: 210,
curve: curve.linear,
},
saturation: {
start: 10,
end: 15,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 50,
curve: curve.linear,
},
},
})
// Light Dark ======================================== //
export const darkgray = generateColorFamily({
name: "darkgray",
color: {
hue: {
start: 210,
end: 210,
curve: curve.linear,
},
saturation: {
start: 15,
end: 20,
curve: curve.saturation,
},
lightness: {
start: 55,
end: 8,
curve: curve.linear,
},
},
})
// Red ======================================== //
export const red = generateColorFamily({
name: "red",
color: {
hue: {
start: 0,
end: 0,
curve: curve.linear,
},
saturation: {
start: 95,
end: 75,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
})
// Sunset ======================================== //
export const sunset = generateColorFamily({
name: "sunset",
color: {
hue: {
start: 15,
end: 15,
curve: curve.linear,
},
saturation: {
start: 100,
end: 90,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
})
// Orange ======================================== //
export const orange = generateColorFamily({
name: "orange",
color: {
hue: {
start: 25,
end: 25,
curve: curve.linear,
},
saturation: {
start: 100,
end: 95,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
})
// Amber ======================================== //
export const amber = generateColorFamily({
name: "amber",
color: {
hue: {
start: 38,
end: 38,
curve: curve.linear,
},
saturation: {
start: 100,
end: 100,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 18,
curve: curve.lightness,
},
},
})
// Yellow ======================================== //
export const yellow = generateColorFamily({
name: "yellow",
color: {
hue: {
start: 48,
end: 48,
curve: curve.linear,
},
saturation: {
start: 90,
end: 100,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 15,
curve: curve.lightness,
},
},
})
// Lemon ======================================== //
export const lemon = generateColorFamily({
name: "lemon",
color: {
hue: {
start: 55,
end: 55,
curve: curve.linear,
},
saturation: {
start: 85,
end: 95,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 15,
curve: curve.lightness,
},
},
})
// Citron ======================================== //
export const citron = generateColorFamily({
name: "citron",
color: {
hue: {
start: 70,
end: 70,
curve: curve.linear,
},
saturation: {
start: 85,
end: 90,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 15,
curve: curve.lightness,
},
},
})
// Lime ======================================== //
export const lime = generateColorFamily({
name: "lime",
color: {
hue: {
start: 85,
end: 85,
curve: curve.linear,
},
saturation: {
start: 85,
end: 80,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 18,
curve: curve.lightness,
},
},
})
// Green ======================================== //
export const green = generateColorFamily({
name: "green",
color: {
hue: {
start: 108,
end: 108,
curve: curve.linear,
},
saturation: {
start: 60,
end: 70,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 18,
curve: curve.lightness,
},
},
})
// Mint ======================================== //
export const mint = generateColorFamily({
name: "mint",
color: {
hue: {
start: 142,
end: 142,
curve: curve.linear,
},
saturation: {
start: 60,
end: 75,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
})
// Cyan ======================================== //
export const cyan = generateColorFamily({
name: "cyan",
color: {
hue: {
start: 179,
end: 179,
curve: curve.linear,
},
saturation: {
start: 70,
end: 80,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
})
// Sky ======================================== //
export const sky = generateColorFamily({
name: "sky",
color: {
hue: {
start: 195,
end: 205,
curve: curve.linear,
},
saturation: {
start: 85,
end: 90,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 15,
curve: curve.lightness,
},
},
})
// Blue ======================================== //
export const blue = generateColorFamily({
name: "blue",
color: {
hue: {
start: 218,
end: 218,
curve: curve.linear,
},
saturation: {
start: 85,
end: 70,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 15,
curve: curve.lightness,
},
},
})
// Indigo ======================================== //
export const indigo = generateColorFamily({
name: "indigo",
color: {
hue: {
start: 245,
end: 245,
curve: curve.linear,
},
saturation: {
start: 60,
end: 50,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 22,
curve: curve.lightness,
},
},
})
// Purple ======================================== //
export const purple = generateColorFamily({
name: "purple",
color: {
hue: {
start: 260,
end: 270,
curve: curve.linear,
},
saturation: {
start: 65,
end: 55,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
})
// Pink ======================================== //
export const pink = generateColorFamily({
name: "pink",
color: {
hue: {
start: 320,
end: 330,
curve: curve.linear,
},
saturation: {
start: 70,
end: 65,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 32,
curve: curve.lightness,
},
},
})
// Rose ======================================== //
export const rose = generateColorFamily({
name: "rose",
color: {
hue: {
start: 345,
end: 345,
curve: curve.linear,
},
saturation: {
start: 90,
end: 70,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 32,
curve: curve.lightness,
},
},
})

View file

@ -1,25 +0,0 @@
export interface Curve {
name: string
value: number[]
}
export interface Curves {
lightness: Curve
saturation: Curve
linear: Curve
}
export const curve: Curves = {
lightness: {
name: "lightnessCurve",
value: [0.2, 0, 0.75, 1.0],
},
saturation: {
name: "saturationCurve",
value: [0.67, 0.6, 0.55, 1.0],
},
linear: {
name: "linear",
value: [0.5, 0.5, 0.5, 0.5],
},
}

View file

@ -1,32 +0,0 @@
import chroma from "chroma-js"
import * as colorFamily from "./ref/color"
const color = {
lightgray: chroma
.scale(colorFamily.lightgray.scale.values)
.mode("lch")
.colors(9),
darkgray: chroma
.scale(colorFamily.darkgray.scale.values)
.mode("lch")
.colors(9),
red: chroma.scale(colorFamily.red.scale.values).mode("lch").colors(9),
sunset: chroma.scale(colorFamily.sunset.scale.values).mode("lch").colors(9),
orange: chroma.scale(colorFamily.orange.scale.values).mode("lch").colors(9),
amber: chroma.scale(colorFamily.amber.scale.values).mode("lch").colors(9),
yellow: chroma.scale(colorFamily.yellow.scale.values).mode("lch").colors(9),
lemon: chroma.scale(colorFamily.lemon.scale.values).mode("lch").colors(9),
citron: chroma.scale(colorFamily.citron.scale.values).mode("lch").colors(9),
lime: chroma.scale(colorFamily.lime.scale.values).mode("lch").colors(9),
green: chroma.scale(colorFamily.green.scale.values).mode("lch").colors(9),
mint: chroma.scale(colorFamily.mint.scale.values).mode("lch").colors(9),
cyan: chroma.scale(colorFamily.cyan.scale.values).mode("lch").colors(9),
sky: chroma.scale(colorFamily.sky.scale.values).mode("lch").colors(9),
blue: chroma.scale(colorFamily.blue.scale.values).mode("lch").colors(9),
indigo: chroma.scale(colorFamily.indigo.scale.values).mode("lch").colors(9),
purple: chroma.scale(colorFamily.purple.scale.values).mode("lch").colors(9),
pink: chroma.scale(colorFamily.pink.scale.values).mode("lch").colors(9),
rose: chroma.scale(colorFamily.rose.scale.values).mode("lch").colors(9),
}
export { color }

View file

@ -1,66 +0,0 @@
import { Curve } from "./ref/curves"
export interface ColorAccessibilityValue {
value: number
aaPass: boolean
aaaPass: boolean
}
/**
* Calculates the color contrast between a specified color and its corresponding background and foreground colors.
*
* @note This implementation is currently basic Currently we only calculate contrasts against black and white, in the future will allow for dynamic color contrast calculation based on the colors present in a given palette.
* @note The goal is to align with WCAG3 accessibility standards as they become stabilized. See the [WCAG 3 Introduction](https://www.w3.org/WAI/standards-guidelines/wcag/wcag3-intro/) for more information.
*/
export interface ColorAccessibility {
black: ColorAccessibilityValue
white: ColorAccessibilityValue
}
export type Color = {
step: number
contrast: ColorAccessibility
hex: string
lch: number[]
rgba: number[]
isLight: boolean
}
export interface ColorScale {
colors: Color[]
// An array of hex values for each color in the scale
values: string[]
}
export type ColorFamily = {
name: string
scale: ColorScale
invertedScale: ColorScale
}
export interface ColorFamilyHue {
start: number
end: number
curve: Curve
}
export interface ColorFamilySaturation {
start: number
end: number
curve: Curve
}
export interface ColorFamilyLightness {
start: number
end: number
curve: Curve
}
export interface ColorFamilyConfig {
name: string
color: {
hue: ColorFamilyHue
saturation: ColorFamilySaturation
lightness: ColorFamilyLightness
}
}

View file

@ -218,9 +218,9 @@ function buildStyleSet(
ramp: Scale,
backgroundBase: number,
foregroundBase: number,
step: number = 0.08
step = 0.08
): StyleSet {
let styleDefinitions = buildStyleDefinition(
const styleDefinitions = buildStyleDefinition(
backgroundBase,
foregroundBase,
step
@ -255,7 +255,7 @@ function buildStyleSet(
function buildStyleDefinition(
bgBase: number,
fgBase: number,
step: number = 0.08
step = 0.08
) {
return {
background: {

View file

@ -6,8 +6,8 @@ import {
} from "./themeConfig"
export function colorRamp(color: Color): Scale {
let endColor = color.desaturate(1).brighten(5)
let startColor = color.desaturate(1).darken(4)
const endColor = color.desaturate(1).brighten(5)
const startColor = color.desaturate(1).darken(4)
return chroma.scale([startColor, color, endColor]).mode("lab")
}
@ -18,15 +18,15 @@ export function colorRamp(color: Color): Scale {
theme so that we don't modify the passed in ramps.
This combined with an error in the type definitions for chroma js means we have to cast the colors
function to any in order to get the colors back out from the original ramps.
* @param isLight
* @param colorRamps
* @returns
* @param isLight
* @param colorRamps
* @returns
*/
export function getRamps(
isLight: boolean,
colorRamps: ThemeConfigInputColors
): RampSet {
const ramps: RampSet = {} as any
const ramps: RampSet = {} as any // eslint-disable-line @typescript-eslint/no-explicit-any
const colorsKeys = Object.keys(colorRamps) as ThemeConfigInputColorsKeys[]
if (isLight) {

View file

@ -56,7 +56,7 @@ export interface Syntax {
// == Types ====== /
// We allow Function here because all JS objects literals have this property
constructor: SyntaxHighlightStyle | Function
constructor: SyntaxHighlightStyle | Function // eslint-disable-line @typescript-eslint/ban-types
variant: SyntaxHighlightStyle
type: SyntaxHighlightStyle
// js: predefined_type

View file

@ -177,30 +177,29 @@ const buildVariant = (variant: Variant): ThemeConfig => {
let neutral: string[] = []
switch (variant.name) {
case "Dark Hard": {
case "Dark Hard":
neutral = darkHardNeutral
break
}
case "Dark": {
case "Dark":
neutral = darkNeutral
break
}
case "Dark Soft": {
case "Dark Soft":
neutral = darkSoftNeutral
break
}
case "Light Hard": {
case "Light Hard":
neutral = lightHardNeutral
break
}
case "Light": {
case "Light":
neutral = lightNeutral
break
}
case "Light Soft": {
case "Light Soft":
neutral = lightSoftNeutral
break
}
}
const ramps = {

View file

@ -1,4 +1,4 @@
import { Clean } from "./util"
import * as zed from './zed'
import * as zed from "./zed"
export type Text = Clean<zed.TextStyle>

View file

@ -1,5 +1,5 @@
import * as StyleTree from './styleTree'
import * as Property from './property'
import * as Element from './element'
import * as StyleTree from "./styleTree"
import * as Property from "./property"
import * as Element from "./element"
export { StyleTree, Property, Element }

View file

@ -1,5 +1,5 @@
import { Clean } from './util'
import * as zed from './zed'
import { Clean } from "./util"
import * as zed from "./zed"
export type Color = zed.Color
export type CursorStyle = zed.CursorStyle

View file

@ -1,29 +1,33 @@
import { Clean } from './util'
import * as zed from './zed'
import { Clean } from "./util"
import * as zed from "./zed"
export type AssistantStyle = Readonly<Clean<zed.AssistantStyle>>;
export type CommandPalette = Readonly<Clean<zed.CommandPalette>>;
export type ContactFinder = Readonly<Clean<zed.ContactFinder>>;
export type ContactList = Readonly<Clean<zed.ContactList>>;
export type ContactNotification = Readonly<Clean<zed.ContactNotification>>;
export type ContactsPopover = Readonly<Clean<zed.ContactsPopover>>;
export type ContextMenu = Readonly<Clean<zed.ContextMenu>>;
export type Copilot = Readonly<Clean<zed.Copilot>>;
export type Editor = Readonly<Clean<zed.Editor>>;
export type FeedbackStyle = Readonly<Clean<zed.FeedbackStyle>>;
export type IncomingCallNotification = Readonly<Clean<zed.IncomingCallNotification>>;
export type ThemeMeta = Readonly<Clean<zed.ThemeMeta>>;
export type Picker = Readonly<Clean<zed.Picker>>;
export type ProjectDiagnostics = Readonly<Clean<zed.ProjectDiagnostics>>;
export type ProjectPanel = Readonly<Clean<zed.ProjectPanel>>;
export type ProjectSharedNotification = Readonly<Clean<zed.ProjectSharedNotification>>;
export type Search = Readonly<Clean<zed.Search>>;
export type SharedScreen = Readonly<Clean<zed.ContainerStyle>>;
export type MessageNotification = Readonly<Clean<zed.MessageNotification>>;
export type TerminalStyle = Readonly<Clean<zed.TerminalStyle>>;
export type UserMenu = Readonly<Clean<zed.UserMenu>>;
export type DropdownMenu = Readonly<Clean<zed.DropdownMenu>>;
export type TooltipStyle = Readonly<Clean<zed.TooltipStyle>>;
export type UpdateNotification = Readonly<Clean<zed.UpdateNotification>>;
export type WelcomeStyle = Readonly<Clean<zed.WelcomeStyle>>;
export type Workspace = Readonly<Clean<zed.Workspace>>;
export type AssistantStyle = Readonly<Clean<zed.AssistantStyle>>
export type CommandPalette = Readonly<Clean<zed.CommandPalette>>
export type ContactFinder = Readonly<Clean<zed.ContactFinder>>
export type ContactList = Readonly<Clean<zed.ContactList>>
export type ContactNotification = Readonly<Clean<zed.ContactNotification>>
export type ContactsPopover = Readonly<Clean<zed.ContactsPopover>>
export type ContextMenu = Readonly<Clean<zed.ContextMenu>>
export type Copilot = Readonly<Clean<zed.Copilot>>
export type Editor = Readonly<Clean<zed.Editor>>
export type FeedbackStyle = Readonly<Clean<zed.FeedbackStyle>>
export type IncomingCallNotification = Readonly<
Clean<zed.IncomingCallNotification>
>
export type ThemeMeta = Readonly<Clean<zed.ThemeMeta>>
export type Picker = Readonly<Clean<zed.Picker>>
export type ProjectDiagnostics = Readonly<Clean<zed.ProjectDiagnostics>>
export type ProjectPanel = Readonly<Clean<zed.ProjectPanel>>
export type ProjectSharedNotification = Readonly<
Clean<zed.ProjectSharedNotification>
>
export type Search = Readonly<Clean<zed.Search>>
export type SharedScreen = Readonly<Clean<zed.ContainerStyle>>
export type MessageNotification = Readonly<Clean<zed.MessageNotification>>
export type TerminalStyle = Readonly<Clean<zed.TerminalStyle>>
export type UserMenu = Readonly<Clean<zed.UserMenu>>
export type DropdownMenu = Readonly<Clean<zed.DropdownMenu>>
export type TooltipStyle = Readonly<Clean<zed.TooltipStyle>>
export type UpdateNotification = Readonly<Clean<zed.UpdateNotification>>
export type WelcomeStyle = Readonly<Clean<zed.WelcomeStyle>>
export type Workspace = Readonly<Clean<zed.Workspace>>

View file

@ -1,15 +1,17 @@
export type Prettify<T> = {
[K in keyof T]: T[K];
} & unknown;
[K in keyof T]: T[K]
} & unknown
/**
* Clean removes the [k: string]: unknown property from an object,
* and Prettifies it, providing better hover information for the type
*/
* Clean removes the [k: string]: unknown property from an object,
* and Prettifies it, providing better hover information for the type
*/
export type Clean<T> = {
[K in keyof T as string extends K ? never : K]: T[K];
[K in keyof T as string extends K ? never : K]: T[K]
}
export type DeepClean<T> = {
[K in keyof T as string extends K ? never : K]: T[K] extends object ? DeepClean<T[K]> : T[K];
[K in keyof T as string extends K ? never : K]: T[K] extends object
? DeepClean<T[K]>
: T[K]
}

View file

@ -3,8 +3,8 @@ export function slugify(t: string): string {
.toString()
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/[^\w\-]+/g, "")
.replace(/\-\-+/g, "-")
.replace(/[^\w-]+/g, "")
.replace(/--+/g, "-")
.replace(/^-+/, "")
.replace(/-+$/, "")
}

View file

@ -5,8 +5,8 @@ import { snakeCase } from "case-anything"
// Typescript magic to convert any string from camelCase to snake_case at compile time
type SnakeCase<S> = S extends string
? S extends `${infer T}${infer U}`
? `${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${SnakeCase<U>}`
: S
? `${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${SnakeCase<U>}`
: S
: S
type SnakeCased<Type> = {
@ -14,7 +14,7 @@ type SnakeCased<Type> = {
}
export default function snakeCaseTree<T>(object: T): SnakeCased<T> {
const snakeObject: any = {}
const snakeObject: any = {} // eslint-disable-line @typescript-eslint/no-explicit-any
for (const key in object) {
snakeObject[snakeCase(key, { keepSpecialCharacters: true })] =
snakeCaseValue(object[key])
@ -22,6 +22,7 @@ export default function snakeCaseTree<T>(object: T): SnakeCased<T> {
return snakeObject
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function snakeCaseValue(value: any): any {
if (typeof value === "object") {
if (Array.isArray(value)) {

View file

@ -21,16 +21,36 @@
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"skipLibCheck": true,
"useUnknownInCatchVariables": false,
"baseUrl": ".",
"paths": {
"@/*": ["./*"],
"@element/*": ["./src/element/*"],
"@component/*": ["./src/component/*"],
"@styleTree/*": ["./src/styleTree/*"],
"@theme/*": ["./src/theme/*"],
"@themes/*": ["./src/themes/*"],
"@util/*": ["./src/util/*"]
"@/*": [
"./*"
],
"@element/*": [
"./src/element/*"
],
"@component/*": [
"./src/component/*"
],
"@styleTree/*": [
"./src/styleTree/*"
],
"@theme/*": [
"./src/theme/*"
],
"@types/*": [
"./src/util/*"
],
"@themes/*": [
"./src/themes/*"
],
"@util/*": [
"./src/util/*"
]
}
},
"exclude": ["node_modules"]
"exclude": [
"node_modules"
]
}