@carissa-io/theme-default 0.0.0-stage → 0.1.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/DESIGN.md ADDED
@@ -0,0 +1,174 @@
1
+ # Carissa Default theme
2
+
3
+ **Swiss precision for high-performance interfaces.** International Typographic Style: information over decoration.
4
+
5
+ This is the design document of the **Carissa Default theme** (`@carissa-io/theme-default`): the decisions behind its
6
+ values. The components are style-agnostic; this theme gives them their look through SCSS variable overrides in
7
+ [scss/index.scss](scss/index.scss), and its palette and shared values (radius, focus ring, transition...) are Sass
8
+ variables at the top of that file. Other themes (tech terminal, brutalist, ...) are their own `theme-<name>` repositories,
9
+ never changes to the components.
10
+
11
+ ## Principles
12
+ - **Objective clarity:** information is prioritized over decoration.
13
+ - **Mathematical grid:** precise alignment and spacing, square corners.
14
+ - **High contrast:** absolute black (`#000`) for primary actions and focus; neutral scales for meta-data.
15
+
16
+ ## Palette
17
+ | Role | Value |
18
+ | :--- | :--- |
19
+ | Primary | `#000000` |
20
+ | Surface | `#fafafa` / `#f5f5f5` |
21
+ | Border (fields) | `#737373` (hover and focus: `#000`, focus adds a 1px ring) |
22
+ | Text (body) | `#171717` |
23
+ | Text (meta, placeholder) | `#737373` (4.7:1; lighter greys only for disabled states) |
24
+
25
+ ## Typography
26
+ | Variant | Purpose | Style |
27
+ | :--- | :--- | :--- |
28
+ | `h1` | Primary page header | Black (900), tight tracking |
29
+ | `h2` | Section header | Black (900) |
30
+ | `h3` | Sub-section | Bold (700) |
31
+ | `body` | Main content | Regular (400) |
32
+ | `label` | Metadata / tags / field labels | Bold (700), uppercase, widest tracking |
33
+ | `mono` | System data | Technical precision |
34
+
35
+ Font family: a neutral grotesque stack, `Helvetica Neue, Helvetica, Arial, Liberation Sans, sans-serif`, in keeping with
36
+ the International Typographic Style. No webfont is loaded, so a theme never depends on the network. Field text is
37
+ 1rem (16px, which also avoids the zoom-on-focus of mobile browsers); labels are 11px.
38
+
39
+ ## Buttons
40
+ Three variants from [components-button](components/components-button), all square, 44px tall, with the same uppercase,
41
+ bold, tracked 11px label as the field labels and 200ms color transitions.
42
+ - **Primary:** black background, white text; hover `#262626`, active `#404040`.
43
+ - **Secondary:** white background, 1px `#737373` border; the border turns black on hover.
44
+ - **Ghost:** transparent; a `#f5f5f5` surface appears on hover.
45
+ - **Disabled:** `#a3a3a3` text on a `#f5f5f5` surface (primary), or a lighter border (secondary, ghost); no hover.
46
+ - **Focus:** keyboard focus (`:focus-visible`) follows the general rule below: secondary and ghost thicken their border to
47
+ 2px; primary (filled) draws a 1px black ring offset by 2px.
48
+
49
+ ## Checkbox
50
+ From [components-checkbox](components/components-checkbox): the whole row (box and label) is the click target and is at
51
+ least 44px tall. The label is body text (1rem, `#171717`), not the uppercase field-label style.
52
+ - **Box:** 20px square, square corners, 1px `#737373` border; the border turns black on hover.
53
+ - **Checked:** black background with a white Lucide `check` mark.
54
+ - **Disabled:** `#a3a3a3` label and mark on a `#f5f5f5` box with a `#d4d4d4` border; no hover.
55
+ - **Error:** `#dc3545`, 13px, under the row; the box border turns red too. The built-in error shows after the first
56
+ interaction, an error passed by the parent shows at once.
57
+ - **Focus:** keyboard focus (`:focus-visible`): an empty box thickens its border to 2px; a checked (black) box draws a 1px
58
+ black ring offset by 2px.
59
+
60
+ ## Switch
61
+ From [components-switch](components/components-switch), a checkbox with `role="switch"`, same row, label and error.
62
+ - **Track:** 40 x 20px, square, white with a 1px `#737373` border (black on hover); a `#737373` square thumb.
63
+ - **On:** black track, white thumb; the thumb slides in 200ms, like the other color transitions.
64
+ - **Disabled:** `#f5f5f5` track with a `#d4d4d4` border and an `#a3a3a3` thumb.
65
+ - **Focus:** an off track thickens its border to 2px; an on (black) track draws a 1px black ring offset by 2px.
66
+
67
+ ## Radio group
68
+ From [components-radio-group](components/components-radio-group): a fieldset whose legend uses the field-label style
69
+ (11px, bold, uppercase, tracked, `#737373`). Each option row (dot and label) is the click target and is at least 44px
70
+ tall; the label is body text (1rem, `#171717`).
71
+ - **Dot:** 20px circle (the one round shape in the theme: a radio is a circle, so its radius is not the square `$radius`),
72
+ 1px `#737373` border; the border turns black on hover.
73
+ - **Checked:** black border with a 10px black inner dot on white.
74
+ - **Disabled:** `#a3a3a3` label on a `#f5f5f5` dot with a `#d4d4d4` border; no hover. A single option can be disabled too.
75
+ - **Error:** `#dc3545`, 13px, under the options; the dots get a red border. The built-in error shows after the first
76
+ interaction (a change, or focus leaving the group), an error passed by the parent shows at once.
77
+ - **Focus:** keyboard focus (`:focus-visible`) thickens the dot's border from 1px to 2px, black, with no separate ring (so a
78
+ checked radio never reads as a double circle); the arrow keys move the selection.
79
+
80
+ ## Textarea
81
+ From [components-textarea](components/components-textarea), which is the input with `multiline`: it uses exactly the
82
+ input's look (notched uppercase label, 1px `#737373` border that turns black on hover and focus, 1px black focus ring,
83
+ `#dc3545` error). Only the control differs:
84
+ - **Height:** at least 6rem (about three lines of 16px text) and resizable vertically only, so it never breaks the grid;
85
+ `rows` sets the initial height.
86
+ - **Disabled and error:** same as the input (`#a3a3a3` on `#f5f5f5`; red border and 13px message).
87
+
88
+ ## Slider
89
+ From [components-slider](components/components-slider), a native range input; the row is at least 44px tall. The label
90
+ uses the field-label style (11px, bold, uppercase, tracked, `#737373`); the optional live value, on the same line at
91
+ the right, is body text (1rem, `#171717`).
92
+ - **Track:** a 2px `#737373` line, square; the part before the thumb is black.
93
+ - **Thumb:** 20px black square with a 1px white border (so it stays distinct where it crosses the track); `#262626` on
94
+ hover, `#404040` while dragging.
95
+ - **Disabled:** `#a3a3a3` label, thumb and fill on a `#d4d4d4` track; no hover.
96
+ - **Focus:** keyboard focus (`:focus-visible`) draws a 1px black ring offset by 2px around the thumb.
97
+
98
+ ## Popover
99
+ From [components-popover](components/components-popover), the floating panel behind the select, combobox and date picker:
100
+ white, a 1px `#737373` border, square corners and no shadow (flat, like the rest of the theme), 4px below its anchor.
101
+ It fades in over 200ms and opens above the anchor when there is no room below. It has no padding of its own: the
102
+ content (a list, a calendar) brings its spacing.
103
+
104
+ ## Listbox
105
+ From [components-listbox](components/components-listbox), the option list used inside the popover. Each option is at
106
+ least 44px tall, body text (1rem, `#171717`) with 0.75rem of horizontal padding.
107
+ - **Active** (hover or keyboard cursor): `#f5f5f5` surface.
108
+ - **Selected:** bold text with a 2px black bar on the inline-start edge.
109
+ - **Disabled:** `#a3a3a3`, no hover.
110
+ - **Empty:** a `#737373` message with 0.75rem of padding.
111
+ - **Height:** at most 15rem; longer lists scroll.
112
+
113
+ ## Select
114
+ From [components-select](components/components-select): a custom list, so it looks the same in every browser. The closed
115
+ field is the Input (notched uppercase label, 1px `#737373` border, black on hover and focus, 44px tall); the value reads
116
+ as body text, and the placeholder is `#737373` like the input placeholder. A 16px `#737373` chevron sits on the right
117
+ and turns black; when the list is open it rotates 180 degrees over 200ms and the border stays black. The open panel is
118
+ the Popover and the options are the Listbox, as wide as the field. Errors, required marker and disabled look are the
119
+ Input's.
120
+
121
+ ## Combobox
122
+ From [components-combobox](components/components-combobox): the Select field with a text input in place of the button, so
123
+ the user can type to filter the list. Same Input look (notched uppercase label, 1px `#737373` border, black on hover and
124
+ focus, 44px tall), same 16px `#737373` chevron that turns black and rotates 180 degrees when the list is open. The text
125
+ is body text (`#171717`) and the placeholder `#737373`. A press anywhere in the box focuses the input (the chevron is
126
+ decorative, not a button); the list opens when typing or with the arrow keys. The panel is the Popover and the options
127
+ the Listbox, as wide as the field; a message such as "No results" uses the Listbox empty style. Errors, required marker
128
+ and disabled look are the Input's.
129
+
130
+ ## Upload
131
+ From [components-upload](components/components-upload): the Input field turned into a dropzone. The box keeps the
132
+ notched uppercase label and the 1px `#737373` border but dashed, black on hover; while files are dragged over it the
133
+ border is black and the background `#f5f5f5`. The zone is at least 5.5rem tall and centers its content as muted (`#737373`)
134
+ body text, and the whole box is the click target. Chosen files are listed below the zone as 44px rows split by a 1px
135
+ `#e5e5e5` line: the name in body text with an ellipsis, and a 44px square remove button (a multiplication sign, `#737373`,
136
+ black on hover, 1px black focus ring). The focus ring of the box is the Input's. Errors, required marker and disabled look
137
+ (`#a3a3a3` on `#f5f5f5`) are the Input's.
138
+
139
+ ## Calendar
140
+ From [components-calendar](components/components-calendar): a standalone month grid (the date picker shows it inside the
141
+ Popover, which draws the only border). It has no outer border. The header is two 44px navigation buttons (muted
142
+ chevrons that turn black, 1px black focus ring drawn inside) around the month and year in the label style (11px, bold,
143
+ uppercase, `0.1em` tracking, `#737373`); the weekday row uses the same style. Days are 44px squares in body text
144
+ (`#171717`) with square corners and a `#f5f5f5` hover. The selected day is a black square with white text; today is a
145
+ 1px black border, drawn inside the square so nothing shifts. Days outside `min..max` are `#a3a3a3` with no hover, and
146
+ the days of the neighbor months are left empty. The keyboard focus ring is 1px black, inset. The grid always shows six
147
+ weeks so the height never changes between months.
148
+
149
+ ## Date picker
150
+ From [components-date-picker](components/components-date-picker): the Select field with a calendar in the panel. The closed
151
+ field is the Input (notched uppercase label, 1px `#737373` border, black on hover and focus, 44px tall); the chosen date
152
+ reads as body text (for example "Oct 14, 2026") and the placeholder is `#737373`. A 16px `#737373` calendar icon sits on the
153
+ right and turns black on hover and while open; it does not rotate, and the border stays black while open. The open panel
154
+ is the Popover (1px `#737373` border, no shadow) with 0.5rem of padding around the Calendar, as wide as the calendar
155
+ needs, not as the field. Errors, required marker and disabled look are the Input's.
156
+
157
+ ## Search
158
+ From [components-search](components/components-search): the Input of type search with two inline parts built on the input's
159
+ `start` and `end` slots. The field is the Input's (notched uppercase label, 1px `#737373` border, black on hover and focus,
160
+ 44px tall; the keyboard focus rule below applies). A 20px `#737373` magnifier icon sits on the left and turns black while the
161
+ field has the focus. The clear button appears on the right only while there is text: a 16px `#737373` cross in the Input's
162
+ 44px side-button box that turns black on hover; the browser's own clear button is hidden so the look is the same everywhere.
163
+ Errors, required marker and disabled look are the Input's. The Input and Textarea accept `start` and `end` content (a prefix
164
+ icon, a unit) in the same muted color (`#737373`) with `0.5rem` between the content and the text.
165
+
166
+ ## Keyboard focus (all controls)
167
+ One rule keeps the controls coherent: **an outlined control thickens its own border from 1px to 2px, black** (text fields,
168
+ select, combobox, date picker, textarea, upload, empty checkbox, off switch, radio, secondary and ghost buttons); **a filled
169
+ (black) control draws a separate 1px black ring offset by 2px**, because a thicker border would be invisible on a black fill
170
+ (primary button, checked checkbox, on switch, slider thumb). Calendar days and the upload remove button use an inset 1px ring.
171
+
172
+ ## Guidelines
173
+ - **Accessibility:** 4.5:1 contrast for body text; interactive elements are at least 44px tall.
174
+ - **Motion:** subtle, 200-300ms. Hover gives immediate feedback (border or color shift).
package/README.md CHANGED
@@ -1,3 +1,46 @@
1
- # Temporary Holding Version
1
+ # @carissa-io/theme-default
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The Carissa Default theme: **Swiss minimalism** (square corners, absolute black for primary actions and focus, a neutral
4
+ grey scale, a neutral grotesque type stack). The Carissa components ship neutral defaults and no look of their own; this
5
+ package gives them one by overriding their SCSS variables. The decisions behind the values are in [DESIGN.md](DESIGN.md).
6
+
7
+ ## Install
8
+ ```bash
9
+ npm install @carissa-io/theme-default
10
+ ```
11
+ The compiled CSS needs nothing else. To compile the SCSS yourself, also install the components you use (they are optional
12
+ peer dependencies).
13
+
14
+ ## Use it
15
+ 1. **Compiled CSS** (nothing to compile; the components must still be installed to render):
16
+ ```js
17
+ import '@carissa-io/theme-default/css'
18
+ ```
19
+ It is also the package's main export, so `import '@carissa-io/theme-default'` works with a bundler that handles CSS.
20
+ 2. **SCSS source:** forward or `@use` it from your own Sass entry, with `@carissa-io/*` resolvable (`node_modules` on the
21
+ load path):
22
+ ```scss
23
+ @use '@carissa-io/theme-default/scss';
24
+ ```
25
+ 3. **A starting point for a new theme:** copy `scss/index.scss` and change the values. In the Carissa workspace,
26
+ `scripts/new-theme.sh <name> "<description>"` does this and sets up the repo.
27
+
28
+ ## What it configures
29
+ `components-input`, `-button`, `-checkbox`, `-switch`, `-radio-group`, `-slider`, `-popover`, `-listbox`, `-select`,
30
+ `-combobox`, `-upload`, `-calendar`, `-date-picker` and `-search`. `components-email`, `-password`, `-url` and `-textarea`
31
+ are styled through the input.
32
+
33
+ ## Change a value
34
+ The palette and the values shared by every component (radius, minimum height, focus ring, transition, label style, dropdown
35
+ arrow) are Sass variables at the top of `scss/index.scss`; each component has one `@use ... with (...)` block of overrides
36
+ below. Change the value, run `npm run build`, and update [DESIGN.md](DESIGN.md) if the decision changes.
37
+
38
+ ## Develop
39
+ ```bash
40
+ npm install
41
+ npm run lint # compile, fail on any Sass error or warning
42
+ npm test # builds, then checks every component root has rules and dist/ is current
43
+ npm run build # dist/index.css
44
+ ```
45
+ `dist/` is not committed; it is built before every publish. The package ships `dist`, `scss` and `DESIGN.md`. Releases
46
+ follow the Carissa project rules: branch and pull request, CI publishes when the version on `main` is new.