origam 2.18.20 → 2.18.21

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/CHANGELOG.md CHANGED
@@ -18,6 +18,66 @@ This project follows [Semantic Versioning](https://semver.org).
18
18
 
19
19
  ## [Unreleased]
20
20
 
21
+ ## [2.18.21] - 2026-09-30
22
+
23
+ ### Fixed — `useBorder` supprimait silencieusement une largeur en `var()`
24
+
25
+ `BORDER_REGEX` n'acceptait en largeur que des chiffres suivis d'une unite,
26
+ tandis que son groupe **couleur** accepte `var(--…)`. Une chaine comme
27
+ `borderLeft="var(--x) solid var(--y)"` etait donc happee **entierement par le
28
+ groupe couleur** : `parseBorderPositionValue` renvoyait une largeur vide,
29
+ `formatBorderPositionStylesVar` sautait la declaration, et le navigateur
30
+ jetait le `border-left-color` invalide. Resultat rendu : un bord `medium`
31
+ (~3px) en `currentColor` au lieu de la largeur et de la couleur demandees.
32
+
33
+ ⛔ **Aucun diagnostic.** Le type-check passait, rien n'etait leve, rien
34
+ n'etait logue. Le chemin booleen (`borderLeft: true`) emettait pourtant un
35
+ `var()` correctement — seul l'analyseur de chaine refusait.
36
+
37
+ Le groupe `width` accepte desormais une alternative `var()`, **conditionnee
38
+ par un lookahead sur un mot-clé de style**. Ce garde n'est pas decoratif : les
39
+ trois groupes de la regex peuvent matcher vide, donc une alternative `var()`
40
+ nue aurait happe `var(--ma-couleur)` — une couleur SEULE, cas courant qui
41
+ fonctionnait — et aurait inverse la panne. Le lookahead tire sa liste de
42
+ `BORDER_STYLE`, pour qu'elle ne puisse plus deriver de celle du groupe `style`.
43
+
44
+ ⚠️ **Limite connue, pinnee par trois tests et non corrigee ici.** Une largeur
45
+ `var()` **contenant une espace** (`var(--x, 4px)`) ne passe que par les props
46
+ PAR COTE. La prop globale `border` fait un `split(' ')` et coupe la valeur en
47
+ fragments invalides. Avant ce lot la meme valeur tombait entiere dans `color`
48
+ et y etait scindee en quatre — aucun bord dans les deux cas, donc pas de
49
+ regression, mais pas repare. **Un preset portant une largeur tokenisee doit
50
+ viser une prop par cote ou d'axe, jamais `border`.**
51
+
52
+ ### Added — `fontStyle` en passthrough sur `ITypographyProps`
53
+
54
+ `font-style` n'avait ni prop, ni groupe de tokens, ni classe utilitaire
55
+ (`0` occurrence dans `interfaces/Commons/` et `composables/Commons/`, `0` pour
56
+ `font__style` dans `primitive.css`). `useTypography` enveloppant toute valeur
57
+ en token, `italic` / `normal` — des mots-clés CSS, pas des echelons — devaient
58
+ passer **litteralement**. Aucun canal nouveau : `--origam-blockquote---font-style`
59
+ etait deja declare et deja lu.
60
+
61
+ ### Internal — ce que la campagne zero-changement ne prouve pas
62
+
63
+ `BORDER_REGEX` sert la prop `border` sur ~100 composants sans baseline VRT, et
64
+ la verification exigee etait donc : aucune valeur du depot ne change de
65
+ decoupage. Verdict — **81 valeurs `border*` distinctes, 81 decoupages
66
+ identiques, delta zero**.
67
+
68
+ ⛔ Mais la regex **naive** que ce garde-fou existe pour eviter ne diverge, elle
69
+ non plus, **sur aucune des 81 valeurs reelles** : aucun fichier du depot ne
70
+ passe une couleur `var()` seule a une prop de bordure. **Le corpus reel
71
+ n'aurait pas attrape la regression inverse** — seul le controle negatif
72
+ synthetique `var(--c)` l'attrape. Une campagne sur valeurs reelles prouve
73
+ moins qu'elle n'en a l'air ; les controles negatifs sont ce qui la rend
74
+ concluante. Consigne dans `border.const.ts`.
75
+
76
+ Hors paquet publie, dans le meme intervalle : `pnpm audit` est repasse de
77
+ **7 high / 7 moderate / 3 low** a **0**, par relevement de trois `overrides`
78
+ (`brace-expansion@2`, `brace-expansion@5`, `undici@8`). Aucun fichier de
79
+ `packages/ds` touche, donc le tarball est inchange par cette partie.
80
+
21
81
  ## [2.18.20] - 2026-09-30
22
82
 
23
83
  ### Added — surfaces de props `opacity` et `backdrop`, et les deux trous de `IStateEffectConfig`
@@ -113,7 +113,8 @@ const props = defineProps({
113
113
  fontSize: { type: null, required: false },
114
114
  fontWeight: { type: null, required: false },
115
115
  lineHeight: { type: null, required: false },
116
- letterSpacing: { type: null, required: false }
116
+ letterSpacing: { type: null, required: false },
117
+ fontStyle: { type: String, required: false }
117
118
  });
118
119
  defineEmits([]);
119
120
  defineSlots();
@@ -33,7 +33,8 @@ const props = defineProps({
33
33
  fontSize: { type: null, required: false },
34
34
  fontWeight: { type: null, required: false },
35
35
  lineHeight: { type: null, required: false },
36
- letterSpacing: { type: null, required: false }
36
+ letterSpacing: { type: null, required: false },
37
+ fontStyle: { type: String, required: false }
37
38
  });
38
39
  defineEmits([]);
39
40
  defineSlots();
@@ -66,7 +66,8 @@ const props = defineProps({
66
66
  fontSize: { type: null, required: false },
67
67
  fontWeight: { type: null, required: false },
68
68
  lineHeight: { type: null, required: false },
69
- letterSpacing: { type: null, required: false }
69
+ letterSpacing: { type: null, required: false },
70
+ fontStyle: { type: String, required: false }
70
71
  });
71
72
  const { filterProps } = useProps(props);
72
73
  defineEmits([]);
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useTypography = useTypography;
7
7
  var _vue = require("vue");
8
8
  const TYPOGRAPHY_TOKEN_MAP = [["fontFamily", "font-family", "font__family"], ["fontSize", "font-size", "font__size"], ["fontWeight", "font-weight", "font__weight"], ["lineHeight", "line-height", "font__lineHeight"], ["letterSpacing", "letter-spacing", "font__letterSpacing"]];
9
+ const TYPOGRAPHY_PASSTHROUGH_MAP = [["fontStyle", "font-style"]];
9
10
  function useTypography(props, varPrefix) {
10
11
  const typographyStyles = (0, _vue.computed)(() => {
11
12
  const styles = {};
@@ -15,6 +16,12 @@ function useTypography(props, varPrefix) {
15
16
  styles[`--origam-${varPrefix}---${cssProp}`] = `var(--origam-${tokenGroup}---${value})`;
16
17
  }
17
18
  }
19
+ for (const [propKey, cssProp] of TYPOGRAPHY_PASSTHROUGH_MAP) {
20
+ const value = props[propKey];
21
+ if (value) {
22
+ styles[`--origam-${varPrefix}---${cssProp}`] = String(value);
23
+ }
24
+ }
18
25
  return Object.keys(styles).length ? styles : null;
19
26
  });
20
27
  return {
@@ -4,13 +4,18 @@ import type { ITypographyProps } from '../../interfaces/Commons/typography.inter
4
4
  *
5
5
  * @description
6
6
  * Volet typographique de `useMargin`/`useBorder`/`useColor` : pour
7
- * chacune des cinq `ITypographyProps` (`fontFamily`, `fontSize`,
7
+ * chacune des cinq `ITypographyProps` de TOKEN (`fontFamily`, `fontSize`,
8
8
  * `fontWeight`, `lineHeight`, `letterSpacing`) que le consommateur a
9
9
  * fixee, emet une custom property inline `--origam-{varPrefix}---{prop}`
10
10
  * qui repointe vers le token primitif correspondant. Une prop non fixee
11
11
  * n'emet rien — le theme/la variante du composant garde la main.
12
12
  *
13
13
  * @description
14
+ * La sixieme, `fontStyle`, passe par un canal PASSTHROUGH : sa valeur est
15
+ * un mot-cle CSS rendu verbatim, sans enveloppe `var()`. Voir
16
+ * `TYPOGRAPHY_PASSTHROUGH_MAP` pour le pourquoi.
17
+ *
18
+ * @description
14
19
  * INLINE UNIQUEMENT (pas de classe utilitaire — `origam-utilities.css`
15
20
  * n'a pas de famille `.origam--font-*`), et `typographyStyles` est un
16
21
  * objet PLAT `{ '--var': valeur }` (jamais un tableau) : `useStyle()`
@@ -6,6 +6,9 @@ const TYPOGRAPHY_TOKEN_MAP = [
6
6
  ["lineHeight", "line-height", "font__lineHeight"],
7
7
  ["letterSpacing", "letter-spacing", "font__letterSpacing"]
8
8
  ];
9
+ const TYPOGRAPHY_PASSTHROUGH_MAP = [
10
+ ["fontStyle", "font-style"]
11
+ ];
9
12
  export function useTypography(props, varPrefix) {
10
13
  const typographyStyles = computed(() => {
11
14
  const styles = {};
@@ -15,6 +18,12 @@ export function useTypography(props, varPrefix) {
15
18
  styles[`--origam-${varPrefix}---${cssProp}`] = `var(--origam-${tokenGroup}---${value})`;
16
19
  }
17
20
  }
21
+ for (const [propKey, cssProp] of TYPOGRAPHY_PASSTHROUGH_MAP) {
22
+ const value = props[propKey];
23
+ if (value) {
24
+ styles[`--origam-${varPrefix}---${cssProp}`] = String(value);
25
+ }
26
+ }
18
27
  return Object.keys(styles).length ? styles : null;
19
28
  });
20
29
  return { typographyStyles };
@@ -5,7 +5,10 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.BORDER_REGEX = exports.BORDER_PROP_KEYS = exports.BORDER_POSITION_MAP = exports.BORDER_LOGICAL_AXIS_MAP = exports.BORDER_KEYWORD_WIDTH = void 0;
7
7
  var _enums = require("../../enums/index.cjs");
8
- const BORDER_REGEX = exports.BORDER_REGEX = /^(?<width>(?: ?(?:[0-9]+)(?:px|pt|PC|in|cm|mm|em|rem|%|ex|ch|fr)?){0,4}) {0,1}(?<style>(?:(?: ?(?:none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset))+){0,4}) ?(?<color>(?: ?(?:(?:(?:#)(?:[a-f0-9]{3}|[a-f0-9]{6}))|(?:var\(--[^)]+\))|(?:(?:rgb|hsl|rgba)a?\(.*\))|(?:[A-Za-z]+))){0,4})$/;
8
+ const BORDER_STYLE_ALTERNATION = Object.values(_enums.BORDER_STYLE).join("|");
9
+ const BORDER_LENGTH_UNITS = "(?:px|pt|PC|in|cm|mm|em|rem|%|ex|ch|fr)?";
10
+ const BORDER_COLOR_GROUP = "(?<color>(?: ?(?:(?:(?:#)(?:[a-f0-9]{3}|[a-f0-9]{6}))|(?:var\\(--[^)]+\\))|(?:(?:rgb|hsl|rgba)a?\\(.*\\))|(?:[A-Za-z]+))){0,4})";
11
+ const BORDER_REGEX = exports.BORDER_REGEX = new RegExp(`^(?<width>(?: ?var\\(--[^)]+\\)(?= +(?:${BORDER_STYLE_ALTERNATION}))| ?(?:[0-9]+)${BORDER_LENGTH_UNITS}){0,4}) {0,1}(?<style>(?:(?: ?(?:${BORDER_STYLE_ALTERNATION}))+){0,4}) ?` + BORDER_COLOR_GROUP + "$");
9
12
  const BORDER_POSITION_MAP = exports.BORDER_POSITION_MAP = [{
10
13
  side: _enums.BLOCK.TOP,
11
14
  widthProp: "borderTop",
@@ -1,23 +1,5 @@
1
1
  import { BLOCK, INLINE } from '../../enums';
2
2
  import type { TBorderLogicalAxis, TBorderWidthKeyword } from '../../types/Commons/border.type';
3
- /**
4
- * Parse a free-form `border` value into width / style / color groups.
5
- *
6
- * Accepted color forms (in alternation order — `var()` MUST come before
7
- * the bare `[A-Za-z]+` branch, otherwise `var` would be eaten as a word
8
- * before the parenthesis group has a chance to match):
9
- *
10
- * • Hex literal — `#abc` / `#aabbcc`
11
- * • CSS function — `rgb(…)` / `rgba(…)` / `hsl(…)` / `hsla(…)`
12
- * • CSS custom prop — `var(--origam-color__action--primary---bg)` (with optional
13
- * fallback: `var(--x, fallback)`)
14
- * • Named keyword — `red`, `currentColor`, `transparent`, etc.
15
- *
16
- * The user reported that DS-token references (`var(--…)`) silently
17
- * dropped through this regex and were never emitted as `border-color`,
18
- * while raw hex / named colors worked. Adding the `var()` alternative
19
- * fixes the design-token path.
20
- */
21
3
  export declare const BORDER_REGEX: RegExp;
22
4
  /**
23
5
  * Physical-side lookup driving the per-side border wiring (issue #215).
@@ -1,5 +1,10 @@
1
- import { BLOCK, BORDER_LOGICAL_AXIS, INLINE } from "../../enums/index.js";
2
- export const BORDER_REGEX = /^(?<width>(?: ?(?:[0-9]+)(?:px|pt|PC|in|cm|mm|em|rem|%|ex|ch|fr)?){0,4}) {0,1}(?<style>(?:(?: ?(?:none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset))+){0,4}) ?(?<color>(?: ?(?:(?:(?:#)(?:[a-f0-9]{3}|[a-f0-9]{6}))|(?:var\(--[^)]+\))|(?:(?:rgb|hsl|rgba)a?\(.*\))|(?:[A-Za-z]+))){0,4})$/;
1
+ import { BLOCK, BORDER_LOGICAL_AXIS, BORDER_STYLE, INLINE } from "../../enums/index.js";
2
+ const BORDER_STYLE_ALTERNATION = Object.values(BORDER_STYLE).join("|");
3
+ const BORDER_LENGTH_UNITS = "(?:px|pt|PC|in|cm|mm|em|rem|%|ex|ch|fr)?";
4
+ const BORDER_COLOR_GROUP = "(?<color>(?: ?(?:(?:(?:#)(?:[a-f0-9]{3}|[a-f0-9]{6}))|(?:var\\(--[^)]+\\))|(?:(?:rgb|hsl|rgba)a?\\(.*\\))|(?:[A-Za-z]+))){0,4})";
5
+ export const BORDER_REGEX = new RegExp(
6
+ `^(?<width>(?: ?var\\(--[^)]+\\)(?= +(?:${BORDER_STYLE_ALTERNATION}))| ?(?:[0-9]+)${BORDER_LENGTH_UNITS}){0,4}) {0,1}(?<style>(?:(?: ?(?:${BORDER_STYLE_ALTERNATION}))+){0,4}) ?` + BORDER_COLOR_GROUP + "$"
7
+ );
3
8
  export const BORDER_POSITION_MAP = [
4
9
  { side: BLOCK.TOP, widthProp: "borderTop", colorProp: "borderTopColor" },
5
10
  { side: INLINE.RIGHT, widthProp: "borderRight", colorProp: "borderRightColor" },
@@ -6,9 +6,14 @@ import type { TLineHeight } from '../../types/Commons/line-height.type';
6
6
  /**
7
7
  * Cross-cutting typography surface — the font equivalent of
8
8
  * `IColorProps` / `IBorderProps` / `IMarginProps`. Every prop is optional
9
- * and maps a primitive font token key to the matching component CSS
10
- * variable via `useTypography`. When a prop is unset the component keeps
11
- * its theme value (no override emitted).
9
+ * and resolves to the matching component CSS variable via `useTypography`.
10
+ * When a prop is unset the component keeps its theme value (no override
11
+ * emitted).
12
+ *
13
+ * The first FIVE props are primitive font token KEYS, wrapped into
14
+ * `var(--origam-font__{group}---{value})`. `fontStyle` is the one
15
+ * PASSTHROUGH: a CSS keyword emitted verbatim, because `font-style` has no
16
+ * design scale — see its own note below.
12
17
  *
13
18
  * | Prop | CSS property | Primitive token group |
14
19
  * |-----------------|-------------------|------------------------------|
@@ -17,6 +22,7 @@ import type { TLineHeight } from '../../types/Commons/line-height.type';
17
22
  * | `fontWeight` | `font-weight` | `--origam-font__weight---*` |
18
23
  * | `lineHeight` | `line-height` | `--origam-font__lineHeight---*` |
19
24
  * | `letterSpacing` | `letter-spacing` | `--origam-font__letterSpacing---*` |
25
+ * | `fontStyle` | `font-style` | *none — passthrough, see below* |
20
26
  *
21
27
  * Collision-free names by design: `fontSize` / `fontWeight` / `fontFamily`
22
28
  * (not `size` / `weight` / `family`) so the surface composes with
@@ -53,4 +59,42 @@ export interface ITypographyProps {
53
59
  * When unset, the component keeps its theme letter-spacing.
54
60
  */
55
61
  letterSpacing?: TLetterSpacing;
62
+ /*********************************************************
63
+ * fontStyle
64
+ *
65
+ * @description
66
+ * Style de fonte, emis LITTERALEMENT dans
67
+ * `--origam-{prefix}---font-style`. Seul membre PASSTHROUGH de cette
68
+ * interface : les cinq autres props sont des cles de token que
69
+ * `useTypography` enveloppe en `var(--origam-font__{groupe}---{valeur})`.
70
+ *
71
+ * @description
72
+ * ⛔ POURQUOI PAS UN TOKEN. `italic` / `normal` / `oblique` sont des
73
+ * MOTS-CLES CSS, pas les echelons d'une echelle de design : il n'existe
74
+ * aucun groupe `--origam-font__style---*` dans `primitive.css` (verifie,
75
+ * zero occurrence) et il n'en faut pas. Enveloppee, la valeur sortirait
76
+ * en `var(--origam-font__style---italic)`, un nom que nulle feuille ne
77
+ * declare — donc rien ne peindrait.
78
+ *
79
+ * @description
80
+ * Type `string` volontairement large, par coherence avec
81
+ * `IBorderProps.borderStyle` / `borderColor`, les deux autres
82
+ * passthrough de mot-cle CSS des interfaces Commons. Laisse passer
83
+ * `oblique 10deg`, qu'une union fermee rejetterait.
84
+ *
85
+ * @description
86
+ * ⚠️ N'a d'EFFET que si la SCSS du composant lit le var GENERIQUE
87
+ * `--origam-{prefix}---font-style`. Mesure a l'ajout : un seul composant
88
+ * le fait — `OrigamBlockquote`
89
+ * (`--origam-blockquote---resolved-font-style` retombe dessus).
90
+ * @description
91
+ * ⛔ `OrigamBracketCompetitor` ne compte PAS, et la nuance vaut d'etre
92
+ * lue : il lit `--origam-bracket-competitor--pending---font-style`, un
93
+ * var de MODIFICATEUR D'ETAT (double tiret `--pending---`), pas le
94
+ * generique que `useTypography(props, 'bracket-competitor')` emet. La
95
+ * prop y type-check et emet sa variable sans rien peindre — meme cas
96
+ * que `fontFamily` sur Btn. Ne pas ajouter de regle SCSS pour lui
97
+ * forcer un effet sans le signaler.
98
+ ********************************************************/
99
+ fontStyle?: string;
56
100
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "origam",
3
- "version": "2.18.20",
3
+ "version": "2.18.21",
4
4
  "type": "module",
5
5
  "description": "origam — a Vue 3 design system with multi-theme design tokens, CSS-first components and TypeScript types.",
6
6
  "keywords": [