@wippy-fe/theme 0.0.7

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.
Files changed (91) hide show
  1. package/README.md +64 -0
  2. package/THEMING.md +316 -0
  3. package/package.json +35 -0
  4. package/primevue/accordion.css +58 -0
  5. package/primevue/autocomplete.css +144 -0
  6. package/primevue/avatar.css +50 -0
  7. package/primevue/badge.css +53 -0
  8. package/primevue/blockui.css +15 -0
  9. package/primevue/breadcrumb.css +41 -0
  10. package/primevue/button.css +341 -0
  11. package/primevue/buttongroup.css +19 -0
  12. package/primevue/card.css +22 -0
  13. package/primevue/carousel.css +64 -0
  14. package/primevue/cascadeselect.css +169 -0
  15. package/primevue/checkbox.css +84 -0
  16. package/primevue/chip.css +27 -0
  17. package/primevue/colorpicker.css +47 -0
  18. package/primevue/common.css +81 -0
  19. package/primevue/confirmdialog.css +10 -0
  20. package/primevue/confirmpopup.css +66 -0
  21. package/primevue/contextmenu.css +101 -0
  22. package/primevue/datatable.css +408 -0
  23. package/primevue/dataview.css +29 -0
  24. package/primevue/datepicker.css +211 -0
  25. package/primevue/dialog.css +125 -0
  26. package/primevue/divider.css +52 -0
  27. package/primevue/dock.css +84 -0
  28. package/primevue/drawer.css +94 -0
  29. package/primevue/fieldset.css +45 -0
  30. package/primevue/fileupload.css +57 -0
  31. package/primevue/floatlabel.css +73 -0
  32. package/primevue/galleria.css +244 -0
  33. package/primevue/iconfield.css +23 -0
  34. package/primevue/iftalabel.css +32 -0
  35. package/primevue/image.css +56 -0
  36. package/primevue/imagecompare.css +38 -0
  37. package/primevue/inplace.css +13 -0
  38. package/primevue/inputgroup.css +67 -0
  39. package/primevue/inputnumber.css +84 -0
  40. package/primevue/inputotp.css +9 -0
  41. package/primevue/inputtext.css +38 -0
  42. package/primevue/knob.css +37 -0
  43. package/primevue/listbox.css +79 -0
  44. package/primevue/megamenu.css +207 -0
  45. package/primevue/menu.css +51 -0
  46. package/primevue/menubar.css +169 -0
  47. package/primevue/message.css +228 -0
  48. package/primevue/metergroup.css +67 -0
  49. package/primevue/multiselect.css +143 -0
  50. package/primevue/orderlist.css +10 -0
  51. package/primevue/organizationchart.css +71 -0
  52. package/primevue/overlaybadge.css +13 -0
  53. package/primevue/paginator.css +58 -0
  54. package/primevue/panel.css +27 -0
  55. package/primevue/panelmenu.css +94 -0
  56. package/primevue/password.css +61 -0
  57. package/primevue/picklist.css +18 -0
  58. package/primevue/popover.css +46 -0
  59. package/primevue/progressbar.css +67 -0
  60. package/primevue/progressspinner.css +58 -0
  61. package/primevue/radiobutton.css +93 -0
  62. package/primevue/rating.css +23 -0
  63. package/primevue/ripple.css +7 -0
  64. package/primevue/scrollpanel.css +41 -0
  65. package/primevue/scrolltop.css +25 -0
  66. package/primevue/select.css +144 -0
  67. package/primevue/selectbutton.css +25 -0
  68. package/primevue/skeleton.css +11 -0
  69. package/primevue/slider.css +42 -0
  70. package/primevue/speeddial.css +48 -0
  71. package/primevue/splitbutton.css +34 -0
  72. package/primevue/splitter.css +56 -0
  73. package/primevue/stepper.css +102 -0
  74. package/primevue/tabs.css +84 -0
  75. package/primevue/tag.css +38 -0
  76. package/primevue/tailwind.css +104 -0
  77. package/primevue/terminal.css +22 -0
  78. package/primevue/textarea.css +42 -0
  79. package/primevue/tieredmenu.css +105 -0
  80. package/primevue/timeline.css +113 -0
  81. package/primevue/toast.css +172 -0
  82. package/primevue/togglebutton.css +63 -0
  83. package/primevue/toggleswitch.css +66 -0
  84. package/primevue/toolbar.css +12 -0
  85. package/primevue/tooltip.css +38 -0
  86. package/primevue/tree.css +103 -0
  87. package/primevue/treeselect.css +116 -0
  88. package/primevue/treetable.css +300 -0
  89. package/primevue-plugin.ts +8 -0
  90. package/tailwind.config.ts +28 -0
  91. package/theme-config.css +124 -0
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # @wippy-fe/theme
2
+
3
+ Theme variables, shared Tailwind config, and PrimeVue styling for Wippy web components and applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @wippy-fe/theme
9
+ ```
10
+
11
+ ## Quick Setup
12
+
13
+ ### 1. Theme variables (all components)
14
+
15
+ Import the CSS variables in your `styles.css`:
16
+
17
+ ```css
18
+ @import "@wippy-fe/theme/theme-config.css";
19
+ ```
20
+
21
+ ### 2. Tailwind preset (components using Tailwind)
22
+
23
+ Use the shared preset in your `tailwind.config.ts`:
24
+
25
+ ```ts
26
+ import themePreset from '@wippy-fe/theme/tailwind.config'
27
+
28
+ export default {
29
+ presets: [themePreset],
30
+ content: ['./src/**/*.{vue,ts}'],
31
+ }
32
+ ```
33
+
34
+ This includes `tailwindcss-primeui` (color utilities, semantic classes, animations), `tailwind-scrollbar`, and the secondary color palette.
35
+
36
+ ### 3. PrimeVue plugin (components using PrimeVue)
37
+
38
+ Install PrimeVue with the correct config:
39
+
40
+ ```ts
41
+ import { PrimeVuePlugin } from '@wippy-fe/theme/primevue-plugin'
42
+
43
+ // In vueConfig.plugins:
44
+ plugins: [PrimeVuePlugin]
45
+ ```
46
+
47
+ Import PrimeVue component styles in your CSS:
48
+
49
+ ```css
50
+ @import "@wippy-fe/theme/primevue/tailwind.css";
51
+ ```
52
+
53
+ ## What's Included
54
+
55
+ | Export | Description |
56
+ |---|---|
57
+ | `@wippy-fe/theme` | Default theme CSS variables (`theme-config.css`) |
58
+ | `@wippy-fe/theme/tailwind.config` | Shared Tailwind preset (PrimeUI + secondary colors + scrollbar) |
59
+ | `@wippy-fe/theme/primevue-plugin` | Vue plugin that installs PrimeVue with `{ theme: 'none' }` |
60
+ | `@wippy-fe/theme/primevue/*` | PrimeVue component CSS files (Tailwind @apply-based) |
61
+
62
+ ## Theming Reference
63
+
64
+ See [THEMING.md](./THEMING.md) for the full reference on CSS variables, Tailwind utility classes, dark mode behavior, and PrimeVue component styling.
package/THEMING.md ADDED
@@ -0,0 +1,316 @@
1
+ # Wippy Theming Reference
2
+
3
+ Comprehensive reference for CSS variables, Tailwind utility classes, dark mode behavior, and PrimeVue styling used across Wippy web components and applications.
4
+
5
+ ## 1. CSS Variables
6
+
7
+ All variables are defined in `theme-config.css` and set on `:root`. At runtime, the host injects the real theme — these serve as the dev-time fallback and contract.
8
+
9
+ ### Primary palette (11 vars)
10
+
11
+ Base: `--p-primary` (default: `rgb(0, 95, 178)`)
12
+
13
+ | Variable | Value |
14
+ |---|---|
15
+ | `--p-primary-50` | `color-mix(in srgb, var(--p-primary) 5%, white)` |
16
+ | `--p-primary-100` | `color-mix(in srgb, var(--p-primary) 10%, white)` |
17
+ | `--p-primary-200` | `color-mix(in srgb, var(--p-primary) 20%, white)` |
18
+ | `--p-primary-300` | `color-mix(in srgb, var(--p-primary) 30%, white)` |
19
+ | `--p-primary-400` | `color-mix(in srgb, var(--p-primary) 40%, white)` |
20
+ | `--p-primary-500` | `var(--p-primary)` (base) |
21
+ | `--p-primary-600` | `color-mix(in srgb, var(--p-primary) 80%, black)` |
22
+ | `--p-primary-700` | `color-mix(in srgb, var(--p-primary) 70%, black)` |
23
+ | `--p-primary-800` | `color-mix(in srgb, var(--p-primary) 60%, black)` |
24
+ | `--p-primary-900` | `color-mix(in srgb, var(--p-primary) 50%, black)` |
25
+ | `--p-primary-950` | `color-mix(in srgb, var(--p-primary) 40%, black)` |
26
+
27
+ ### Secondary palette (11 vars)
28
+
29
+ Base: `--p-secondary` (default: `#6f7385`)
30
+
31
+ Same numbered scale pattern as primary (50–950) using `color-mix`.
32
+
33
+ ### Surface palette (13 vars)
34
+
35
+ | Variable | Light value | Dark value |
36
+ |---|---|---|
37
+ | `--p-surface-0` | `#fff` | `#fff` |
38
+ | `--p-surface-50` | `#fafafa` | `#fafafa` |
39
+ | `--p-surface-100` | `#f4f4f5` | `#f4f4f5` |
40
+ | `--p-surface-200` | `#e4e4e7` | `#e4e4e7` |
41
+ | `--p-surface-300` | `#d4d4d8` | `#d4d4d8` |
42
+ | `--p-surface-400` | `#a1a1aa` | `#a1a1aa` |
43
+ | `--p-surface-500` | `#71717a` | `#71717a` |
44
+ | `--p-surface-600` | `#52525b` | `#545250` (warm) |
45
+ | `--p-surface-700` | `#3f3f46` | `#403e3c` (warm) |
46
+ | `--p-surface-800` | `#27272a` | `#2b2927` (warm) |
47
+ | `--p-surface-900` | `#18181b` | `#1c1a19` (warm) |
48
+ | `--p-surface-950` | `#09090b` | `#0f0e0d` (warm) |
49
+
50
+ **Fixed light-to-dark scale** — 0 is always lightest, 950 always darkest. The scale does NOT flip with dark mode. In dark mode, only 600–950 get warmer undertones.
51
+
52
+ ### Semantic variables (15 vars)
53
+
54
+ These **flip with dark mode** — use these for theme-dependent styling.
55
+
56
+ | Variable | Light | Dark |
57
+ |---|---|---|
58
+ | `--p-primary-color` | `primary-500` | `primary-400` |
59
+ | `--p-primary-contrast-color` | `surface-0` | `surface-900` |
60
+ | `--p-primary-hover-color` | `primary-600` | `primary-300` |
61
+ | `--p-primary-active-color` | `primary-700` | `primary-200` |
62
+ | `--p-text-color` | `surface-700` | `surface-0` |
63
+ | `--p-text-hover-color` | `surface-800` | `surface-0` |
64
+ | `--p-text-muted-color` | `surface-500` | `surface-400` |
65
+ | `--p-text-hover-muted-color` | `surface-600` | `surface-300` |
66
+ | `--p-content-background` | — | `surface-900` (via host) |
67
+ | `--p-content-border-color` | `surface-200` | `surface-700` |
68
+ | `--p-content-hover-background` | `surface-100` | `surface-800` |
69
+ | `--p-content-hover-color` | `surface-800` | `surface-0` |
70
+ | `--p-highlight-background` | `primary-50` | `primary-400 @ 16%` |
71
+ | `--p-highlight-color` | `primary-700` | `white @ 87%` |
72
+ | `--p-highlight-focus-background` | `primary-100` | `primary-400 @ 24%` |
73
+ | `--p-highlight-focus-color` | `primary-800` | `white @ 87%` |
74
+ | `--p-content-border-radius` | `6px` | `6px` |
75
+
76
+ ## 2. Tailwind Utility Classes
77
+
78
+ Provided by `tailwindcss-primeui` plugin (included in the shared Tailwind preset).
79
+
80
+ ### Color utilities
81
+
82
+ Work with `bg-`, `text-`, `border-`, `outline-`, `ring-` prefixes:
83
+
84
+ | Class suffix | Maps to |
85
+ |---|---|
86
+ | `primary` | `--p-primary-color` |
87
+ | `primary-emphasis` | `--p-primary-hover-color` |
88
+ | `primary-emphasis-alt` | `--p-primary-active-color` |
89
+ | `primary-contrast` | `--p-primary-contrast-color` |
90
+ | `primary-{0,50,100,...,950}` | Full primary shade range |
91
+ | `surface-{0,50,100,...,950}` | Full surface shade range |
92
+
93
+ ### Semantic utilities
94
+
95
+ | Class | Maps to |
96
+ |---|---|
97
+ | `.text-color` | `--p-text-color` |
98
+ | `.text-color-emphasis` | `--p-text-hover-color` |
99
+ | `.text-muted-color` | `--p-text-muted-color` |
100
+ | `.text-muted-color-emphasis` | `--p-text-hover-muted-color` |
101
+ | `.bg-emphasis` | Emphasis background + text |
102
+ | `.bg-highlight` | Highlighted state (selected items, active rows) |
103
+ | `.bg-highlight-emphasis` | Emphasized highlight |
104
+ | `.border-surface` | `--p-content-border-color` |
105
+ | `.rounded-border` | `--p-content-border-radius` |
106
+
107
+ ### Animation utilities
108
+
109
+ | Class | Description |
110
+ |---|---|
111
+ | `.animate-fadein` | Fade in |
112
+ | `.animate-fadeout` | Fade out |
113
+ | `.animate-slidedown` | Slide down |
114
+ | `.animate-slideup` | Slide up |
115
+ | `.animate-scalein` | Scale in |
116
+ | `.animate-fadeinleft` | Fade in from left |
117
+ | `.animate-fadeinright` | Fade in from right |
118
+ | `.animate-fadeinup` | Fade in from below |
119
+ | `.animate-fadeindown` | Fade in from above |
120
+ | `.animate-duration-{ms}` | Animation duration |
121
+ | `.animate-delay-{ms}` | Animation delay |
122
+ | `.animate-ease-*` | Easing functions |
123
+
124
+ ### Secondary color utilities
125
+
126
+ Added by the shared Tailwind preset via `theme.extend.colors`:
127
+
128
+ ```
129
+ bg-secondary-{50..950}
130
+ text-secondary-{50..950}
131
+ border-secondary-{50..950}
132
+ ```
133
+
134
+ ## 3. Dark Mode
135
+
136
+ Variables switch at `@media (prefers-color-scheme: dark)`. Key changes:
137
+
138
+ - `--p-primary` base shifts from `rgb(0, 95, 178)` to `rgb(0, 125, 178)` (brighter)
139
+ - `--p-primary-color` shifts from `primary-500` to `primary-400`
140
+ - `--p-content-background` shifts to `surface-900` (via host injection)
141
+ - `--p-text-color` shifts from `surface-700` to `surface-0`
142
+ - Surface 600–950 get warmer undertones in dark mode
143
+
144
+ ### Rules
145
+
146
+ - **Use semantic variables** (`--p-text-color`, `--p-content-background`) for colors that should flip with dark mode.
147
+ - **Use `surface-0`/`surface-950`** only when you explicitly need the fixed shade regardless of mode.
148
+ - **For derived shades**: `color-mix(in srgb, var(--p-content-background) 85%, var(--p-text-color) 15%)`.
149
+ - **Never use `--p-surface-N`** for theme-dependent colors — the numbered scale does NOT flip.
150
+
151
+ ## 4. PrimeVue Styling (opt-in)
152
+
153
+ The `primevue/` directory contains CSS files that style PrimeVue component tags (`.p-button`, `.p-datatable`, etc.) using Tailwind `@apply` directives. These are **only needed if your component uses PrimeVue tags**.
154
+
155
+ ### Setup
156
+
157
+ 1. Add `primevue` as a dependency
158
+ 2. Import `PrimeVuePlugin` from `@wippy-fe/theme/primevue-plugin` — installs PrimeVue with `{ theme: 'none' }`
159
+ 3. Import PrimeVue CSS: `@import "@wippy-fe/theme/primevue/tailwind.css"` in your styles
160
+ 4. Add `'primeVueCssUrl'` to `hostCssKeys` so the host injects PrimeVue CSS at runtime
161
+
162
+ ### How it works
163
+
164
+ The CSS files use theme variables via Tailwind classes. Example from `button.css`:
165
+
166
+ ```css
167
+ .p-button {
168
+ @apply bg-primary text-primary-contrast border-primary
169
+ enabled:hover:bg-primary-emphasis enabled:active:bg-primary-emphasis-alt ...
170
+ }
171
+ ```
172
+
173
+ The `tailwind.css` master file imports all component CSS files organized by category (form, button, data, overlay, menu, panel, file, message, media, misc).
174
+
175
+ ### Available PrimeVue component styles
176
+
177
+ **Form**: autocomplete, cascadeselect, checkbox, colorpicker, datepicker, iconfield, iftalabel, inputgroup, inputnumber, inputotp, inputtext, floatlabel, knob, listbox, multiselect, password, radiobutton, rating, select, selectbutton, slider, textarea, togglebutton, toggleswitch, treeselect
178
+
179
+ **Button**: button, buttongroup, speeddial, splitbutton
180
+
181
+ **Data**: datatable, dataview, paginator, picklist, orderlist, organizationchart, timeline, tree, treetable
182
+
183
+ **Overlay**: confirmdialog, confirmpopup, dialog, drawer, popover, tooltip
184
+
185
+ **Menu**: breadcrumb, contextmenu, dock, menu, menubar, megamenu, panelmenu, tieredmenu
186
+
187
+ **Panel**: accordion, card, divider, fieldset, panel, scrollpanel, splitter, stepper, tabs, toolbar
188
+
189
+ **File**: fileupload
190
+
191
+ **Message**: message, toast
192
+
193
+ **Media**: carousel, galleria, image, imagecompare
194
+
195
+ **Misc**: avatar, badge, blockui, chip, inplace, metergroup, overlaybadge, progressbar, progressspinner, ripple, scrolltop, skeleton, tag, terminal
196
+
197
+ ## 5. Choosing Custom Colors
198
+
199
+ When overriding `--p-primary`, `--p-secondary`, or the surface palette, follow these guidelines to ensure contrast and readability across both modes.
200
+
201
+ ### How the shade scale works
202
+
203
+ The `color-mix()` system blends your base color with white (lighter shades) or black (darker shades). The percentages are fixed:
204
+
205
+ | Shade | Blend |
206
+ |---|---|
207
+ | 50 | 5% base + 95% white |
208
+ | 100 | 10% base + 90% white |
209
+ | 200 | 20% base + 80% white |
210
+ | 300 | 30% base + 70% white |
211
+ | 400 | 40% base + 60% white |
212
+ | **500** | **100% base (no blend)** |
213
+ | 600 | 80% base + 20% black |
214
+ | 700 | 70% base + 30% black |
215
+ | 800 | 60% base + 40% black |
216
+ | 900 | 50% base + 50% black |
217
+ | 950 | 40% base + 60% black |
218
+
219
+ This means the base color's luminosity determines the contrast of the **entire scale**. A too-light base produces a washed-out 500 that can't contrast against white text; a too-dark base makes 400 too dim for dark mode.
220
+
221
+ ### Primary color luminosity
222
+
223
+ The primary base is used at two critical contrast points:
224
+
225
+ 1. **Light mode**: `bg-primary` (500) with `text-primary-contrast` (white) — buttons, badges, checkboxes
226
+ 2. **Dark mode**: `bg-primary` (400 = 40% base + 60% white) with `text-primary-contrast` (surface-900, near-black)
227
+
228
+ **Recommended relative luminance for `--p-primary`: 0.05–0.15** (medium-dark, saturated).
229
+
230
+ | Example | RGB | Rel. luminance | Light contrast (500 vs white) | Dark contrast (400 vs black) |
231
+ |---|---|---|---|---|
232
+ | Default blue | `rgb(0, 95, 178)` | ~0.10 | ~8.5:1 (AAA) | ~6.8:1 (AA) |
233
+ | Deep teal | `rgb(0, 128, 128)` | ~0.14 | ~5.8:1 (AA) | ~8.7:1 (AAA) |
234
+ | Indigo | `rgb(79, 70, 229)` | ~0.07 | ~8.0:1 (AAA) | ~5.5:1 (AA) |
235
+ | Red | `rgb(185, 28, 28)` | ~0.05 | ~9.2:1 (AAA) | ~4.7:1 (borderline) |
236
+ | Forest green | `rgb(22, 101, 52)` | ~0.08 | ~7.2:1 (AAA) | ~6.1:1 (AA) |
237
+ | Orange | `rgb(194, 120, 3)` | ~0.18 | ~3.7:1 (FAIL) | ~9.5:1 (AAA) |
238
+
239
+ **Key constraints:**
240
+ - Luminance **> 0.18** → 500 shade is too light for white text (fails WCAG AA 4.5:1 in light mode)
241
+ - Luminance **< 0.04** → 400 shade is too dark for dark-on-light text (fails WCAG AA in dark mode)
242
+ - The sweet spot is **0.06–0.14** — both modes pass WCAG AA (4.5:1), with most passing AAA (7:1)
243
+ - Pure, saturated colors (high chroma) work best. Desaturated/muted colors lose contrast faster
244
+
245
+ **If your brand color is too light** (e.g., orange, yellow, lime): darken it for `--p-primary` and use the original as a secondary or accent. Light-mode buttons with white text will fail contrast otherwise.
246
+
247
+ **If your brand color is too dark** (e.g., navy, dark brown): lighten it slightly. The 400 shade in dark mode needs enough contrast against `surface-900`.
248
+
249
+ ### Secondary color luminosity
250
+
251
+ Secondary is used for muted/deemphasized elements — less critical than primary but still appears in text and borders.
252
+
253
+ **Recommended relative luminance for `--p-secondary`: 0.10–0.25** (mid-range, desaturated).
254
+
255
+ The default `#6f7385` (luminance ~0.16) is a muted gray-purple that reads as neutral in both modes. Good secondary colors:
256
+ - Are **less saturated** than primary (avoid competing for attention)
257
+ - Have **mid-range luminance** so the full shade scale is usable
258
+ - Work as `text-secondary-600` on white and `text-secondary-300` on dark backgrounds
259
+
260
+ ### Surface palette
261
+
262
+ Surfaces are a fixed grayscale ramp — they do NOT flip with dark mode. The semantic variables (`--p-content-background`, `--p-text-color`) reference different points on this scale per mode.
263
+
264
+ **Light mode assignments:**
265
+
266
+ | Role | Surface | Hex | Purpose |
267
+ |---|---|---|---|
268
+ | Page background | 0 | `#ffffff` | Main canvas |
269
+ | Card/container background | 0 | `#ffffff` | Content containers |
270
+ | Hover background | 100 | `#f4f4f5` | Interactive hover state |
271
+ | Border | 200 | `#e4e4e7` | Borders, dividers |
272
+ | Muted text | 500 | `#71717a` | Secondary text, labels |
273
+ | Body text | 700 | `#3f3f46` | Primary readable text |
274
+ | Strong emphasis | 800 | `#27272a` | Headings, hover text |
275
+
276
+ **Dark mode assignments:**
277
+
278
+ | Role | Surface | Hex | Purpose |
279
+ |---|---|---|---|
280
+ | Page background | 900 | `#1c1a19` (warm) | Main canvas |
281
+ | Card/container background | 800 | `#2b2927` (warm) | Elevated containers |
282
+ | Hover background | 800 | `#2b2927` (warm) | Interactive hover state |
283
+ | Border | 700 | `#403e3c` (warm) | Borders, dividers |
284
+ | Muted text | 400 | `#a1a1aa` | Secondary text, labels |
285
+ | Body text | 0 | `#ffffff` | Primary readable text |
286
+ | Strong emphasis | 0 | `#ffffff` | Headings, hover text |
287
+
288
+ **Dark mode warm tones** (600–950): The default surfaces shift from cool zinc grays to slightly warm brown-grays in dark mode. This reduces visual fatigue on dark backgrounds. The shift is subtle — `#545250` vs `#52525b` for surface-600 — but creates a warmer, more natural feel.
289
+
290
+ When providing custom surfaces, keep these rules:
291
+ - **0 must always be `#ffffff`** (or very near it) — used as contrast text in dark mode
292
+ - **950 must always be very dark** — used as the maximum-contrast anchor
293
+ - **The scale must increase monotonically in darkness** — no inversions
294
+ - **600–950 should shift warm** in dark mode for visual comfort (optional but recommended)
295
+ - **Don't change 0–500** between modes unless you have a specific reason — the semantic variables handle mode switching
296
+
297
+ ### Contrast verification
298
+
299
+ After choosing colors, verify these critical pairs meet WCAG AA (4.5:1 minimum):
300
+
301
+ | Pair | Light mode | Dark mode |
302
+ |---|---|---|
303
+ | `bg-primary` + `text-primary-contrast` | primary-500 vs white | primary-400 vs surface-900 |
304
+ | `bg-highlight` + text | primary-50 vs primary-700 | primary-400@16% vs white@87% |
305
+ | Body text on background | surface-700 vs white | surface-0 vs surface-900 |
306
+ | Muted text on background | surface-500 vs white | surface-400 vs surface-900 |
307
+
308
+ Quick formula for relative luminance of an sRGB color:
309
+ ```
310
+ L = 0.2126 * R' + 0.7152 * G' + 0.0722 * B'
311
+ where R' = (R/255)^2.2 (simplified gamma)
312
+
313
+ Contrast ratio = (L_lighter + 0.05) / (L_darker + 0.05)
314
+ ```
315
+
316
+ WCAG AA requires 4.5:1 for normal text, 3:1 for large text (18px+ bold or 24px+ regular).
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@wippy-fe/theme",
3
+ "version": "0.0.7",
4
+ "description": "Theme variables, shared Tailwind config, and PrimeVue styling for Wippy web components.",
5
+ "type": "module",
6
+ "main": "theme-config.css",
7
+ "exports": {
8
+ ".": "./theme-config.css",
9
+ "./theme-config.css": "./theme-config.css",
10
+ "./tailwind.config": "./tailwind.config.ts",
11
+ "./primevue-plugin": "./primevue-plugin.ts",
12
+ "./primevue/*": "./primevue/*"
13
+ },
14
+ "files": [
15
+ "theme-config.css",
16
+ "tailwind.config.ts",
17
+ "primevue-plugin.ts",
18
+ "primevue/",
19
+ "THEMING.md",
20
+ "README.md"
21
+ ],
22
+ "dependencies": {
23
+ "tailwindcss-primeui": "^0.6.1",
24
+ "tailwind-scrollbar": "^3.0.0"
25
+ },
26
+ "peerDependencies": {
27
+ "primevue": "^4.0.0"
28
+ },
29
+ "peerDependenciesMeta": {
30
+ "primevue": {
31
+ "optional": true
32
+ }
33
+ },
34
+ "license": "UNLICENSED"
35
+ }
@@ -0,0 +1,58 @@
1
+ .p-accordionpanel {
2
+ @apply flex flex-col border-b border-surface-200 dark:border-surface-700
3
+ }
4
+
5
+ .p-accordionheader {
6
+ @apply cursor-pointer disabled:cursor-auto flex items-center justify-between p-[1.125rem] font-semibold
7
+ bg-surface-0 dark:bg-surface-900
8
+ text-surface-500 dark:text-surface-400
9
+ transition-colors duration-200
10
+ }
11
+
12
+ .p-accordionpanel:first-child > .p-accordionheader {
13
+ @apply rounded-ss-md rounded-se-md
14
+ }
15
+
16
+ .p-accordionpanel:last-child > .p-accordionheader {
17
+ @apply rounded-ee-md rounded-es-md
18
+ }
19
+
20
+ .p-accordionpanel:last-child.p-accordionpanel-active > .p-accordionheader {
21
+ @apply rounded-ee-md rounded-es-md
22
+ }
23
+
24
+ .p-accordionheader-toggle-icon {
25
+ @apply text-surface-500 dark:text-surface-400
26
+ }
27
+
28
+ .p-accordionpanel:not(.p-disabled) .p-accordionheader:focus-visible {
29
+ @apply outline outline-1 outline-offset-[-1px] outline-primary
30
+ }
31
+
32
+ .p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled) > .p-accordionheader:hover {
33
+ @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0
34
+ }
35
+
36
+ .p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled) .p-accordionheader:hover .p-accordionheader-toggle-icon {
37
+ @apply text-surface-700 dark:text-surface-0
38
+ }
39
+
40
+ .p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader {
41
+ @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0
42
+ }
43
+
44
+ .p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader .p-accordionheader-toggle-icon {
45
+ @apply text-surface-700 dark:text-surface-0;
46
+ }
47
+
48
+ .p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader:hover {
49
+ @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0
50
+ }
51
+
52
+ .p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader:hover .p-accordionheader-toggle-icon {
53
+ @apply text-surface-700 dark:text-surface-0;
54
+ }
55
+
56
+ .p-accordioncontent-content {
57
+ @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 pt-0 px-[1.125rem] pb-[1.125rem]
58
+ }
@@ -0,0 +1,144 @@
1
+ @import './inputtext';
2
+ @import './chip';
3
+
4
+ .p-autocomplete {
5
+ @apply inline-flex
6
+ }
7
+
8
+ .p-autocomplete.p-disabled {
9
+ @apply opacity-100
10
+ }
11
+
12
+ .p-autocomplete-loader {
13
+ @apply absolute top-1/2 -mt-2 end-3
14
+ }
15
+
16
+
17
+ .p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-loader {
18
+ @apply end-[3.25rem]
19
+ }
20
+
21
+ .p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input {
22
+ @apply flex-auto w-[1%]
23
+ }
24
+
25
+ .p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input,
26
+ .p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input-multiple {
27
+ @apply rounded-e-none
28
+ }
29
+
30
+ .p-autocomplete-dropdown {
31
+ @apply cursor-pointer inline-flex items-center justify-center select-none overflow-hidden relative w-10 rounded-e-md
32
+ bg-surface-100 enabled:hover:bg-surface-200 enabled:active:bg-surface-300
33
+ text-surface-600 enabled:hover:text-surface-700 enabled:hover:active:text-surface-800
34
+ dark:bg-surface-800 dark:enabled:hover:bg-surface-700 dark:enabled:active:bg-surface-600
35
+ dark:text-surface-300 dark:enabled:hover:text-surface-200 dark:enabled:active:text-surface-100
36
+ focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary
37
+ transition-colors duration-200
38
+ }
39
+
40
+ .p-autocomplete .p-autocomplete-overlay {
41
+ @apply min-w-full
42
+ }
43
+
44
+ .p-autocomplete-overlay {
45
+ @apply absolute top-0 left-0 rounded-md
46
+ bg-surface-0 dark:bg-surface-900
47
+ border border-surface-200 dark:border-surface-700
48
+ text-surface-700 dark:text-surface-0
49
+ shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)]
50
+ }
51
+
52
+ .p-autocomplete-list-container {
53
+ @apply overflow-auto
54
+ }
55
+
56
+ .p-autocomplete-list {
57
+ @apply m-0 p-1 list-none flex flex-col gap-[2px]
58
+ }
59
+
60
+ .p-autocomplete-option {
61
+ @apply cursor-pointer whitespace-nowrap relative overflow-hidden flex items-center px-3 py-2 rounded-sm
62
+ text-surface-700 dark:text-surface-0 bg-transparent border-none
63
+ transition-colors duration-200
64
+ }
65
+
66
+ .p-autocomplete-option:not(.p-autocomplete-option-selected):not(.p-disabled).p-focus {
67
+ @apply bg-surface-100 dark:bg-surface-800 text-surface-700 dark:text-surface-0
68
+ }
69
+
70
+ .p-autocomplete-option-selected {
71
+ @apply bg-highlight
72
+ }
73
+
74
+ .p-autocomplete-option-selected.p-focus {
75
+ @apply bg-highlight-emphasis
76
+ }
77
+
78
+ .p-autocomplete-option-group {
79
+ @apply m-0 px-3 py-2 text-surface-500 dark:text-surface-400 font-semibold bg-transparent
80
+ }
81
+
82
+ .p-autocomplete-input-multiple {
83
+ @apply m-0 list-none cursor-text overflow-hidden flex items-center flex-wrap
84
+ px-3 py-1 gap-1 text-surface-700 dark:text-surface-0 bg-surface-0 dark:bg-surface-950
85
+ border border-surface-300 dark:border-surface-700 rounded-md w-full
86
+ shadow-[0_1px_2px_0_rgba(18,18,23,0.05)]
87
+ transition-colors duration-200 outline-none
88
+ }
89
+
90
+ .p-autocomplete:not(.p-disabled):hover .p-autocomplete-input-multiple {
91
+ @apply border-surface-400 dark:border-surface-600
92
+ }
93
+
94
+ .p-autocomplete:not(.p-disabled).p-focus .p-autocomplete-input-multiple {
95
+ @apply border-primary
96
+ }
97
+
98
+ .p-autocomplete.p-invalid .p-autocomplete-input-multiple {
99
+ @apply border-red-400 dark:border-red-300
100
+ }
101
+
102
+ .p-variant-filled.p-autocomplete-input-multiple {
103
+ @apply bg-surface-50 dark:bg-surface-800
104
+ }
105
+
106
+ .p-autocomplete.p-disabled .p-autocomplete-input-multiple {
107
+ @apply opacity-100 cursor-default bg-surface-200 text-surface-500 dark:bg-surface-700 dark:text-surface-400
108
+ }
109
+
110
+ .p-autocomplete-chip.p-chip {
111
+ @apply py-1 rounded-sm
112
+ }
113
+
114
+ .p-autocomplete-input-multiple:has(.p-autocomplete-chip) {
115
+ @apply px-1
116
+ }
117
+
118
+ .p-autocomplete-chip-item.p-focus .p-autocomplete-chip {
119
+ @apply bg-surface-200 text-surface-800 dark:bg-surface-700 dark:text-surface-0
120
+ }
121
+
122
+ .p-autocomplete-input-chip {
123
+ @apply flex-auto inline-flex py-1
124
+ }
125
+
126
+ .p-autocomplete-input-chip input {
127
+ @apply border-none outline-none bg-transparent m-0 p-0 shadow-none rounded-none w-full text-inherit
128
+ }
129
+
130
+ .p-autocomplete-input-chip input::placeholder {
131
+ @apply text-surface-500 dark:text-surface-400
132
+ }
133
+
134
+ .p-autocomplete-empty-message {
135
+ @apply px-3 py-2
136
+ }
137
+
138
+ .p-autocomplete-fluid {
139
+ @apply flex
140
+ }
141
+
142
+ .p-autocomplete-fluid:has(.p-autocomplete-dropdown) .p-autocomplete-input {
143
+ @apply w-[1%]
144
+ }
@@ -0,0 +1,50 @@
1
+ .p-avatar {
2
+ @apply inline-flex items-center justify-center
3
+ w-8 h-8 text-base rounded-md
4
+ bg-surface-200 dark:bg-surface-700
5
+ }
6
+
7
+ .p-avatar-image {
8
+ @apply bg-transparent
9
+ }
10
+
11
+ .p-avatar-circle,
12
+ .p-avatar-circle img {
13
+ @apply rounded-full
14
+ }
15
+
16
+ .p-avatar-icon {
17
+ @apply text-base
18
+ }
19
+
20
+ .p-avatar img {
21
+ @apply w-full h-full
22
+ }
23
+
24
+ .p-avatar-lg {
25
+ @apply w-12 h-12 text-2xl
26
+ }
27
+
28
+ .p-avatar-lg .p-avatar-icon {
29
+ @apply text-2xl
30
+ }
31
+
32
+ .p-avatar-xl {
33
+ @apply w-16 h-16 text-[2rem]
34
+ }
35
+
36
+ .p-avatar-xl .p-avatar-icon {
37
+ @apply text-[2rem]
38
+ }
39
+
40
+ .p-avatar-group {
41
+ @apply flex items-center
42
+ }
43
+
44
+ .p-avatar-group .p-avatar + .p-avatar {
45
+ @apply -ms-4
46
+ }
47
+
48
+ .p-avatar-group .p-avatar {
49
+ @apply border-2 border-surface-200 dark:border-surface-700
50
+ }