fold-ng 0.2.1 → 0.4.0

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/llms.txt CHANGED
@@ -19,15 +19,15 @@ with a `@selector` and an `@example`.
19
19
 
20
20
  - [Install & quickstart](https://github.com/hugoheynard/fold-ng#readme): `npm install fold-ng`, import tokens, use standalone components.
21
21
  - [Design tokens](https://github.com/hugoheynard/fold-ng#the-two-tier-model): two-tier model — primitives (`--fold-ref-*`) → semantic (`--fold-color-*`); components consume the semantic layer only.
22
- - [Theming](https://github.com/hugoheynard/fold-ng#consuming-the-tokens): `data-theme="umbra|lumen|bubbly|navi"`; re-theme by re-pointing the semantic layer, never touching a component.
22
+ - [Theming](https://github.com/hugoheynard/fold-ng#consuming-the-tokens): `data-theme="umbra|lumen|bubbly|navi|titan"`; re-theme by re-pointing the semantic layer, never touching a component.
23
23
 
24
24
  ## Components
25
25
 
26
26
  - Actions: `[foldButton]` (on a real `<button>`/`<a>`; `emphasis` × `intent` axes; `loading`), `fold-button-icon` (momentary), `fold-toggle-icon` (toggle), `fold-link`.
27
27
  - Forms: `fold-input`, `fold-number-input`, `fold-select`, `fold-search`, `fold-slider`, `fold-range-slider`, `fold-file-dropzone` (Angular Signal Forms — no `ngModel`/`ReactiveFormsModule`).
28
28
  - Overlays: `fold-panel-host` / `fold-panel-header` (modal side panels with accessible name, `inert` background barrier, focus trap, scroll-lock; imperative `open<TData,TResult>()` → typed `FoldPanelRef`).
29
- - Navigation: `fold-menu`, `fold-nav-launcher`, `fold-tab-nav`.
30
- - Layout: `fold-app-shell`, `fold-page-layout`, `fold-aside-layout`, `fold-tab-layout`, `fold-hero-section`.
29
+ - Navigation: `fold-menu`, `fold-nav-launcher`, `fold-view-nav` (tab-styled nav bar; items with a `link` render real `<a routerLink>` with `aria-current` + auto active state, else buttons; `direction="auto"`, `collapsed` icon rail), `fold-tabs` + `fold-tab-panel` (the in-page ARIA Tabs widget — `role="tablist"`, roving arrow keys).
30
+ - Layout: `fold-app-shell`, `fold-page-layout`, `fold-aside-layout`, `fold-nav-layout` (places a nav/tabs bar + content, folds side↔top), `fold-hero-section`.
31
31
  - Content: `fold-card`, `fold-hero-card`, `fold-badge`, `fold-status-badge`, `fold-avatar`, `fold-avatar-list`, `fold-timeline`, `fold-data-table`, `fold-paginator`, `fold-field`.
32
32
  - Feedback: `fold-callout`, `fold-disclosure`, `fold-toast`, `fold-loading`, `fold-empty-state`.
33
33
  - Foundations: `fold-icon` (114 built-in SVGs + registry), `fold-spinner`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fold-ng",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Accessible, dark-first Angular 22 UI component library & design system — signals-first, standalone, zoneless, SSR-ready. Design tokens + WCAG-minded components, themeable to the bone.",
5
5
  "keywords": [
6
6
  "angular",
@@ -108,6 +108,25 @@
108
108
  --fold-ref-grape-600: #9333ea; /* hover / strong */
109
109
  --fold-ref-grape-700: #7e22ce; /* readable brand text */
110
110
 
111
+ /* ── Steel / Titanium — the TITAN theme families ──────────────
112
+ Brushed titanium, light: a cool near-neutral steel ramp for the
113
+ brushed silver page, the header + rails at its own tint, and the
114
+ bright polished cards that float on it — plus a HEAT-anodized
115
+ titanium brand, the copper-orange the metal takes when torched. */
116
+ --fold-ref-steel-900: #1b1f24; /* graphite body text */
117
+ --fold-ref-steel-600: #566069; /* secondary text */
118
+ --fold-ref-steel-500: #7c8894; /* muted text */
119
+ --fold-ref-steel-400: #9aa6b1; /* faded text */
120
+ --fold-ref-steel-300: #c0c8d0; /* solid brushed-steel border */
121
+ --fold-ref-steel-200: #d4dae1; /* brushed page ground */
122
+ --fold-ref-steel-150: #e2e7ec; /* header · rail 2 · hover · divider */
123
+ --fold-ref-steel-100: #eef1f5; /* raised rail plate · sunken */
124
+ --fold-ref-steel-50: #f8fafc; /* bright polished card */
125
+
126
+ --fold-ref-titanium-700: #863810; /* brand text (burnt copper) */
127
+ --fold-ref-titanium-600: #a5451a; /* hover / strong */
128
+ --fold-ref-titanium-500: #c2521b; /* brand base (copper-orange · AA w/ white) */
129
+
111
130
  /* ── Pure black — pairs with white for neutral alpha overlays */
112
131
  --fold-ref-black: #000000;
113
132
  }
package/tokens/scales.css CHANGED
@@ -55,6 +55,14 @@
55
55
  --fold-space-lg: 16px;
56
56
  --fold-space-xl: 20px;
57
57
 
58
+ /* Rail-width scale — the shared widths for the nav-rail hierarchy, named to
59
+ pair 1:1 with the `--fold-color-bg-rail-*` colour tokens (primary app menu →
60
+ secondary workspace/aside → tertiary in-page nav). Retune once, every rail
61
+ follows; each layout's own `--fold-<layout>-rail-*` var still overrides. */
62
+ --fold-rail-primary: 64px; /* app menu — the compact icon rail (fold-app-shell) */
63
+ --fold-rail-secondary: 220px; /* workspace / content aside (fold-aside-layout) */
64
+ --fold-rail-tertiary: 200px; /* in-page / section nav (fold-nav-layout) */
65
+
58
66
  /* Motion scale — transition shorthands (duration + easing bundled, matching
59
67
  the app so `--t-*` bridge onto these 1:1). One knob per interaction speed. */
60
68
  --fold-motion-fast: 0.1s ease;
@@ -104,3 +112,14 @@
104
112
  --fold-radius-md: 16px;
105
113
  --fold-radius-lg: 24px;
106
114
  }
115
+
116
+ /* ── Theme shape override: TITAN ──────────────────────────────
117
+ Softened, iPhone-premium: corners rounded a step past the base so a
118
+ polished-steel card reads like a device, not a slab — but short of
119
+ bubbly's pill. `pill` and `round` stay: shapes, not scale steps. */
120
+ [data-theme="titan"] {
121
+ --fold-radius-xs: 5px;
122
+ --fold-radius-sm: 10px;
123
+ --fold-radius-md: 14px;
124
+ --fold-radius-lg: 20px;
125
+ }
@@ -186,6 +186,99 @@
186
186
  color: var(--fold-color-text);
187
187
  }
188
188
 
189
+ /* ── Accent surface — an auto-inverting region ────────────────────────────────
190
+ `[data-surface="accent"]` (stamped by fold-card's `surface="accent"`, or the
191
+ `foldSurface` directive) fills with the brand accent and re-points its whole
192
+ content sub-tree to an on-accent palette — text, borders, band gradation and
193
+ even nested buttons / links / icon-tiles read on the accent, with no
194
+ per-component code.
195
+
196
+ The move that makes this both theme-agnostic AND able to *swap* the brand pair
197
+ (`primary` ↔ `on-primary`, needed for a solid button or a filled icon tile)
198
+ without a CSS custom-property cycle: the accent + its ink are CAPTURED on the
199
+ surface element (where the tokens still hold their normal values), then the
200
+ inverted role-set is applied to DESCENDANTS from those captures — so a role can
201
+ reference the pre-inversion value it is replacing. Every value is a `color-mix`
202
+ of the captured pair, so it holds on every theme, and the surface and band
203
+ steps stay a lighter shade of the accent (gradation kept in-hue).
204
+
205
+ A theme that needs to diverge overrides any role by nesting a rule for its own
206
+ `[data-theme=…]` under `[data-surface="accent"]` — the same seam as chrome. */
207
+ [data-surface="accent"] {
208
+ color: var(--fold-color-on-primary);
209
+ --_accent-ink: var(--fold-color-on-primary);
210
+ --_accent-fill: var(--fold-color-primary);
211
+ }
212
+ [data-surface="accent"] * {
213
+ /* text ramp → the light ink. COMPRESSED vs a normal surface: an accent ground
214
+ has little contrast headroom (a mid-bright accent caps white text near 3:1),
215
+ so the accent card is an emphasis surface — its text clears AA-large (3:1),
216
+ asserted by accent-contrast.spec.ts, and secondary/muted keep more ink than
217
+ they would on the page. A light accent that still reads thin overrides the
218
+ ramp per theme (surfaces.md). */
219
+ --fold-color-text: var(--_accent-ink);
220
+ --fold-color-text-secondary: color-mix(
221
+ in srgb,
222
+ var(--_accent-ink) 96%,
223
+ transparent
224
+ );
225
+ --fold-color-text-muted: color-mix(
226
+ in srgb,
227
+ var(--_accent-ink) 74%,
228
+ transparent
229
+ );
230
+ --fold-color-text-faded: color-mix(
231
+ in srgb,
232
+ var(--_accent-ink) 58%,
233
+ transparent
234
+ );
235
+ /* borders + separators → thin ink lines */
236
+ --fold-color-border: color-mix(in srgb, var(--_accent-ink) 24%, transparent);
237
+ --fold-color-border-subtle: color-mix(
238
+ in srgb,
239
+ var(--_accent-ink) 15%,
240
+ transparent
241
+ );
242
+ /* nested surfaces + raised tiles/bands → a lighter step of the ACCENT itself */
243
+ --fold-color-surface-card: color-mix(
244
+ in srgb,
245
+ var(--_accent-ink) 12%,
246
+ var(--_accent-fill)
247
+ );
248
+ --fold-color-surface-raised: color-mix(
249
+ in srgb,
250
+ var(--_accent-ink) 16%,
251
+ var(--_accent-fill)
252
+ );
253
+ --fold-color-surface-hover: color-mix(
254
+ in srgb,
255
+ var(--_accent-ink) 18%,
256
+ var(--_accent-fill)
257
+ );
258
+ --fold-color-surface-sunken: color-mix(
259
+ in srgb,
260
+ var(--_accent-ink) 8%,
261
+ var(--_accent-fill)
262
+ );
263
+ /* the brand pair, SWAPPED from the captures (no cycle): the fill becomes the
264
+ light ink (link text, glass button, chip ground) and its on-colour becomes
265
+ the accent — so a filled icon tile or solid button reads accent-on-light. */
266
+ --fold-color-primary: var(--_accent-ink);
267
+ --fold-color-on-primary: var(--_accent-fill);
268
+ --fold-color-primary-text: var(--_accent-ink);
269
+ --fold-color-primary-strong: var(--_accent-ink);
270
+ --fold-color-primary-surface: color-mix(
271
+ in srgb,
272
+ var(--_accent-ink) 16%,
273
+ transparent
274
+ );
275
+ --fold-color-primary-border: color-mix(
276
+ in srgb,
277
+ var(--_accent-ink) 32%,
278
+ transparent
279
+ );
280
+ }
281
+
189
282
  /* ── Elevated surfaces ────────────────────────────────────────
190
283
  A `[data-elevated]` (stamped by the `[foldElevated]` directive) is a raised
191
284
  card: radius + shadow, riding on the element's own background so its colour
@@ -702,3 +795,148 @@
702
795
  transparent
703
796
  );
704
797
  }
798
+
799
+ /* ── Extra theme: TITAN ───────────────────────────────────────
800
+ Brushed titanium, light + warm. A cool brushed-steel ground — the
801
+ header + rails sit at the page's own tint, so the top reads frameless
802
+ — with bright polished cards that float off it on the shared elevation
803
+ shadow (that lift is the "raised metal piece", no per-theme shadow
804
+ needed). The brand is HEAT-anodized titanium: the copper-orange the
805
+ metal takes when torched, warming the whole steel read. Content borders
806
+ re-point to a SOLID steel primitive (a palpable machined seam, where
807
+ the light themes use an alpha hairline); corners soften in scales.css.
808
+ Status families hold at the lumen (light) tints — only ground + brand
809
+ move. Uniform-polarity, so no chrome override is needed. */
810
+ [data-theme="titan"] {
811
+ /* Surfaces — header + rails at the page's own tint (a frameless top) */
812
+ --fold-color-bg-page: var(--fold-ref-steel-200);
813
+ --fold-color-bg-header: var(--fold-ref-steel-150);
814
+ --fold-color-bg-rail-primary: var(--fold-ref-steel-100);
815
+ --fold-color-bg-rail-secondary: var(--fold-ref-steel-150);
816
+ --fold-color-bg-rail-tertiary: color-mix(
817
+ in srgb,
818
+ var(--fold-ref-black) 3%,
819
+ transparent
820
+ );
821
+
822
+ /* Primary / accent — heat-anodized copper-orange, deep enough for white */
823
+ --fold-color-primary: var(--fold-ref-titanium-500);
824
+ --fold-color-primary-strong: var(--fold-ref-titanium-600);
825
+ --fold-color-on-primary: var(--fold-ref-white);
826
+ --fold-color-primary-text: var(--fold-ref-titanium-700);
827
+ --fold-color-primary-surface: color-mix(
828
+ in srgb,
829
+ var(--fold-ref-titanium-500) 10%,
830
+ transparent
831
+ );
832
+ --fold-color-primary-border: color-mix(
833
+ in srgb,
834
+ var(--fold-ref-titanium-500) 28%,
835
+ transparent
836
+ );
837
+
838
+ /* Info (purple) — lumen tint */
839
+ --fold-color-info: var(--fold-ref-purple-600);
840
+ --fold-color-info-text: var(--fold-ref-purple-500);
841
+ --fold-color-info-surface: color-mix(
842
+ in srgb,
843
+ var(--fold-ref-purple-600) 8%,
844
+ transparent
845
+ );
846
+ --fold-color-info-border: color-mix(
847
+ in srgb,
848
+ var(--fold-ref-purple-600) 22%,
849
+ transparent
850
+ );
851
+
852
+ /* Warning (amber) */
853
+ --fold-color-warning: var(--fold-ref-amber-600);
854
+ --fold-color-warning-text: var(--fold-ref-amber-550);
855
+ --fold-color-warning-surface: color-mix(
856
+ in srgb,
857
+ var(--fold-ref-amber-600) 8%,
858
+ transparent
859
+ );
860
+ --fold-color-warning-border: color-mix(
861
+ in srgb,
862
+ var(--fold-ref-amber-600) 22%,
863
+ transparent
864
+ );
865
+
866
+ /* Alert (red) */
867
+ --fold-color-alert: var(--fold-ref-red-600);
868
+ --fold-color-alert-text: var(--fold-ref-red-450);
869
+ --fold-color-alert-surface: color-mix(
870
+ in srgb,
871
+ var(--fold-ref-red-600) 8%,
872
+ transparent
873
+ );
874
+ --fold-color-alert-border: color-mix(
875
+ in srgb,
876
+ var(--fold-ref-red-600) 22%,
877
+ transparent
878
+ );
879
+
880
+ /* Success (green) */
881
+ --fold-color-success: var(--fold-ref-green-500);
882
+ --fold-color-success-text: var(--fold-ref-green-550);
883
+ --fold-color-success-surface: color-mix(
884
+ in srgb,
885
+ var(--fold-ref-green-500) 10%,
886
+ transparent
887
+ );
888
+ --fold-color-success-border: color-mix(
889
+ in srgb,
890
+ var(--fold-ref-green-500) 25%,
891
+ transparent
892
+ );
893
+
894
+ /* Text — graphite on the light page (high contrast) */
895
+ --fold-color-text: var(--fold-ref-steel-900);
896
+ --fold-color-text-secondary: var(--fold-ref-steel-600);
897
+ --fold-color-text-muted: var(--fold-ref-steel-500);
898
+ --fold-color-text-faded: var(--fold-ref-steel-400);
899
+
900
+ /* Card — a bright polished-steel plate that floats off the silver ground */
901
+ --fold-color-surface-card: var(--fold-ref-steel-50);
902
+ --fold-color-surface-sunken: var(--fold-ref-steel-100);
903
+
904
+ /* Neutral surfaces — faint black overlays for hover/raise cues on light */
905
+ --fold-color-surface-subtle: color-mix(
906
+ in srgb,
907
+ var(--fold-ref-black) 3%,
908
+ transparent
909
+ );
910
+ --fold-color-surface-raised: color-mix(
911
+ in srgb,
912
+ var(--fold-ref-black) 5%,
913
+ transparent
914
+ );
915
+ --fold-color-surface-hover: var(
916
+ --fold-ref-steel-150
917
+ ); /* solid raised hover */
918
+
919
+ /* Borders — SOLID brushed-steel seams (the palpable metal edge), where the
920
+ light themes use an alpha hairline. */
921
+ --fold-color-border: var(--fold-ref-steel-300);
922
+ --fold-color-border-subtle: var(--fold-ref-steel-150);
923
+
924
+ /* Glass — frosted brushed steel */
925
+ --fold-color-glass: color-mix(
926
+ in srgb,
927
+ var(--fold-ref-steel-50) 66%,
928
+ transparent
929
+ );
930
+ --fold-color-glass-border: color-mix(
931
+ in srgb,
932
+ var(--fold-ref-black) 12%,
933
+ transparent
934
+ );
935
+
936
+ /* Scrim — a darkening veil behind the mobile nav drawer. */
937
+ --fold-color-scrim: color-mix(
938
+ in srgb,
939
+ var(--fold-ref-black) 45%,
940
+ transparent
941
+ );
942
+ }