@the-portland-company/shell 0.38.0 → 0.39.1

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/dist/index.cjs CHANGED
@@ -72,109 +72,115 @@ var colors = {
72
72
  700: "#2d3748",
73
73
  800: "#1a202c",
74
74
  900: "#171923"
75
+ },
76
+ // The neutral-black dark ramp from Reference/Global-Rules → Dark Mode. Every
77
+ // value is hue-free (R = G = B); layering is expressed by lightness only.
78
+ //
79
+ // The `gray` ramp above is Chakra's, which is BLUE-TINTED (#2d3748, #1a202c,
80
+ // #171923). Every dark value in the theme used to point into it, so dark mode
81
+ // rendered navy against the black chrome — the single most common way dark
82
+ // mode drifts off-brand, and explicitly called out in the spec. Dark values
83
+ // resolve here instead.
84
+ neutral: {
85
+ page: "#0A0A0A",
86
+ surface: "#161616",
87
+ raised: "#1F1F1F",
88
+ raised2: "#212121",
89
+ hover: "#2B2B2B",
90
+ border: "#333333",
91
+ borderStrong: "#404040",
92
+ textMuted: "#A3A3A3",
93
+ textDim: "#8A8A8A",
94
+ text: "#E8E8E8",
95
+ textStrong: "#F5F5F5"
75
96
  }
76
97
  };
