@aglyn/shared-data-enums 1.0.0-beta.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +3 -0
- package/package.json +39 -0
- package/src/enums.d.ts +26 -0
- package/src/enums.js +27 -0
- package/src/enums.js.map +1 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +18 -0
- package/src/index.js.map +1 -0
- package/src/lib/aglyn-applications.d.ts +39 -0
- package/src/lib/aglyn-applications.js +53 -0
- package/src/lib/aglyn-applications.js.map +1 -0
- package/src/lib/aglyn.d.ts +49 -0
- package/src/lib/aglyn.js +86 -0
- package/src/lib/aglyn.js.map +1 -0
- package/src/lib/breakpoint-span.d.ts +66 -0
- package/src/lib/breakpoint-span.js +117 -0
- package/src/lib/breakpoint-span.js.map +1 -0
- package/src/lib/data-table.d.ts +107 -0
- package/src/lib/data-table.js +225 -0
- package/src/lib/data-table.js.map +1 -0
- package/src/lib/firebase-auth.d.ts +73 -0
- package/src/lib/firebase-auth.js +178 -0
- package/src/lib/firebase-auth.js.map +1 -0
- package/src/lib/global.d.ts +32 -0
- package/src/lib/global.js +33 -0
- package/src/lib/global.js.map +1 -0
- package/src/lib/http.d.ts +145 -0
- package/src/lib/http.js +155 -0
- package/src/lib/http.js.map +1 -0
- package/src/lib/icons.d.ts +108 -0
- package/src/lib/icons.js +130 -0
- package/src/lib/icons.js.map +1 -0
- package/src/lib/palette-token-css-var.d.ts +111 -0
- package/src/lib/palette-token-css-var.js +221 -0
- package/src/lib/palette-token-css-var.js.map +1 -0
- package/src/lib/styles.d.ts +170 -0
- package/src/lib/styles.js +315 -0
- package/src/lib/styles.js.map +1 -0
- package/src/lib/sx-property-aliases.d.ts +129 -0
- package/src/lib/sx-property-aliases.js +231 -0
- package/src/lib/sx-property-aliases.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/data/enums/src/lib/palette-token-css-var.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2023 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Palette tokens as CSS custom properties: the `var(--mui-palette-…)` form a\n * bound colour is persisted in, its channel variant for author-chosen alpha,\n * and the readers that take both back apart.\n *\n * Its own module because a published page reads only these — the sx palette\n * resolver rewrites every token-bound colour on the page through them — while\n * `styles.ts` around it is authoring-surface work: the unit enum and its\n * pickers, the dimension parser, and the whole gradient model. None of that\n * runs to resolve a colour, and a bundler cannot drop it around three named\n * imports.\n */\n\n/**\n * Splits a CSS argument list on TOP-LEVEL commas, respecting nesting.\n *\n * Exported because the gradient parser in `styles.ts` splits stop lists with\n * the same rule; one implementation, so a nested `rgba()` cannot start\n * parsing differently in the two places.\n */\nexport function splitTopLevelArgs(text: string): string[] {\n const args: string[] = []\n let depth = 0\n let start = 0\n for (let i = 0; i < text.length; i += 1) {\n const char = text[i]\n if (char === '(') depth += 1\n else if (char === ')') depth -= 1\n // A comma inside `var(--x, #fff)` or `rgba(0, 0, 0, .5)` belongs to\n // that function, not to the stop list.\n else if (char === ',' && depth === 0) {\n args.push(text.slice(start, i).trim())\n start = i + 1\n }\n }\n args.push(text.slice(start).trim())\n return args\n}\n\n/**\n * CSS custom-property prefix MUI uses for palette entries — the same one\n * `theme.vars.palette.*` emits under the default `mui` cssVarPrefix.\n *\n * A gradient stop bound to a THEME TOKEN is persisted as\n * `var(--mui-palette-primary-main, #00B0FF)` (AGL-1331): `backgroundImage`\n * is not one of MUI's palette-keyed sx properties (only `color`, `bgcolor`\n * and `backgroundColor` are), so a bare `primary.main` inside a gradient\n * would reach CSS verbatim and the whole declaration would be dropped —\n * the exact silent failure this issue is about. A `var()` reference with a\n * literal fallback is valid CSS everywhere, so the worst case is the\n * fallback colour, never a vanished background.\n */\nconst PALETTE_CSS_VAR_PREFIX = '--mui-palette-'\n\n/** A palette token reference parsed out of a `var()` expression. */\nexport interface PaletteTokenRef {\n /** Dot path into the palette, e.g. `primary.main`. */\n path: string\n /** Literal colour rendered when the custom property is undefined. */\n fallback?: string\n}\n\n/**\n * The CSS custom-property name a palette token path maps to:\n * `primary.main` becomes `--mui-palette-primary-main`, matching MUI's own\n * naming. Path segments are lowercase words in every token the picker\n * offers, so the `.`/`-` swap is exactly reversible by\n * {@link cssVarNameToPaletteToken}.\n */\nexport function paletteTokenToCssVarName(path: string): string {\n return `${PALETTE_CSS_VAR_PREFIX}${path.trim().split('.').join('-')}`\n}\n\n/** Inverse of {@link paletteTokenToCssVarName}; undefined for other vars. */\nexport function cssVarNameToPaletteToken(name: string): string | undefined {\n const trimmed = name.trim()\n if (!trimmed.startsWith(PALETTE_CSS_VAR_PREFIX)) return undefined\n const rest = trimmed.slice(PALETTE_CSS_VAR_PREFIX.length)\n return rest ? rest.split('-').join('.') : undefined\n}\n\n/** Builds the persisted form of a token-bound colour. */\nexport function paletteTokenToCssVar(path: string, fallback?: string): string {\n const name = paletteTokenToCssVarName(path)\n return fallback ? `var(${name}, ${fallback})` : `var(${name})`\n}\n\n/**\n * Reads a `var(--mui-palette-…[, fallback])` expression back into its token\n * path plus fallback. Anything else (a literal, a non-palette custom\n * property) returns undefined so callers treat it as a plain colour.\n */\nexport function parsePaletteTokenCssVar(\n value: string | undefined | null,\n): PaletteTokenRef | undefined {\n if (!value) return undefined\n const text = `${value}`.trim()\n if (!text.toLowerCase().startsWith('var(') || !text.endsWith(')')) {\n return undefined\n }\n const [name, ...fallbackParts] = splitTopLevelArgs(text.slice(4, -1))\n if (name === undefined) return undefined\n const path = cssVarNameToPaletteToken(name)\n if (!path) return undefined\n const fallback = fallbackParts.join(', ').trim()\n return fallback ? { path, fallback } : { path }\n}\n\n/**\n * Suffix MUI appends to a palette custom property holding the SPACE-SEPARATED\n * RGB channels of a colour — `--mui-palette-primary-mainChannel` is\n * `31 41 55` where `--mui-palette-primary-main` is `#1F2937`.\n *\n * MUI publishes these for exactly one reason: so alpha can be applied to a\n * palette TOKEN at render time, as `rgba(var(…Channel) / 0.12)`, instead of\n * the token being flattened to a literal `rgba(…)` by\n * whoever wrote the style. That distinction is the whole feature: a flattened\n * literal stops following the palette, so a white-label site or a palette\n * change keeps the old colour for ever and nothing reports it. The designer's\n * own chrome already uses this form (`box-styler/components/box-diagram.tsx`).\n */\nconst PALETTE_CHANNEL_SUFFIX = 'Channel'\n\n/** `primary.main` → `--mui-palette-primary-mainChannel`. */\nexport function paletteTokenToChannelCssVarName(path: string): string {\n return `${paletteTokenToCssVarName(path)}${PALETTE_CHANNEL_SUFFIX}`\n}\n\n/**\n * The palette path a CHANNEL custom property names — `primary.main` for\n * `--mui-palette-primary-mainChannel` — or undefined when the name is not a\n * channel reference. Note this returns the path of the COLOUR, not of a\n * `mainChannel` key: a theme built with plain `createTheme` (which is what\n * `createResponsiveTheme` does) has no channel entries at all, so the\n * resolver derives the triplet from the colour itself.\n */\nexport function channelCssVarNameToPaletteToken(\n name: string,\n): string | undefined {\n const trimmed = `${name ?? ''}`.trim()\n // Case-insensitive on the suffix only: CSS custom properties ARE\n // case-sensitive, but a value that reached us through a CSS minifier or a\n // hand edit should still round-trip into the picker rather than reading as\n // an opaque literal.\n if (\n trimmed.slice(-PALETTE_CHANNEL_SUFFIX.length).toLowerCase() !==\n PALETTE_CHANNEL_SUFFIX.toLowerCase()\n ) {\n return undefined\n }\n return cssVarNameToPaletteToken(\n trimmed.slice(0, -PALETTE_CHANNEL_SUFFIX.length),\n )\n}\n\nconst HEX_CHANNEL_PATTERN = /^#([0-9a-f]{3,8})$/i\nconst RGB_FUNCTION_PATTERN = /^rgba?\\(([^()]*)\\)$/i\n\n/**\n * A colour's `R G B` triplet — MUI's channel form — or undefined when the\n * value is not one this can read (a named colour, `hsl()`, a `var()` that has\n * not been substituted yet). Undefined is a real answer: the caller then\n * leaves the reference's literal fallback in place rather than emitting a\n * malformed `rgba()` that the browser would drop.\n *\n * An alpha component in the input is deliberately DISCARDED — the channel is\n * the colour, and the alpha being applied is the author's, not the palette's.\n */\nexport function cssColorToChannel(\n color: string | undefined | null,\n): string | undefined {\n const text = `${color ?? ''}`.trim()\n if (!text) return undefined\n const hex = HEX_CHANNEL_PATTERN.exec(text)\n if (hex) {\n const digits = hex[1]\n // `#abc` and `#abcd` are shorthand: each digit doubles. The 8-digit form\n // carries alpha in the last pair, which is dropped with the rest.\n const expanded =\n digits.length <= 4\n ? digits\n .split('')\n .map((digit) => `${digit}${digit}`)\n .join('')\n : digits\n if (expanded.length < 6) return undefined\n const channels = [0, 2, 4].map((offset) =>\n Number.parseInt(expanded.slice(offset, offset + 2), 16),\n )\n return channels.some((channel) => Number.isNaN(channel))\n ? undefined\n : channels.join(' ')\n }\n const fn = RGB_FUNCTION_PATTERN.exec(text)\n if (!fn) return undefined\n // Both the legacy comma form and the modern `r g b / a` form, since either\n // can appear in a hand-authored palette.\n const parts = fn[1]\n .split('/')[0]\n .split(/[\\s,]+/)\n .filter((part) => part !== '')\n if (parts.length < 3) return undefined\n const channels = parts.slice(0, 3).map((part) => Number.parseFloat(part))\n if (channels.some((channel) => !Number.isFinite(channel))) return undefined\n return channels.map((channel) => Math.round(channel)).join(' ')\n}\n\n/** A palette token carrying an author-chosen alpha. */\nexport interface PaletteAlphaTokenRef {\n /** Dot path into the palette, e.g. `primary.main`. */\n path: string\n /** Opacity in [0, 1]. */\n alpha: number\n /** Literal channel triplet rendered when the custom property is undefined. */\n fallback?: string\n}\n\n/**\n * The persisted form of \"a theme token at N% opacity\":\n * `rgba(var(--mui-palette-primary-mainChannel, 31 41 55) / 0.12)`.\n *\n * A CSS var reference with a literal fallback, exactly like the gradient\n * field's token stops (AGL-1331) — the reference is what keeps the value a\n * TOKEN, and the fallback is what renders if the substitution pass is ever\n * skipped, so the worst case is a slightly stale colour rather than a dropped\n * declaration. `fallbackColor` is the colour the token resolves to today; it\n * is converted to channels here so callers never have to know the form.\n */\nexport function paletteTokenToAlphaCssVar(\n path: string,\n alpha: number,\n fallbackColor?: string,\n): string {\n const name = paletteTokenToChannelCssVarName(path)\n const fallback = cssColorToChannel(fallbackColor)\n const reference = fallback ? `var(${name}, ${fallback})` : `var(${name})`\n // Trimmed so `0.5` does not persist as `0.50`, and clamped because an\n // out-of-range alpha is a dropped declaration, not a clipped colour.\n const clamped = Math.min(1, Math.max(0, Number(alpha)))\n const amount = Number.isFinite(clamped) ? Number(clamped.toFixed(4)) : 1\n return `rgba(${reference} / ${amount})`\n}\n\nconst ALPHA_TOKEN_PATTERN =\n /^rgba?\\(\\s*var\\(\\s*(--mui-palette-[a-z0-9-]+channel)\\s*(?:,([^()]*))?\\)\\s*\\/\\s*([0-9]*\\.?[0-9]+)\\s*\\)$/i\n\n/**\n * Reads {@link paletteTokenToAlphaCssVar} back into its token path and alpha,\n * so re-opening the picker on a stored value shows the TOKEN and its opacity\n * rather than an opaque string. Anything else returns undefined and is treated\n * as a plain colour.\n */\nexport function parsePaletteTokenAlphaCssVar(\n value: string | undefined | null,\n): PaletteAlphaTokenRef | undefined {\n if (!value) return undefined\n const matched = ALPHA_TOKEN_PATTERN.exec(`${value}`.trim())\n if (!matched) return undefined\n const path = channelCssVarNameToPaletteToken(matched[1])\n if (!path) return undefined\n const alpha = Number.parseFloat(matched[3])\n if (!Number.isFinite(alpha) || alpha < 0 || alpha > 1) return undefined\n const fallback = (matched[2] ?? '').trim()\n return fallback ? { path, alpha, fallback } : { path, alpha }\n}\n"],"names":["splitTopLevelArgs","text","args","depth","start","i","length","char","push","slice","trim","PALETTE_CSS_VAR_PREFIX","paletteTokenToCssVarName","path","split","join","cssVarNameToPaletteToken","name","trimmed","startsWith","undefined","rest","paletteTokenToCssVar","fallback","parsePaletteTokenCssVar","value","toLowerCase","endsWith","fallbackParts","PALETTE_CHANNEL_SUFFIX","paletteTokenToChannelCssVarName","channelCssVarNameToPaletteToken","HEX_CHANNEL_PATTERN","RGB_FUNCTION_PATTERN","cssColorToChannel","color","hex","exec","digits","expanded","map","digit","channels","offset","Number","parseInt","some","channel","isNaN","fn","parts","filter","part","parseFloat","isFinite","Math","round","paletteTokenToAlphaCssVar","alpha","fallbackColor","reference","clamped","min","max","amount","toFixed","ALPHA_TOKEN_PATTERN","parsePaletteTokenAlphaCssVar","matched"],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
export * from './palette-token-css-var';
|
|
18
|
+
export declare enum CssUnit {
|
|
19
|
+
INITIAL = "initial",
|
|
20
|
+
UNSET = "unset",
|
|
21
|
+
INHERIT = "inherit",
|
|
22
|
+
AUTO = "auto",
|
|
23
|
+
PIXELS = "px",
|
|
24
|
+
EM = "em",
|
|
25
|
+
PERCENT = "%",
|
|
26
|
+
REM = "rem",
|
|
27
|
+
POINTS = "pt",
|
|
28
|
+
PICAS = "pc",
|
|
29
|
+
CH = "ch",
|
|
30
|
+
VIEWPORT_WIDTH = "vw",
|
|
31
|
+
VIEWPORT_HEIGHT = "vh",
|
|
32
|
+
VIEWPORT_MAX = "vmax",
|
|
33
|
+
VIEWPORT_MIN = "vmin",
|
|
34
|
+
SMALL_VIEWPORT_WIDTH = "svw",
|
|
35
|
+
SMALL_VIEWPORT_HEIGHT = "svh",
|
|
36
|
+
LARGE_VIEWPORT_WIDTH = "lvw",
|
|
37
|
+
LARGE_VIEWPORT_HEIGHT = "lvh",
|
|
38
|
+
DYNAMIC_VIEWPORT_WIDTH = "dvw",
|
|
39
|
+
DYNAMIC_VIEWPORT_HEIGHT = "dvh",
|
|
40
|
+
DPI = "dpi",
|
|
41
|
+
MILLIMETERS = "mm",
|
|
42
|
+
CENTIMETERS = "cm",
|
|
43
|
+
INCHES = "in"
|
|
44
|
+
}
|
|
45
|
+
export declare function isGlobalUnit(unit: CssUnit): unit is CssUnit.INITIAL | CssUnit.UNSET | CssUnit.INHERIT | CssUnit.AUTO;
|
|
46
|
+
/**
|
|
47
|
+
* A CSS dimension split into the parts an editor can put on screen
|
|
48
|
+
* (AGL-1219): a numeric quantity plus its unit, a bare keyword unit
|
|
49
|
+
* (`auto`, `inherit`, …), or — when the string is richer than
|
|
50
|
+
* `<number><unit>` — the original text under `raw`.
|
|
51
|
+
*
|
|
52
|
+
* `raw` is the escape hatch that keeps an editor from destroying what it
|
|
53
|
+
* cannot model: `calc(100% - 2rem)`, `clamp(…)`, `min-content` and a
|
|
54
|
+
* `{{token}}` binding all round-trip untouched instead of collapsing to
|
|
55
|
+
* whatever a lenient parse happened to salvage.
|
|
56
|
+
*/
|
|
57
|
+
export interface CssDimension {
|
|
58
|
+
/** Quantity, absent for keyword units and for unparsed (`raw`) values. */
|
|
59
|
+
value?: number;
|
|
60
|
+
unit?: CssUnit;
|
|
61
|
+
/** Set ONLY when the value is not a plain `<number><unit>`. */
|
|
62
|
+
raw?: string;
|
|
63
|
+
}
|
|
64
|
+
/** Every unit the pickers offer, in enum order — ONE list, no second one. */
|
|
65
|
+
export declare const CSS_UNITS: CssUnit[];
|
|
66
|
+
/**
|
|
67
|
+
* Splits a CSS dimension string into {@link CssDimension}. Anything that is
|
|
68
|
+
* not empty, a keyword unit, or `<number><known unit>` comes back as `raw`
|
|
69
|
+
* so callers can hand it straight back (AGL-1219).
|
|
70
|
+
*/
|
|
71
|
+
export declare function parseCssDimension(value: string | number | undefined | null): CssDimension;
|
|
72
|
+
/**
|
|
73
|
+
* Serializes a {@link CssDimension} back to the single CSS string that gets
|
|
74
|
+
* persisted. The inverse of {@link parseCssDimension}: an empty dimension
|
|
75
|
+
* serializes to an empty string, never to a partial value like `px`.
|
|
76
|
+
*/
|
|
77
|
+
export declare function buildCssDimension(dimension?: CssDimension): string;
|
|
78
|
+
export type CssGradientType = 'linear' | 'radial';
|
|
79
|
+
/** One colour stop of a gradient the Background field can edit. */
|
|
80
|
+
export interface CssGradientStop {
|
|
81
|
+
/**
|
|
82
|
+
* Stop colour: a literal (`#7A5CF0`, `rgb(…)`) or a palette token
|
|
83
|
+
* reference from {@link paletteTokenToCssVar}. Both forms are allowed on
|
|
84
|
+
* the same gradient — the marketing CTA's endpoints are tokens while its
|
|
85
|
+
* mid stop has no token and stays a hex (AGL-1331).
|
|
86
|
+
*/
|
|
87
|
+
color: string;
|
|
88
|
+
/** Position along the ramp in percent; omitted lets CSS distribute it. */
|
|
89
|
+
position?: number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* A gradient split into the parts the Background field puts on screen
|
|
93
|
+
* (AGL-1331) — the {@link CssDimension} idiom applied to `backgroundImage`.
|
|
94
|
+
*
|
|
95
|
+
* `raw` is the same escape hatch: a `conic-gradient`, a `to bottom right`
|
|
96
|
+
* direction, a multi-position stop or a stacked image list round-trips
|
|
97
|
+
* untouched instead of being flattened into whatever a lenient parse
|
|
98
|
+
* salvaged.
|
|
99
|
+
*/
|
|
100
|
+
export interface CssGradient {
|
|
101
|
+
type: CssGradientType;
|
|
102
|
+
/** Degrees, linear only. Absent means CSS's default (`to bottom`). */
|
|
103
|
+
angle?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Where a RADIAL gradient's centre sits, in percent of the box
|
|
106
|
+
*. Absent means CSS's default, dead centre.
|
|
107
|
+
*
|
|
108
|
+
* A radial gradient is how a page paints a glow, and a glow is almost
|
|
109
|
+
* never centred — the one behind a hero sits high and bleeds off the top.
|
|
110
|
+
* Without this the control could only ever centre it, so authors either
|
|
111
|
+
* accepted a halo in the middle of their text or dropped to Custom CSS.
|
|
112
|
+
* Linear's counterpart is {@link angle}; this is radial's.
|
|
113
|
+
*/
|
|
114
|
+
position?: {
|
|
115
|
+
x: number;
|
|
116
|
+
y: number;
|
|
117
|
+
};
|
|
118
|
+
stops: CssGradientStop[];
|
|
119
|
+
/** Set ONLY when the value is a gradient this model cannot express. */
|
|
120
|
+
raw?: string;
|
|
121
|
+
}
|
|
122
|
+
/** Whether a value is gradient-shaped — the check the colour fields reject on. */
|
|
123
|
+
export declare function isCssGradientValue(value: unknown): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Splits a `backgroundImage` value into {@link CssGradient}. Returns
|
|
126
|
+
* undefined when the value is empty or is not a gradient at all (a `url(…)`
|
|
127
|
+
* image, say), and a `raw`-carrying gradient when it is one this model
|
|
128
|
+
* cannot express — never a lossy approximation.
|
|
129
|
+
*
|
|
130
|
+
* `background-image` is a comma-separated LAYER LIST and this model holds
|
|
131
|
+
* ONE layer, so the layer split happens before anything else (AGL-1336).
|
|
132
|
+
* Without it `linear-gradient(#000 0%, #fff 100%), url(/hero.jpg)` parsed
|
|
133
|
+
* as a single two-stop gradient whose second stop was the whole string
|
|
134
|
+
* `#fff 100%), url(/hero.jpg` — the function pattern is greedy to the last
|
|
135
|
+
* `)`, and the stray `)` it swallowed then suppressed the top-level comma
|
|
136
|
+
* split. That round-tripped BYTE-IDENTICAL, so nothing looked wrong until
|
|
137
|
+
* the author's first stop edit re-serialized the model and the `url()`
|
|
138
|
+
* layer was gone for good. A stacked value now takes the `raw` path, where
|
|
139
|
+
* the field shows the CSS verbatim and hands it back untouched.
|
|
140
|
+
*/
|
|
141
|
+
export declare function parseCssGradient(value: string | undefined | null): CssGradient | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Serializes a {@link CssGradient} back to the single CSS string persisted
|
|
144
|
+
* under `backgroundImage`. The inverse of {@link parseCssGradient}: fewer
|
|
145
|
+
* than two usable stops serializes to `''` (which clears the property)
|
|
146
|
+
* rather than to a half-written `linear-gradient(` no parser accepts.
|
|
147
|
+
*/
|
|
148
|
+
export declare function buildCssGradient(gradient?: CssGradient): string;
|
|
149
|
+
/**
|
|
150
|
+
* Why a value cannot be a colour, or undefined when it can (AGL-1331).
|
|
151
|
+
*
|
|
152
|
+
* The colour fields' real contract is "a palette token path (`primary.main`)
|
|
153
|
+
* or a valid CSS `<color>`". Before this, `getStrValue` handed any string
|
|
154
|
+
* through, the form was `noValidate`, and a gradient typed into Background
|
|
155
|
+
* Color was stored as `background-color: linear-gradient(…)` — which the
|
|
156
|
+
* CSS parser drops, leaving a transparent element and no error anywhere.
|
|
157
|
+
*
|
|
158
|
+
* Deliberately permissive about what a colour IS: any function form is
|
|
159
|
+
* accepted except the image-producing ones, so `color-mix()`, `oklch()` and
|
|
160
|
+
* whatever CSS adds next are never rejected by a stale allowlist. The job
|
|
161
|
+
* here is to catch the value that would VANISH, not to re-implement the CSS
|
|
162
|
+
* colour grammar.
|
|
163
|
+
*/
|
|
164
|
+
export declare function describeCssColorProblem(value: unknown): string | undefined;
|
|
165
|
+
export declare function parseCssMeasurement(value: string | undefined): Measurement;
|
|
166
|
+
export declare function buildCssMeasurement(measurement: Measurement): string | undefined;
|
|
167
|
+
export interface Measurement {
|
|
168
|
+
unit?: CssUnit;
|
|
169
|
+
value?: number;
|
|
170
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { _isEqualitySameType, _isNum, _isStrT } from "@aglyn/shared-util-tools";
|
|
17
|
+
import { splitTopLevelArgs } from "./palette-token-css-var.js";
|
|
18
|
+
export * from "./palette-token-css-var.js";
|
|
19
|
+
export var CssUnit = /*#__PURE__*/ function(CssUnit) {
|
|
20
|
+
CssUnit["INITIAL"] = "initial";
|
|
21
|
+
CssUnit["UNSET"] = "unset";
|
|
22
|
+
CssUnit["INHERIT"] = "inherit";
|
|
23
|
+
CssUnit["AUTO"] = "auto";
|
|
24
|
+
CssUnit["PIXELS"] = "px";
|
|
25
|
+
CssUnit["EM"] = "em";
|
|
26
|
+
CssUnit["PERCENT"] = "%";
|
|
27
|
+
CssUnit["REM"] = "rem";
|
|
28
|
+
CssUnit["POINTS"] = "pt";
|
|
29
|
+
CssUnit["PICAS"] = "pc";
|
|
30
|
+
CssUnit["CH"] = "ch";
|
|
31
|
+
CssUnit["VIEWPORT_WIDTH"] = "vw";
|
|
32
|
+
CssUnit["VIEWPORT_HEIGHT"] = "vh";
|
|
33
|
+
CssUnit["VIEWPORT_MAX"] = "vmax";
|
|
34
|
+
CssUnit["VIEWPORT_MIN"] = "vmin";
|
|
35
|
+
// Small/large/dynamic viewport units (AGL-2486). On a phone the address
|
|
36
|
+
// bar slides away as the visitor scrolls, so `vh` changes height mid-
|
|
37
|
+
// scroll and anything sized in it jumps. `svh` is the window at its
|
|
38
|
+
// SMALLEST (bar showing) and never jumps, `lvh` the largest, `dvh` the
|
|
39
|
+
// live value. On desktop all three equal `vh`.
|
|
40
|
+
CssUnit["SMALL_VIEWPORT_WIDTH"] = "svw";
|
|
41
|
+
CssUnit["SMALL_VIEWPORT_HEIGHT"] = "svh";
|
|
42
|
+
CssUnit["LARGE_VIEWPORT_WIDTH"] = "lvw";
|
|
43
|
+
CssUnit["LARGE_VIEWPORT_HEIGHT"] = "lvh";
|
|
44
|
+
CssUnit["DYNAMIC_VIEWPORT_WIDTH"] = "dvw";
|
|
45
|
+
CssUnit["DYNAMIC_VIEWPORT_HEIGHT"] = "dvh";
|
|
46
|
+
CssUnit["DPI"] = "dpi";
|
|
47
|
+
CssUnit["MILLIMETERS"] = "mm";
|
|
48
|
+
CssUnit["CENTIMETERS"] = "cm";
|
|
49
|
+
CssUnit["INCHES"] = "in";
|
|
50
|
+
return CssUnit;
|
|
51
|
+
}({});
|
|
52
|
+
export function isGlobalUnit(unit) {
|
|
53
|
+
return _isEqualitySameType(unit, null, "initial", "unset", "inherit", "auto");
|
|
54
|
+
}
|
|
55
|
+
const UNIT_BY_TOKEN = Object.fromEntries(Object.values(CssUnit).map((unit)=>[
|
|
56
|
+
`${unit}`.toLowerCase(),
|
|
57
|
+
unit
|
|
58
|
+
]));
|
|
59
|
+
/** Every unit the pickers offer, in enum order — ONE list, no second one. */ export const CSS_UNITS = Object.values(CssUnit);
|
|
60
|
+
/** `12`, `-4.5`, `.75` — the quantity, then its (possibly empty) unit. */ const CSS_DIMENSION_PATTERN = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))([a-z%]*)$/i;
|
|
61
|
+
/**
|
|
62
|
+
* Splits a CSS dimension string into {@link CssDimension}. Anything that is
|
|
63
|
+
* not empty, a keyword unit, or `<number><known unit>` comes back as `raw`
|
|
64
|
+
* so callers can hand it straight back (AGL-1219).
|
|
65
|
+
*/ export function parseCssDimension(value) {
|
|
66
|
+
if (value === undefined || value === null) return {};
|
|
67
|
+
const text = `${value}`.trim();
|
|
68
|
+
if (!text) return {};
|
|
69
|
+
const known = UNIT_BY_TOKEN[text.toLowerCase()];
|
|
70
|
+
// A bare keyword (`auto`) is the whole value; `px` alone is not a value.
|
|
71
|
+
if (known && isGlobalUnit(known)) return {
|
|
72
|
+
unit: known
|
|
73
|
+
};
|
|
74
|
+
const match = CSS_DIMENSION_PATTERN.exec(text);
|
|
75
|
+
if (!match) return {
|
|
76
|
+
raw: text
|
|
77
|
+
};
|
|
78
|
+
const [, quantity, suffix] = match;
|
|
79
|
+
const unit = suffix ? UNIT_BY_TOKEN[suffix.toLowerCase()] : undefined;
|
|
80
|
+
// A recognized shape carrying an unrecognized unit (`10q`) is still
|
|
81
|
+
// meaningful CSS — pass it through rather than dropping the unit.
|
|
82
|
+
if (suffix && !unit) return {
|
|
83
|
+
raw: text
|
|
84
|
+
};
|
|
85
|
+
const parsed = Number(quantity);
|
|
86
|
+
if (!Number.isFinite(parsed)) return {
|
|
87
|
+
raw: text
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
value: parsed,
|
|
91
|
+
unit
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Serializes a {@link CssDimension} back to the single CSS string that gets
|
|
96
|
+
* persisted. The inverse of {@link parseCssDimension}: an empty dimension
|
|
97
|
+
* serializes to an empty string, never to a partial value like `px`.
|
|
98
|
+
*/ export function buildCssDimension(dimension) {
|
|
99
|
+
var _dimension_unit;
|
|
100
|
+
if (!dimension) return '';
|
|
101
|
+
if (dimension.raw !== undefined) return dimension.raw;
|
|
102
|
+
if (dimension.unit && isGlobalUnit(dimension.unit)) return `${dimension.unit}`;
|
|
103
|
+
if (typeof dimension.value !== 'number' || !Number.isFinite(dimension.value)) {
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
return `${dimension.value}${(_dimension_unit = dimension.unit) != null ? _dimension_unit : ''}`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Whether every `(` is closed and none closes early — the precondition
|
|
110
|
+
* {@link splitTopLevelArgs} needs to be trusted (AGL-1336).
|
|
111
|
+
*
|
|
112
|
+
* Its depth counter goes NEGATIVE on a stray `)`, and a negative depth is
|
|
113
|
+
* never `0`, so every top-level comma after that stray paren stops being a
|
|
114
|
+
* split point. That is not a defect in the splitter — it is what makes
|
|
115
|
+
* checking balance first load-bearing rather than defensive.
|
|
116
|
+
*/ function hasBalancedParens(text) {
|
|
117
|
+
let depth = 0;
|
|
118
|
+
for (const char of text){
|
|
119
|
+
if (char === '(') depth += 1;
|
|
120
|
+
else if (char === ')') {
|
|
121
|
+
depth -= 1;
|
|
122
|
+
if (depth < 0) return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return depth === 0;
|
|
126
|
+
}
|
|
127
|
+
const GRADIENT_FUNCTION_PATTERN = /^([a-z-]*gradient)\s*\(([\s\S]*)\)$/i;
|
|
128
|
+
const GRADIENT_ANGLE_PATTERN = /^(-?\d+(?:\.\d+)?)deg$/i;
|
|
129
|
+
const GRADIENT_STOP_PATTERN = /^([\s\S]+?)\s+(-?\d+(?:\.\d+)?)%$/;
|
|
130
|
+
/** `at 50% 18%` — a radial gradient's centre, the only prefix form modelled. */ const GRADIENT_POSITION_PATTERN = /^at\s+(-?\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)%$/i;
|
|
131
|
+
/** Whether a value is gradient-shaped — the check the colour fields reject on. */ export function isCssGradientValue(value) {
|
|
132
|
+
return typeof value === 'string' && /(^|\s)[a-z-]*gradient\s*\(/i.test(value.trim());
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Splits a `backgroundImage` value into {@link CssGradient}. Returns
|
|
136
|
+
* undefined when the value is empty or is not a gradient at all (a `url(…)`
|
|
137
|
+
* image, say), and a `raw`-carrying gradient when it is one this model
|
|
138
|
+
* cannot express — never a lossy approximation.
|
|
139
|
+
*
|
|
140
|
+
* `background-image` is a comma-separated LAYER LIST and this model holds
|
|
141
|
+
* ONE layer, so the layer split happens before anything else (AGL-1336).
|
|
142
|
+
* Without it `linear-gradient(#000 0%, #fff 100%), url(/hero.jpg)` parsed
|
|
143
|
+
* as a single two-stop gradient whose second stop was the whole string
|
|
144
|
+
* `#fff 100%), url(/hero.jpg` — the function pattern is greedy to the last
|
|
145
|
+
* `)`, and the stray `)` it swallowed then suppressed the top-level comma
|
|
146
|
+
* split. That round-tripped BYTE-IDENTICAL, so nothing looked wrong until
|
|
147
|
+
* the author's first stop edit re-serialized the model and the `url()`
|
|
148
|
+
* layer was gone for good. A stacked value now takes the `raw` path, where
|
|
149
|
+
* the field shows the CSS verbatim and hands it back untouched.
|
|
150
|
+
*/ export function parseCssGradient(value) {
|
|
151
|
+
var _match_, _match_1, _args_;
|
|
152
|
+
var _match_2;
|
|
153
|
+
if (value === undefined || value === null) return undefined;
|
|
154
|
+
const text = `${value}`.trim();
|
|
155
|
+
if (!text || !isCssGradientValue(text)) return undefined;
|
|
156
|
+
/** Held verbatim: gradient-shaped, but not one this model can express. */ const unmodellable = {
|
|
157
|
+
type: 'linear',
|
|
158
|
+
stops: [],
|
|
159
|
+
raw: text
|
|
160
|
+
};
|
|
161
|
+
// Unbalanced parens make every split below meaningless, so refuse first.
|
|
162
|
+
if (!hasBalancedParens(text)) return unmodellable;
|
|
163
|
+
if (splitTopLevelArgs(text).filter((layer)=>layer !== '').length !== 1) {
|
|
164
|
+
return unmodellable;
|
|
165
|
+
}
|
|
166
|
+
const match = GRADIENT_FUNCTION_PATTERN.exec(text);
|
|
167
|
+
const fn = match == null ? void 0 : (_match_2 = match[1]) == null ? void 0 : _match_2.toLowerCase();
|
|
168
|
+
// Only the two the control can round-trip. `conic-gradient` and
|
|
169
|
+
// `repeating-linear-gradient` land in `raw` alongside the stacked lists.
|
|
170
|
+
if (!match || fn !== 'linear-gradient' && fn !== 'radial-gradient') {
|
|
171
|
+
return unmodellable;
|
|
172
|
+
}
|
|
173
|
+
// One layer, balanced overall, and still unbalanced INSIDE the captured
|
|
174
|
+
// body means the trailing `)` closes something else — `linear-gradient(a,
|
|
175
|
+
// b) url(x)` is one layer whose gradient is only part of it.
|
|
176
|
+
if (!hasBalancedParens((_match_ = match[2]) != null ? _match_ : '')) return unmodellable;
|
|
177
|
+
const type = fn === 'radial-gradient' ? 'radial' : 'linear';
|
|
178
|
+
const args = splitTopLevelArgs((_match_1 = match[2]) != null ? _match_1 : '').filter((arg)=>arg !== '');
|
|
179
|
+
const unparsed = {
|
|
180
|
+
type,
|
|
181
|
+
stops: [],
|
|
182
|
+
raw: text
|
|
183
|
+
};
|
|
184
|
+
let angle;
|
|
185
|
+
let position;
|
|
186
|
+
let stopArgs = args;
|
|
187
|
+
const first = (_args_ = args[0]) != null ? _args_ : '';
|
|
188
|
+
const angleMatch = GRADIENT_ANGLE_PATTERN.exec(first);
|
|
189
|
+
const positionMatch = GRADIENT_POSITION_PATTERN.exec(first);
|
|
190
|
+
if (angleMatch) {
|
|
191
|
+
if (type === 'radial') return unparsed;
|
|
192
|
+
angle = Number(angleMatch[1]);
|
|
193
|
+
stopArgs = args.slice(1);
|
|
194
|
+
} else if (positionMatch && type === 'radial') {
|
|
195
|
+
// `at X% Y%` is the one prefix the Position boxes round-trip. Anything
|
|
196
|
+
// richer (`ellipse 60% 40% at …`, `circle closest-side`) still falls
|
|
197
|
+
// through to `raw` below, so a hand-written gradient is never flattened.
|
|
198
|
+
position = {
|
|
199
|
+
x: Number(positionMatch[1]),
|
|
200
|
+
y: Number(positionMatch[2])
|
|
201
|
+
};
|
|
202
|
+
stopArgs = args.slice(1);
|
|
203
|
+
} else if (/^(to\s|at\s|circle|ellipse|closest|farthest|\d)/i.test(first)) {
|
|
204
|
+
// A direction or shape/position prefix the control has no editor for.
|
|
205
|
+
return unparsed;
|
|
206
|
+
}
|
|
207
|
+
const stops = [];
|
|
208
|
+
for (const arg of stopArgs){
|
|
209
|
+
const stopMatch = GRADIENT_STOP_PATTERN.exec(arg);
|
|
210
|
+
if (!stopMatch) {
|
|
211
|
+
stops.push({
|
|
212
|
+
color: arg
|
|
213
|
+
});
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const color = stopMatch[1].trim();
|
|
217
|
+
// A stop may carry TWO positions (`red 0% 40%`), which the two-box stop
|
|
218
|
+
// editor cannot show. A colour that legitimately ends in a percentage
|
|
219
|
+
// closes its own paren (`hsl(200 100% 50%)`), so a bare trailing `%`
|
|
220
|
+
// here is always the first of a pair.
|
|
221
|
+
if (/\d%$/.test(color)) return unparsed;
|
|
222
|
+
stops.push({
|
|
223
|
+
color,
|
|
224
|
+
position: Number(stopMatch[2])
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
if (stops.length < 2) return unparsed;
|
|
228
|
+
return {
|
|
229
|
+
type,
|
|
230
|
+
angle,
|
|
231
|
+
position,
|
|
232
|
+
stops
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Serializes a {@link CssGradient} back to the single CSS string persisted
|
|
237
|
+
* under `backgroundImage`. The inverse of {@link parseCssGradient}: fewer
|
|
238
|
+
* than two usable stops serializes to `''` (which clears the property)
|
|
239
|
+
* rather than to a half-written `linear-gradient(` no parser accepts.
|
|
240
|
+
*/ export function buildCssGradient(gradient) {
|
|
241
|
+
var _gradient_stops;
|
|
242
|
+
if (!gradient) return '';
|
|
243
|
+
if (gradient.raw !== undefined) return gradient.raw;
|
|
244
|
+
const stops = ((_gradient_stops = gradient.stops) != null ? _gradient_stops : []).filter((stop)=>{
|
|
245
|
+
var _stop_color;
|
|
246
|
+
return Boolean(stop == null ? void 0 : (_stop_color = stop.color) == null ? void 0 : _stop_color.trim());
|
|
247
|
+
});
|
|
248
|
+
if (stops.length < 2) return '';
|
|
249
|
+
const parts = stops.map((stop)=>typeof stop.position === 'number' && Number.isFinite(stop.position) ? `${stop.color.trim()} ${stop.position}%` : stop.color.trim());
|
|
250
|
+
if (gradient.type === 'radial') {
|
|
251
|
+
const at = gradient.position && Number.isFinite(gradient.position.x) && Number.isFinite(gradient.position.y) ? `at ${gradient.position.x}% ${gradient.position.y}%, ` : '';
|
|
252
|
+
return `radial-gradient(${at}${parts.join(', ')})`;
|
|
253
|
+
}
|
|
254
|
+
const angle = typeof gradient.angle === 'number' && Number.isFinite(gradient.angle) ? `${gradient.angle}deg, ` : '';
|
|
255
|
+
return `linear-gradient(${angle}${parts.join(', ')})`;
|
|
256
|
+
}
|
|
257
|
+
/** Function forms that produce an IMAGE, not a `<color>`. */ const NON_COLOR_FUNCTION_PATTERN = /^(url|image|image-set|cross-fade|element|paint|[a-z-]*gradient)$/i;
|
|
258
|
+
const CSS_HEX_COLOR_PATTERN = /^#[0-9a-f]{3,8}$/i;
|
|
259
|
+
/** A bare keyword (`red`, `transparent`) or a palette token path. */ const CSS_COLOR_IDENT_PATTERN = /^[a-z][a-z0-9]*(\.[a-z0-9]+)*$/i;
|
|
260
|
+
const CSS_FUNCTION_PATTERN = /^([a-z][a-z0-9-]*)\s*\([\s\S]*\)$/i;
|
|
261
|
+
/**
|
|
262
|
+
* Why a value cannot be a colour, or undefined when it can (AGL-1331).
|
|
263
|
+
*
|
|
264
|
+
* The colour fields' real contract is "a palette token path (`primary.main`)
|
|
265
|
+
* or a valid CSS `<color>`". Before this, `getStrValue` handed any string
|
|
266
|
+
* through, the form was `noValidate`, and a gradient typed into Background
|
|
267
|
+
* Color was stored as `background-color: linear-gradient(…)` — which the
|
|
268
|
+
* CSS parser drops, leaving a transparent element and no error anywhere.
|
|
269
|
+
*
|
|
270
|
+
* Deliberately permissive about what a colour IS: any function form is
|
|
271
|
+
* accepted except the image-producing ones, so `color-mix()`, `oklch()` and
|
|
272
|
+
* whatever CSS adds next are never rejected by a stale allowlist. The job
|
|
273
|
+
* here is to catch the value that would VANISH, not to re-implement the CSS
|
|
274
|
+
* colour grammar.
|
|
275
|
+
*/ export function describeCssColorProblem(value) {
|
|
276
|
+
if (value === undefined || value === null) return undefined;
|
|
277
|
+
const text = `${value}`.trim();
|
|
278
|
+
if (!text) return undefined;
|
|
279
|
+
if (isCssGradientValue(text)) {
|
|
280
|
+
return 'A gradient is not a color — this would be dropped by the browser. ' + 'Use the Background Fill field to build one.';
|
|
281
|
+
}
|
|
282
|
+
if (CSS_HEX_COLOR_PATTERN.test(text)) return undefined;
|
|
283
|
+
if (CSS_COLOR_IDENT_PATTERN.test(text)) return undefined;
|
|
284
|
+
const fn = CSS_FUNCTION_PATTERN.exec(text);
|
|
285
|
+
if (fn && !NON_COLOR_FUNCTION_PATTERN.test(fn[1])) return undefined;
|
|
286
|
+
return 'Not a color — this would be dropped by the browser. Type a hex value ' + '(#161C21) or an rgb()/hsl() color, or pick a theme color.';
|
|
287
|
+
}
|
|
288
|
+
export function parseCssMeasurement(value) {
|
|
289
|
+
if (!value || !_isStrT(value)) return {
|
|
290
|
+
value: undefined,
|
|
291
|
+
unit: undefined
|
|
292
|
+
};
|
|
293
|
+
// Routed through the AGL-1219 parser so the editor and the box styler
|
|
294
|
+
// never disagree about what `1.5rem` means. The hand-rolled regex pair
|
|
295
|
+
// this replaced split off the leading integer only, so a decimal came
|
|
296
|
+
// back as `1` + `.5rem`, and the quantity came back as a STRING — which
|
|
297
|
+
// `buildCssMeasurement`'s numeric guard rejected, wiping the number
|
|
298
|
+
// whenever only the unit was changed.
|
|
299
|
+
const { value: quantity, unit } = parseCssDimension(value);
|
|
300
|
+
return {
|
|
301
|
+
value: quantity,
|
|
302
|
+
unit
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
export function buildCssMeasurement(measurement) {
|
|
306
|
+
if ((measurement == null ? void 0 : measurement.unit) && isGlobalUnit(measurement == null ? void 0 : measurement.unit)) {
|
|
307
|
+
return `${measurement.unit}`;
|
|
308
|
+
}
|
|
309
|
+
if (_isNum(measurement == null ? void 0 : measurement.value) && (measurement == null ? void 0 : measurement.unit)) {
|
|
310
|
+
return `${measurement.value}${measurement == null ? void 0 : measurement.unit}`;
|
|
311
|
+
}
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/data/enums/src/lib/styles.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2023 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { _isEqualitySameType, _isNum, _isStrT } from '@aglyn/shared-util-tools'\nimport { splitTopLevelArgs } from './palette-token-css-var'\n\nexport * from './palette-token-css-var'\n\nexport enum CssUnit {\n INITIAL = 'initial',\n UNSET = 'unset',\n INHERIT = 'inherit',\n AUTO = 'auto',\n PIXELS = 'px',\n EM = 'em',\n PERCENT = '%',\n REM = 'rem',\n POINTS = 'pt',\n PICAS = 'pc',\n CH = 'ch',\n VIEWPORT_WIDTH = 'vw',\n VIEWPORT_HEIGHT = 'vh',\n VIEWPORT_MAX = 'vmax',\n VIEWPORT_MIN = 'vmin',\n // Small/large/dynamic viewport units (AGL-2486). On a phone the address\n // bar slides away as the visitor scrolls, so `vh` changes height mid-\n // scroll and anything sized in it jumps. `svh` is the window at its\n // SMALLEST (bar showing) and never jumps, `lvh` the largest, `dvh` the\n // live value. On desktop all three equal `vh`.\n SMALL_VIEWPORT_WIDTH = 'svw',\n SMALL_VIEWPORT_HEIGHT = 'svh',\n LARGE_VIEWPORT_WIDTH = 'lvw',\n LARGE_VIEWPORT_HEIGHT = 'lvh',\n DYNAMIC_VIEWPORT_WIDTH = 'dvw',\n DYNAMIC_VIEWPORT_HEIGHT = 'dvh',\n DPI = 'dpi',\n MILLIMETERS = 'mm',\n CENTIMETERS = 'cm',\n INCHES = 'in',\n}\n\nexport function isGlobalUnit(unit: CssUnit) {\n return _isEqualitySameType(\n unit,\n null,\n CssUnit.INITIAL,\n CssUnit.UNSET,\n CssUnit.INHERIT,\n CssUnit.AUTO,\n )\n}\n\n/**\n * A CSS dimension split into the parts an editor can put on screen\n * (AGL-1219): a numeric quantity plus its unit, a bare keyword unit\n * (`auto`, `inherit`, …), or — when the string is richer than\n * `<number><unit>` — the original text under `raw`.\n *\n * `raw` is the escape hatch that keeps an editor from destroying what it\n * cannot model: `calc(100% - 2rem)`, `clamp(…)`, `min-content` and a\n * `{{token}}` binding all round-trip untouched instead of collapsing to\n * whatever a lenient parse happened to salvage.\n */\nexport interface CssDimension {\n /** Quantity, absent for keyword units and for unparsed (`raw`) values. */\n value?: number\n unit?: CssUnit\n /** Set ONLY when the value is not a plain `<number><unit>`. */\n raw?: string\n}\n\nconst UNIT_BY_TOKEN: Record<string, CssUnit> = Object.fromEntries(\n Object.values(CssUnit).map((unit) => [`${unit}`.toLowerCase(), unit]),\n)\n\n/** Every unit the pickers offer, in enum order — ONE list, no second one. */\nexport const CSS_UNITS: CssUnit[] = Object.values(CssUnit)\n\n/** `12`, `-4.5`, `.75` — the quantity, then its (possibly empty) unit. */\nconst CSS_DIMENSION_PATTERN = /^([+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+))([a-z%]*)$/i\n\n/**\n * Splits a CSS dimension string into {@link CssDimension}. Anything that is\n * not empty, a keyword unit, or `<number><known unit>` comes back as `raw`\n * so callers can hand it straight back (AGL-1219).\n */\nexport function parseCssDimension(\n value: string | number | undefined | null,\n): CssDimension {\n if (value === undefined || value === null) return {}\n const text = `${value}`.trim()\n if (!text) return {}\n\n const known = UNIT_BY_TOKEN[text.toLowerCase()]\n // A bare keyword (`auto`) is the whole value; `px` alone is not a value.\n if (known && isGlobalUnit(known)) return { unit: known }\n\n const match = CSS_DIMENSION_PATTERN.exec(text)\n if (!match) return { raw: text }\n\n const [, quantity, suffix] = match\n const unit = suffix ? UNIT_BY_TOKEN[suffix.toLowerCase()] : undefined\n // A recognized shape carrying an unrecognized unit (`10q`) is still\n // meaningful CSS — pass it through rather than dropping the unit.\n if (suffix && !unit) return { raw: text }\n\n const parsed = Number(quantity)\n if (!Number.isFinite(parsed)) return { raw: text }\n return { value: parsed, unit }\n}\n\n/**\n * Serializes a {@link CssDimension} back to the single CSS string that gets\n * persisted. The inverse of {@link parseCssDimension}: an empty dimension\n * serializes to an empty string, never to a partial value like `px`.\n */\nexport function buildCssDimension(dimension?: CssDimension): string {\n if (!dimension) return ''\n if (dimension.raw !== undefined) return dimension.raw\n if (dimension.unit && isGlobalUnit(dimension.unit)) return `${dimension.unit}`\n if (typeof dimension.value !== 'number' || !Number.isFinite(dimension.value)) {\n return ''\n }\n return `${dimension.value}${dimension.unit ?? ''}`\n}\n\nexport type CssGradientType = 'linear' | 'radial'\n\n/** One colour stop of a gradient the Background field can edit. */\nexport interface CssGradientStop {\n /**\n * Stop colour: a literal (`#7A5CF0`, `rgb(…)`) or a palette token\n * reference from {@link paletteTokenToCssVar}. Both forms are allowed on\n * the same gradient — the marketing CTA's endpoints are tokens while its\n * mid stop has no token and stays a hex (AGL-1331).\n */\n color: string\n /** Position along the ramp in percent; omitted lets CSS distribute it. */\n position?: number\n}\n\n/**\n * A gradient split into the parts the Background field puts on screen\n * (AGL-1331) — the {@link CssDimension} idiom applied to `backgroundImage`.\n *\n * `raw` is the same escape hatch: a `conic-gradient`, a `to bottom right`\n * direction, a multi-position stop or a stacked image list round-trips\n * untouched instead of being flattened into whatever a lenient parse\n * salvaged.\n */\nexport interface CssGradient {\n type: CssGradientType\n /** Degrees, linear only. Absent means CSS's default (`to bottom`). */\n angle?: number\n /**\n * Where a RADIAL gradient's centre sits, in percent of the box\n *. Absent means CSS's default, dead centre.\n *\n * A radial gradient is how a page paints a glow, and a glow is almost\n * never centred — the one behind a hero sits high and bleeds off the top.\n * Without this the control could only ever centre it, so authors either\n * accepted a halo in the middle of their text or dropped to Custom CSS.\n * Linear's counterpart is {@link angle}; this is radial's.\n */\n position?: { x: number; y: number }\n stops: CssGradientStop[]\n /** Set ONLY when the value is a gradient this model cannot express. */\n raw?: string\n}\n\n/**\n * Whether every `(` is closed and none closes early — the precondition\n * {@link splitTopLevelArgs} needs to be trusted (AGL-1336).\n *\n * Its depth counter goes NEGATIVE on a stray `)`, and a negative depth is\n * never `0`, so every top-level comma after that stray paren stops being a\n * split point. That is not a defect in the splitter — it is what makes\n * checking balance first load-bearing rather than defensive.\n */\nfunction hasBalancedParens(text: string): boolean {\n let depth = 0\n for (const char of text) {\n if (char === '(') depth += 1\n else if (char === ')') {\n depth -= 1\n if (depth < 0) return false\n }\n }\n return depth === 0\n}\n\nconst GRADIENT_FUNCTION_PATTERN =\n /^([a-z-]*gradient)\\s*\\(([\\s\\S]*)\\)$/i\nconst GRADIENT_ANGLE_PATTERN = /^(-?\\d+(?:\\.\\d+)?)deg$/i\nconst GRADIENT_STOP_PATTERN = /^([\\s\\S]+?)\\s+(-?\\d+(?:\\.\\d+)?)%$/\n/** `at 50% 18%` — a radial gradient's centre, the only prefix form modelled. */\nconst GRADIENT_POSITION_PATTERN =\n /^at\\s+(-?\\d+(?:\\.\\d+)?)%\\s+(-?\\d+(?:\\.\\d+)?)%$/i\n\n/** Whether a value is gradient-shaped — the check the colour fields reject on. */\nexport function isCssGradientValue(value: unknown): boolean {\n return (\n typeof value === 'string' &&\n /(^|\\s)[a-z-]*gradient\\s*\\(/i.test(value.trim())\n )\n}\n\n/**\n * Splits a `backgroundImage` value into {@link CssGradient}. Returns\n * undefined when the value is empty or is not a gradient at all (a `url(…)`\n * image, say), and a `raw`-carrying gradient when it is one this model\n * cannot express — never a lossy approximation.\n *\n * `background-image` is a comma-separated LAYER LIST and this model holds\n * ONE layer, so the layer split happens before anything else (AGL-1336).\n * Without it `linear-gradient(#000 0%, #fff 100%), url(/hero.jpg)` parsed\n * as a single two-stop gradient whose second stop was the whole string\n * `#fff 100%), url(/hero.jpg` — the function pattern is greedy to the last\n * `)`, and the stray `)` it swallowed then suppressed the top-level comma\n * split. That round-tripped BYTE-IDENTICAL, so nothing looked wrong until\n * the author's first stop edit re-serialized the model and the `url()`\n * layer was gone for good. A stacked value now takes the `raw` path, where\n * the field shows the CSS verbatim and hands it back untouched.\n */\nexport function parseCssGradient(\n value: string | undefined | null,\n): CssGradient | undefined {\n if (value === undefined || value === null) return undefined\n const text = `${value}`.trim()\n if (!text || !isCssGradientValue(text)) return undefined\n\n /** Held verbatim: gradient-shaped, but not one this model can express. */\n const unmodellable: CssGradient = { type: 'linear', stops: [], raw: text }\n // Unbalanced parens make every split below meaningless, so refuse first.\n if (!hasBalancedParens(text)) return unmodellable\n if (splitTopLevelArgs(text).filter((layer) => layer !== '').length !== 1) {\n return unmodellable\n }\n\n const match = GRADIENT_FUNCTION_PATTERN.exec(text)\n const fn = match?.[1]?.toLowerCase()\n // Only the two the control can round-trip. `conic-gradient` and\n // `repeating-linear-gradient` land in `raw` alongside the stacked lists.\n if (!match || (fn !== 'linear-gradient' && fn !== 'radial-gradient')) {\n return unmodellable\n }\n // One layer, balanced overall, and still unbalanced INSIDE the captured\n // body means the trailing `)` closes something else — `linear-gradient(a,\n // b) url(x)` is one layer whose gradient is only part of it.\n if (!hasBalancedParens(match[2] ?? '')) return unmodellable\n const type: CssGradientType = fn === 'radial-gradient' ? 'radial' : 'linear'\n const args = splitTopLevelArgs(match[2] ?? '').filter((arg) => arg !== '')\n const unparsed: CssGradient = { type, stops: [], raw: text }\n\n let angle: number | undefined\n let position: { x: number; y: number } | undefined\n let stopArgs = args\n const first = args[0] ?? ''\n const angleMatch = GRADIENT_ANGLE_PATTERN.exec(first)\n const positionMatch = GRADIENT_POSITION_PATTERN.exec(first)\n if (angleMatch) {\n if (type === 'radial') return unparsed\n angle = Number(angleMatch[1])\n stopArgs = args.slice(1)\n } else if (positionMatch && type === 'radial') {\n // `at X% Y%` is the one prefix the Position boxes round-trip. Anything\n // richer (`ellipse 60% 40% at …`, `circle closest-side`) still falls\n // through to `raw` below, so a hand-written gradient is never flattened.\n position = { x: Number(positionMatch[1]), y: Number(positionMatch[2]) }\n stopArgs = args.slice(1)\n } else if (/^(to\\s|at\\s|circle|ellipse|closest|farthest|\\d)/i.test(first)) {\n // A direction or shape/position prefix the control has no editor for.\n return unparsed\n }\n\n const stops: CssGradientStop[] = []\n for (const arg of stopArgs) {\n const stopMatch = GRADIENT_STOP_PATTERN.exec(arg)\n if (!stopMatch) {\n stops.push({ color: arg })\n continue\n }\n const color = stopMatch[1].trim()\n // A stop may carry TWO positions (`red 0% 40%`), which the two-box stop\n // editor cannot show. A colour that legitimately ends in a percentage\n // closes its own paren (`hsl(200 100% 50%)`), so a bare trailing `%`\n // here is always the first of a pair.\n if (/\\d%$/.test(color)) return unparsed\n stops.push({ color, position: Number(stopMatch[2]) })\n }\n if (stops.length < 2) return unparsed\n return { type, angle, position, stops }\n}\n\n/**\n * Serializes a {@link CssGradient} back to the single CSS string persisted\n * under `backgroundImage`. The inverse of {@link parseCssGradient}: fewer\n * than two usable stops serializes to `''` (which clears the property)\n * rather than to a half-written `linear-gradient(` no parser accepts.\n */\nexport function buildCssGradient(gradient?: CssGradient): string {\n if (!gradient) return ''\n if (gradient.raw !== undefined) return gradient.raw\n const stops = (gradient.stops ?? []).filter((stop) =>\n Boolean(stop?.color?.trim()),\n )\n if (stops.length < 2) return ''\n const parts = stops.map((stop) =>\n typeof stop.position === 'number' && Number.isFinite(stop.position)\n ? `${stop.color.trim()} ${stop.position}%`\n : stop.color.trim(),\n )\n if (gradient.type === 'radial') {\n const at =\n gradient.position &&\n Number.isFinite(gradient.position.x) &&\n Number.isFinite(gradient.position.y)\n ? `at ${gradient.position.x}% ${gradient.position.y}%, `\n : ''\n return `radial-gradient(${at}${parts.join(', ')})`\n }\n const angle =\n typeof gradient.angle === 'number' && Number.isFinite(gradient.angle)\n ? `${gradient.angle}deg, `\n : ''\n return `linear-gradient(${angle}${parts.join(', ')})`\n}\n\n/** Function forms that produce an IMAGE, not a `<color>`. */\nconst NON_COLOR_FUNCTION_PATTERN =\n /^(url|image|image-set|cross-fade|element|paint|[a-z-]*gradient)$/i\nconst CSS_HEX_COLOR_PATTERN = /^#[0-9a-f]{3,8}$/i\n/** A bare keyword (`red`, `transparent`) or a palette token path. */\nconst CSS_COLOR_IDENT_PATTERN = /^[a-z][a-z0-9]*(\\.[a-z0-9]+)*$/i\nconst CSS_FUNCTION_PATTERN = /^([a-z][a-z0-9-]*)\\s*\\([\\s\\S]*\\)$/i\n\n/**\n * Why a value cannot be a colour, or undefined when it can (AGL-1331).\n *\n * The colour fields' real contract is \"a palette token path (`primary.main`)\n * or a valid CSS `<color>`\". Before this, `getStrValue` handed any string\n * through, the form was `noValidate`, and a gradient typed into Background\n * Color was stored as `background-color: linear-gradient(…)` — which the\n * CSS parser drops, leaving a transparent element and no error anywhere.\n *\n * Deliberately permissive about what a colour IS: any function form is\n * accepted except the image-producing ones, so `color-mix()`, `oklch()` and\n * whatever CSS adds next are never rejected by a stale allowlist. The job\n * here is to catch the value that would VANISH, not to re-implement the CSS\n * colour grammar.\n */\nexport function describeCssColorProblem(value: unknown): string | undefined {\n if (value === undefined || value === null) return undefined\n const text = `${value}`.trim()\n if (!text) return undefined\n if (isCssGradientValue(text)) {\n return (\n 'A gradient is not a color — this would be dropped by the browser. ' +\n 'Use the Background Fill field to build one.'\n )\n }\n if (CSS_HEX_COLOR_PATTERN.test(text)) return undefined\n if (CSS_COLOR_IDENT_PATTERN.test(text)) return undefined\n const fn = CSS_FUNCTION_PATTERN.exec(text)\n if (fn && !NON_COLOR_FUNCTION_PATTERN.test(fn[1])) return undefined\n return (\n 'Not a color — this would be dropped by the browser. Type a hex value ' +\n '(#161C21) or an rgb()/hsl() color, or pick a theme color.'\n )\n}\n\nexport function parseCssMeasurement(value: string | undefined): Measurement {\n if (!value || !_isStrT(value)) return { value: undefined, unit: undefined }\n // Routed through the AGL-1219 parser so the editor and the box styler\n // never disagree about what `1.5rem` means. The hand-rolled regex pair\n // this replaced split off the leading integer only, so a decimal came\n // back as `1` + `.5rem`, and the quantity came back as a STRING — which\n // `buildCssMeasurement`'s numeric guard rejected, wiping the number\n // whenever only the unit was changed.\n const { value: quantity, unit } = parseCssDimension(value)\n return { value: quantity, unit }\n}\n\nexport function buildCssMeasurement(\n measurement: Measurement,\n): string | undefined {\n if (measurement?.unit && isGlobalUnit(measurement?.unit as any)) {\n return `${measurement.unit}`\n }\n if (_isNum(measurement?.value) && measurement?.unit) {\n return `${measurement.value}${measurement?.unit}`\n }\n\n return undefined\n}\n\nexport interface Measurement {\n unit?: CssUnit\n value?: number\n}\n"],"names":["_isEqualitySameType","_isNum","_isStrT","splitTopLevelArgs","CssUnit","isGlobalUnit","unit","UNIT_BY_TOKEN","Object","fromEntries","values","map","toLowerCase","CSS_UNITS","CSS_DIMENSION_PATTERN","parseCssDimension","value","undefined","text","trim","known","match","exec","raw","quantity","suffix","parsed","Number","isFinite","buildCssDimension","dimension","hasBalancedParens","depth","char","GRADIENT_FUNCTION_PATTERN","GRADIENT_ANGLE_PATTERN","GRADIENT_STOP_PATTERN","GRADIENT_POSITION_PATTERN","isCssGradientValue","test","parseCssGradient","args","unmodellable","type","stops","filter","layer","length","fn","arg","unparsed","angle","position","stopArgs","first","angleMatch","positionMatch","slice","x","y","stopMatch","push","color","buildCssGradient","gradient","stop","Boolean","parts","at","join","NON_COLOR_FUNCTION_PATTERN","CSS_HEX_COLOR_PATTERN","CSS_COLOR_IDENT_PATTERN","CSS_FUNCTION_PATTERN","describeCssColorProblem","parseCssMeasurement","buildCssMeasurement","measurement"],"mappings":"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"}
|