77
98
  var semanticTokens = {
78
99
  colors: {
100
+ // Every _dark value resolves to the NEUTRAL ramp (colors.neutral), never to
101
+ // Chakra's blue-tinted `gray` scale. See the note on `neutral` above.
79
102
  // Text colors
80
- "text.primary": {
81
- default: "gray.900",
82
- _dark: "gray.50"
83
- },
84
- "text.secondary": {
85
- default: "gray.600",
86
- _dark: "gray.400"
87
- },
88
- "text.muted": {
89
- default: "gray.500",
90
- _dark: "gray.500"
91
- },
103
+ "text.primary": { default: "gray.900", _dark: "neutral.text" },
104
+ "text.secondary": { default: "gray.600", _dark: "neutral.textMuted" },
105
+ "text.muted": { default: "gray.500", _dark: "neutral.textDim" },
92
106
  // Background colors
93
- "bg.primary": {
94
- default: "white",
95
- _dark: "gray.800"
96
- },
97
- "bg.secondary": {
98
- default: "gray.50",
99
- _dark: "gray.900"
100
- },
101
- "bg.surface": {
102
- default: "white",
103
- _dark: "gray.700"
104
- },
105
- "bg.hover": {
106
- default: "gray.50",
107
- _dark: "gray.600"
108
- },
107
+ "bg.primary": { default: "white", _dark: "neutral.surface" },
108
+ "bg.secondary": { default: "gray.50", _dark: "neutral.page" },
109
+ "bg.surface": { default: "white", _dark: "neutral.raised" },
110
+ "bg.hover": { default: "gray.50", _dark: "neutral.hover" },
109
111
  // Border colors
110
- "border.default": {
111
- default: "gray.200",
112
- _dark: "gray.600"
113
- },
114
- "border.muted": {
115
- default: "gray.100",
116
- _dark: "gray.700"
117
- },
112
+ "border.default": { default: "gray.200", _dark: "neutral.border" },
113
+ "border.muted": { default: "gray.100", _dark: "neutral.border" },
118
114
  // Component specific
119
- "card.bg": {
120
- default: "white",
121
- _dark: "gray.700"
122
- },
123
- "card.border": {
124
- default: "gray.200",
125
- _dark: "gray.600"
126
- },
127
- "input.bg": {
128
- default: "white",
129
- _dark: "gray.700"
130
- },
131
- "input.border": {
132
- default: "gray.200",
133
- _dark: "gray.600"
134
- },
135
- "input.hover": {
136
- default: "gray.400",
137
- _dark: "gray.500"
138
- },
115
+ "heading.fg": { default: "politogy.navy.800", _dark: "neutral.textStrong" },
116
+ "card.bg": { default: "white", _dark: "neutral.surface" },
117
+ "card.border": { default: "gray.200", _dark: "neutral.border" },
118
+ "input.bg": { default: "white", _dark: "neutral.raised" },
119
+ "input.border": { default: "gray.200", _dark: "neutral.border" },
120
+ "input.hover": { default: "gray.400", _dark: "neutral.borderStrong" },
139
121
  // Navigation
140
- "nav.bg": {
141
- default: "white",
142
- _dark: "gray.800"
143
- },
144
- "nav.border": {
145
- default: "gray.200",
146
- _dark: "gray.700"
147
- },
122
+ "nav.bg": { default: "white", _dark: "neutral.surface" },
123
+ "nav.border": { default: "gray.200", _dark: "neutral.border" },
148
124
  // Sidebar
149
- "sidebar.bg": {
150
- default: "gray.50",
151
- _dark: "gray.900"
152
- },
153
- "sidebar.hover": {
154
- default: "gray.100",
155
- _dark: "gray.800"
156
- },
157
- "sidebar.active": {
158
- default: "brand.50",
159
- _dark: "brand.900"
160
- },
161
- // Status colors
162
- "success.bg": {
163
- default: "green.50",
164
- _dark: "green.900"
165
- },
166
- "error.bg": {
167
- default: "red.50",
168
- _dark: "red.900"
169
- },
170
- "warning.bg": {
171
- default: "yellow.50",
172
- _dark: "yellow.900"
173
- },
174
- "info.bg": {
175
- default: "blue.50",
176
- _dark: "blue.900"
177
- }
125
+ "sidebar.bg": { default: "gray.50", _dark: "neutral.surface" },
126
+ "sidebar.hover": { default: "gray.100", _dark: "neutral.hover" },
127
+ "sidebar.active": { default: "brand.50", _dark: "brand.900" },
128
+ // Status surfaces. In dark mode these become neutral raised surfaces — the
129
+ // meaning is carried by the icon/text accent, not by a pale tint that would
130
+ // glare against black (and would break the hue-free surface rule).
131
+ "success.bg": { default: "green.50", _dark: "neutral.raised" },
132
+ "error.bg": { default: "red.50", _dark: "neutral.raised" },
133
+ "warning.bg": { default: "yellow.50", _dark: "neutral.raised" },
134
+ "info.bg": { default: "blue.50", _dark: "neutral.raised" },
135
+ // ---------------------------------------------------------------------
136
+ // Raw palette remap — the high-leverage half of the dark-mode fix.
137
+ //
138
+ // The app carries ~650 hardcoded Chakra literals (`bg="gray.50"`,
139
+ // `borderColor="gray.200"`, `color="gray.600"`, ...) that no semantic token
140
+ // can reach. Making the SCALE ITSELF color-mode-aware fixes them all at
141
+ // once, centrally, with no app edits.
142
+ //
143
+ // The mapping INVERTS: in dark mode a low number (used as a pale surface)
144
+ // becomes a dark surface, and a high number (used as dark text) becomes
145
+ // light text. That is what makes one remap correct for both background and
146
+ // foreground usage.
147
+ "gray.50": { default: "#f7fafc", _dark: "neutral.raised" },
148
+ "gray.100": { default: "#edf2f7", _dark: "neutral.raised2" },
149
+ "gray.200": { default: "#e2e8f0", _dark: "neutral.border" },
150
+ "gray.300": { default: "#cbd5e0", _dark: "neutral.borderStrong" },
151
+ "gray.400": { default: "#a0aec0", _dark: "#6B6B6B" },
152
+ "gray.500": { default: "#718096", _dark: "neutral.textDim" },
153
+ "gray.600": { default: "#4a5568", _dark: "neutral.textMuted" },
154
+ "gray.700": { default: "#2d3748", _dark: "#C6C6C6" },
155
+ "gray.800": { default: "#1a202c", _dark: "neutral.text" },
156
+ "gray.900": { default: "#171923", _dark: "neutral.textStrong" },
157
+ // Pale status tints used directly as card/callout surfaces. Same reasoning
158
+ // as the *.bg tokens above.
159
+ "blue.50": { default: "#ebf8ff", _dark: "neutral.raised" },
160
+ "green.50": { default: "#f0fff4", _dark: "neutral.raised" },
161
+ "red.50": { default: "#fff5f5", _dark: "neutral.raised" },
162
+ "yellow.50": { default: "#fffff0", _dark: "neutral.raised" },
163
+ "orange.50": { default: "#fffaf0", _dark: "neutral.raised" },
164
+ // Dark status TEXT. The deep shades are picked for contrast against a pale
165
+ // tint; against a #1F1F1F surface they are unreadable — measured on the live
166
+ // info alert, whose description rendered #2c5282 (blue.700) on near-black.
167
+ // In dark mode they lighten to the 200/300 band so the hue still reads as
168
+ // informational/success/error without losing legibility.
169
+ "blue.600": { default: "#2b6cb0", _dark: "#7CC0F5" },
170
+ "blue.700": { default: "#2c5282", _dark: "#9AD1F8" },
171
+ "blue.800": { default: "#2a4365", _dark: "#BFE3FB" },
172
+ "green.600": { default: "#38a169", _dark: "#68D391" },
173
+ "green.700": { default: "#2f855a", _dark: "#8EE0AE" },
174
+ "green.800": { default: "#276749", _dark: "#B6ECCB" },
175
+ "red.600": { default: "#e53e3e", _dark: "#FC8181" },
176
+ "red.700": { default: "#c53030", _dark: "#FEA8A8" },
177
+ "red.800": { default: "#9b2c2c", _dark: "#FECACA" },
178
+ "orange.600": { default: "#dd6b20", _dark: "#F6AD55" },
179
+ "orange.700": { default: "#c05621", _dark: "#FBC98A" },
180
+ "orange.800": { default: "#9c4221", _dark: "#FDDCB4" },
181
+ "yellow.600": { default: "#d69e2e", _dark: "#ECC94B" },
182
+ "yellow.700": { default: "#b7791f", _dark: "#F3DC85" },
183
+ "yellow.800": { default: "#975a16", _dark: "#F8EAB4" }
178
184
  }
179
185
  };
180
186
 
@@ -204,7 +210,10 @@ var components = {
204
210
  secondary: {
205
211
  borderWidth: "1px",
206
212
  borderColor: "gray.300",
207
- bg: "white",
213
+ // `card.bg`, not a raw `white` — a literal white here rendered a light
214
+ // pill on the black page in dark mode. (`gray.*` is color-mode-aware via
215
+ // the semanticTokens remap, so those are already safe.)
216
+ bg: "card.bg",
208
217
  color: "gray.700",
209
218
  _hover: {
210
219
  bg: "gray.50"
@@ -271,7 +280,10 @@ var components = {
271
280
  },
272
281
  Heading: {
273
282
  baseStyle: {
274
- color: "politogy.navy.800",
283
+ // Was a hard `politogy.navy.800` (#1a2e47) — near-invisible against the
284
+ // black page in dark mode, and off-brand navy besides. Every heading in
285
+ // every app went through this one style.
286
+ color: "heading.fg",
275
287
  fontWeight: "semibold"
276
288
  }
277
289
  },
@@ -655,7 +667,7 @@ var components = {
655
667
  borderBottom: "none",
656
668
  borderColor: "transparent",
657
669
  _odd: {
658
- bg: "white"
670
+ bg: "card.bg"
659
671
  },
660
672
  _even: {
661
673
  bg: "gray.50"
@@ -667,7 +679,7 @@ var components = {
667
679
  tbody: {
668
680
  tr: {
669
681
  _odd: {
670
- bg: "white"
682
+ bg: "card.bg"
671
683
  },
672
684
  _even: {
673
685
  bg: "gray.50"