@scalewing/react 0.1.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @scalewing/react
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f35314a: Add Box `as="a"` for layout links and Field (label wrapping a native control, token gap) after fantasy-football. Press actions stay on Button; do not use Box as a button.
8
+ - f35314a: Add Button (primary, secondary, ghost, danger; sm and md) for DOM and React Native after FutMas and coach-platform requested the same control. Includes onAccent/onDanger, 44px md hit target, focus ring, and disabled opacity tokens.
9
+ - f35314a: Shift the default visual language to a quiet glass canvas: Apple-like neutrals and type, frosted Card, pill buttons, and generated document styles so links and native text controls are not user-agent chrome.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [f35314a]
14
+ - Updated dependencies [f35314a]
15
+ - @scalewing/tokens@0.2.0
16
+
3
17
  ## 0.1.0
4
18
 
5
19
  ### Minor Changes
package/README.md CHANGED
@@ -4,7 +4,15 @@ DOM components plus the generated Scalewing stylesheet.
4
4
 
5
5
  ```ts
6
6
  import '@scalewing/react/styles.css';
7
- import { Card, Stack, Text, ThemeProvider } from '@scalewing/react';
7
+ import {
8
+ Box,
9
+ Button,
10
+ Card,
11
+ Field,
12
+ Stack,
13
+ Text,
14
+ ThemeProvider,
15
+ } from '@scalewing/react';
8
16
  ```
9
17
 
10
18
  ```html
@@ -13,4 +21,6 @@ import { Card, Stack, Text, ThemeProvider } from '@scalewing/react';
13
21
 
14
22
  Import the CSS once at the application entry. Do not copy it into your source tree.
15
23
 
24
+ `Box as="a"` is a layout link. Use `Button` for press actions. `Field` wraps a native `<input>` or `<select>` with a label and token gap; native text controls inherit the generated document canvas.
25
+
16
26
  React is a peer dependency. Rationale: the host app already owns the React runtime.
@@ -1,14 +1,14 @@
1
1
  import { type RadiusStep, type SemanticColorKey } from '@scalewing/tokens';
2
- import { type HTMLAttributes } from 'react';
2
+ import { type AnchorHTMLAttributes, type HTMLAttributes } from 'react';
3
3
  import { type SpacingProps } from '../spacing-classes.js';
4
- export type BoxElement = 'div' | 'section' | 'article' | 'header' | 'footer' | 'main' | 'nav' | 'aside' | 'span';
5
- export type BoxProps = SpacingProps & HTMLAttributes<HTMLElement> & {
4
+ export type BoxElement = 'div' | 'section' | 'article' | 'header' | 'footer' | 'main' | 'nav' | 'aside' | 'span' | 'a' | 'label';
5
+ export type BoxProps = SpacingProps & HTMLAttributes<HTMLElement> & Pick<AnchorHTMLAttributes<HTMLAnchorElement>, 'download' | 'href' | 'rel' | 'target'> & {
6
6
  as?: BoxElement;
7
7
  background?: Extract<SemanticColorKey, 'background' | 'surface'>;
8
8
  radius?: RadiusStep;
9
9
  border?: boolean;
10
10
  };
11
- export declare const Box: import("react").ForwardRefExoticComponent<SpacingProps & HTMLAttributes<HTMLElement> & {
11
+ export declare const Box: import("react").ForwardRefExoticComponent<SpacingProps & HTMLAttributes<HTMLElement> & Pick<AnchorHTMLAttributes<HTMLAnchorElement>, "rel" | "download" | "href" | "target"> & {
12
12
  as?: BoxElement;
13
13
  background?: Extract<SemanticColorKey, "background" | "surface">;
14
14
  radius?: RadiusStep;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { forwardRef } from 'react';
2
+ import { forwardRef, } from 'react';
3
3
  import { cx } from '../class-names.js';
4
4
  import { spacingClassNames } from '../spacing-classes.js';
5
5
  export const Box = forwardRef(function Box({ as = 'div', background, border, className, padding, paddingBottom, paddingLeft, paddingRight, paddingTop, paddingX, paddingY, radius, style, ...rest }, ref) {
@@ -0,0 +1,17 @@
1
+ import { type ButtonSize, type ButtonVariant } from '@scalewing/tokens';
2
+ import { type ButtonHTMLAttributes, type ReactNode } from 'react';
3
+ export type { ButtonSize, ButtonVariant };
4
+ export type ButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'type'> & {
5
+ children: ReactNode;
6
+ onPress: () => void;
7
+ size?: ButtonSize;
8
+ type?: 'button' | 'submit' | 'reset';
9
+ variant?: ButtonVariant;
10
+ };
11
+ export declare const Button: import("react").ForwardRefExoticComponent<Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onClick" | "type"> & {
12
+ children: ReactNode;
13
+ onPress: () => void;
14
+ size?: ButtonSize;
15
+ type?: "button" | "submit" | "reset";
16
+ variant?: ButtonVariant;
17
+ } & import("react").RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { buttonClassNames, } from '@scalewing/tokens';
3
+ import { forwardRef } from 'react';
4
+ import { cx } from '../class-names.js';
5
+ export const Button = forwardRef(function Button({ children, className, disabled = false, onPress, size = 'md', type = 'button', variant = 'primary', ...rest }, ref) {
6
+ return (_jsx("button", { ref: ref, className: cx(...buttonClassNames({ size, variant }), className), disabled: disabled, type: type, ...rest, onClick: onPress, children: children }));
7
+ });
@@ -1,6 +1,6 @@
1
- import { type SpacingStep } from '@scalewing/tokens';
1
+ import { type SpacingStep, type CardVariant } from '@scalewing/tokens';
2
2
  import { type BoxProps } from './Box.js';
3
- export type CardVariant = 'outlined' | 'elevated';
3
+ export type { CardVariant };
4
4
  export type CardProps = Omit<BoxProps, 'as'> & {
5
5
  padding?: SpacingStep;
6
6
  variant?: CardVariant;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cx } from '../class-names.js';
3
3
  import { Box } from './Box.js';
4
- export function Card({ className, padding = 4, variant = 'outlined', ...rest }) {
5
- return (_jsx(Box, { as: "section", className: cx('sw-card', variant === 'elevated' && 'sw-card-elevated', className), padding: padding, ...rest }));
4
+ export function Card({ className, padding = 4, variant = 'glass', ...rest }) {
5
+ return (_jsx(Box, { as: "section", className: cx('sw-card', `sw-card-${variant}`, className), padding: padding, ...rest }));
6
6
  }
@@ -0,0 +1,8 @@
1
+ import { type SpacingStep } from '@scalewing/tokens';
2
+ import { type ReactNode } from 'react';
3
+ export type FieldProps = {
4
+ children: ReactNode;
5
+ gap?: SpacingStep;
6
+ label: string;
7
+ };
8
+ export declare function Field({ children, gap, label }: FieldProps): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Stack } from './Stack.js';
3
+ import { Text } from './Text.js';
4
+ export function Field({ children, gap = 1, label }) {
5
+ return (_jsxs(Stack, { as: "label", gap: gap, children: [_jsx(Text, { as: "span", variant: "label", children: label }), children] }));
6
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, } from './components/Button.js';
1
2
  export { Box, type BoxElement, type BoxProps } from './components/Box.js';
2
3
  export { Card, type CardProps, type CardVariant } from './components/Card.js';
4
+ export { Field, type FieldProps } from './components/Field.js';
3
5
  export { Inline, type InlineProps } from './components/Inline.js';
4
6
  export { Stack, type Align, type Justify, type StackProps, } from './components/Stack.js';
5
7
  export { Text, type TextElement, type TextProps } from './components/Text.js';
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
+ export { Button, } from './components/Button.js';
1
2
  export { Box } from './components/Box.js';
2
3
  export { Card } from './components/Card.js';
4
+ export { Field } from './components/Field.js';
3
5
  export { Inline } from './components/Inline.js';
4
6
  export { Stack, } from './components/Stack.js';
5
7
  export { Text } from './components/Text.js';
package/dist/styles.css CHANGED
@@ -1,14 +1,16 @@
1
1
  /* Generated by @scalewing/tokens. Do not edit by hand. */
2
2
  :root,
3
3
  [data-theme='light'] {
4
- --sw-color-background: #F4F6F8;
4
+ --sw-color-background: #F5F5F7;
5
5
  --sw-color-surface: #FFFFFF;
6
- --sw-color-text: #121417;
7
- --sw-color-muted: #3F4A55;
6
+ --sw-color-text: #1D1D1F;
7
+ --sw-color-muted: #6E6E73;
8
8
  --sw-color-accent: #0B615E;
9
+ --sw-color-onAccent: #FFFFFF;
9
10
  --sw-color-danger: #B42318;
11
+ --sw-color-onDanger: #FFFFFF;
10
12
  --sw-color-success: #087443;
11
- --sw-color-border: #D6DCE3;
13
+ --sw-color-border: #D2D2D7;
12
14
  --sw-space-0: 0px;
13
15
  --sw-space-1: 4px;
14
16
  --sw-space-2: 8px;
@@ -22,21 +24,34 @@
22
24
  --sw-radius-md: 16px;
23
25
  --sw-radius-lg: 24px;
24
26
  --sw-radius-pill: 999px;
27
+ --sw-control-sm-min-height: 32px;
28
+ --sw-control-sm-padding-inline: 12px;
29
+ --sw-control-md-min-height: 44px;
30
+ --sw-control-md-padding-inline: 16px;
25
31
  --sw-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
26
- --sw-elevation-sm: 0 1px 2px rgba(16, 18, 20, 0.06), 0 8px 24px rgba(16, 18, 20, 0.08);
27
- --sw-elevation-md: 0 12px 40px rgba(16, 18, 20, 0.12);
32
+ --sw-elevation-sm: 0 1px 2px rgba(0, 0, 0, 0.04), 0 12px 32px rgba(0, 0, 0, 0.06);
33
+ --sw-elevation-md: 0 16px 48px rgba(0, 0, 0, 0.1);
34
+ --sw-disabled-opacity: 0.4;
35
+ --sw-focus-ring-width: 2px;
36
+ --sw-focus-ring-offset: 2px;
28
37
  --sw-container-max: 72rem;
38
+ --sw-glass-blur: 24px;
39
+ --sw-glass-saturate: 1.8;
40
+ --sw-glass-fill: rgba(255, 255, 255, 0.78);
41
+ --sw-glass-border: rgba(255, 255, 255, 0.62);
29
42
  }
30
43
 
31
44
  [data-theme='dark'] {
32
- --sw-color-background: #101214;
33
- --sw-color-surface: #1A1E22;
34
- --sw-color-text: #F5F7F8;
35
- --sw-color-muted: #C5CDD4;
45
+ --sw-color-background: #000000;
46
+ --sw-color-surface: #1C1C1E;
47
+ --sw-color-text: #F5F5F7;
48
+ --sw-color-muted: #A1A1A6;
36
49
  --sw-color-accent: #7EDAD6;
50
+ --sw-color-onAccent: #101214;
37
51
  --sw-color-danger: #F97066;
52
+ --sw-color-onDanger: #101214;
38
53
  --sw-color-success: #5BE0A0;
39
- --sw-color-border: #2C333A;
54
+ --sw-color-border: #3A3A3C;
40
55
  --sw-space-0: 0px;
41
56
  --sw-space-1: 4px;
42
57
  --sw-space-2: 8px;
@@ -50,10 +65,73 @@
50
65
  --sw-radius-md: 16px;
51
66
  --sw-radius-lg: 24px;
52
67
  --sw-radius-pill: 999px;
68
+ --sw-control-sm-min-height: 32px;
69
+ --sw-control-sm-padding-inline: 12px;
70
+ --sw-control-md-min-height: 44px;
71
+ --sw-control-md-padding-inline: 16px;
53
72
  --sw-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
54
- --sw-elevation-sm: 0 1px 2px rgba(16, 18, 20, 0.06), 0 8px 24px rgba(16, 18, 20, 0.08);
55
- --sw-elevation-md: 0 12px 40px rgba(16, 18, 20, 0.12);
73
+ --sw-elevation-sm: 0 1px 2px rgba(0, 0, 0, 0.04), 0 12px 32px rgba(0, 0, 0, 0.06);
74
+ --sw-elevation-md: 0 16px 48px rgba(0, 0, 0, 0.1);
75
+ --sw-disabled-opacity: 0.4;
76
+ --sw-focus-ring-width: 2px;
77
+ --sw-focus-ring-offset: 2px;
56
78
  --sw-container-max: 72rem;
79
+ --sw-glass-blur: 24px;
80
+ --sw-glass-saturate: 1.8;
81
+ --sw-glass-fill: rgba(28, 28, 30, 0.72);
82
+ --sw-glass-border: rgba(255, 255, 255, 0.16);
83
+ }
84
+
85
+ html,
86
+ body {
87
+ margin: 0;
88
+ }
89
+
90
+ [data-theme] {
91
+ background-color: var(--sw-color-background);
92
+ color: var(--sw-color-text);
93
+ font-family: var(--sw-font-sans);
94
+ font-size: 17px;
95
+ letter-spacing: -0.2px;
96
+ line-height: 25px;
97
+ min-height: 100vh;
98
+ min-height: 100dvh;
99
+ -webkit-font-smoothing: antialiased;
100
+ -moz-osx-font-smoothing: grayscale;
101
+ }
102
+
103
+ [data-theme='light'] {
104
+ color-scheme: light;
105
+ }
106
+
107
+ [data-theme='dark'] {
108
+ color-scheme: dark;
109
+ }
110
+
111
+ [data-theme] a {
112
+ color: var(--sw-color-accent);
113
+ text-decoration: none;
114
+ }
115
+
116
+ [data-theme] a:hover {
117
+ color: var(--sw-color-text);
118
+ }
119
+
120
+ [data-theme] a:focus-visible {
121
+ outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
122
+ outline-offset: var(--sw-focus-ring-offset);
123
+ }
124
+
125
+ [data-theme] :is(input[type='text'], input[type='email'], input[type='number'], input[type='search'], input[type='url'], input[type='password'], input:not([type]), select, textarea) {
126
+ background-color: var(--sw-glass-fill);
127
+ border: 1px solid var(--sw-color-border);
128
+ border-radius: var(--sw-radius-sm);
129
+ box-sizing: border-box;
130
+ color: inherit;
131
+ font-family: inherit;
132
+ font-size: inherit;
133
+ min-height: var(--sw-control-md-min-height);
134
+ padding-inline: var(--sw-control-md-padding-inline);
57
135
  }
58
136
 
59
137
  .sw-padding-0 { padding: var(--sw-space-0); }
@@ -153,26 +231,81 @@
153
231
  .sw-justify-between { justify-content: space-between; }
154
232
 
155
233
  .sw-card {
234
+ border-radius: var(--sw-radius-lg);
235
+ color: var(--sw-color-text);
236
+ }
237
+
238
+ .sw-card-glass {
239
+ background: var(--sw-glass-fill);
240
+ border: 1px solid var(--sw-glass-border);
241
+ backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
242
+ -webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
243
+ }
244
+
245
+ .sw-card-outlined {
156
246
  background: var(--sw-color-surface);
157
247
  border: 1px solid var(--sw-color-border);
158
- border-radius: var(--sw-radius-md);
159
- color: var(--sw-color-text);
160
248
  }
161
249
 
162
250
  .sw-card-elevated {
251
+ background: var(--sw-color-surface);
163
252
  border-color: transparent;
164
253
  box-shadow: var(--sw-elevation-sm);
165
254
  }
166
255
 
256
+ @media (prefers-reduced-transparency: reduce) {
257
+ .sw-card-glass,
258
+ .sw-button-secondary {
259
+ background: var(--sw-color-surface);
260
+ backdrop-filter: none;
261
+ -webkit-backdrop-filter: none;
262
+ }
263
+ }
264
+
167
265
  .sw-truncate {
168
266
  overflow: hidden;
169
267
  text-overflow: ellipsis;
170
268
  white-space: nowrap;
171
269
  }
172
270
 
173
- .sw-text-display { font-family: var(--sw-font-sans); font-size: 34px; line-height: 40px; font-weight: 800; letter-spacing: -0.8px; }
174
- .sw-text-heading { font-family: var(--sw-font-sans); font-size: 24px; line-height: 32px; font-weight: 700; letter-spacing: -0.4px; }
175
- .sw-text-title { font-family: var(--sw-font-sans); font-size: 18px; line-height: 26px; font-weight: 700; letter-spacing: -0.2px; }
176
- .sw-text-body { font-family: var(--sw-font-sans); font-size: 16px; line-height: 24px; font-weight: 400; letter-spacing: 0px; }
177
- .sw-text-label { font-family: var(--sw-font-sans); font-size: 14px; line-height: 20px; font-weight: 600; letter-spacing: 0.2px; }
178
- .sw-text-caption { font-family: var(--sw-font-sans); font-size: 12px; line-height: 16px; font-weight: 500; letter-spacing: 0.2px; }
271
+ .sw-text-display { font-family: var(--sw-font-sans); font-size: 40px; line-height: 48px; font-weight: 600; letter-spacing: -0.8px; }
272
+ .sw-text-heading { font-family: var(--sw-font-sans); font-size: 28px; line-height: 34px; font-weight: 600; letter-spacing: -0.45px; }
273
+ .sw-text-title { font-family: var(--sw-font-sans); font-size: 20px; line-height: 28px; font-weight: 600; letter-spacing: -0.3px; }
274
+ .sw-text-body { font-family: var(--sw-font-sans); font-size: 17px; line-height: 25px; font-weight: 400; letter-spacing: -0.2px; }
275
+ .sw-text-label { font-family: var(--sw-font-sans); font-size: 15px; line-height: 20px; font-weight: 600; letter-spacing: -0.2px; }
276
+ .sw-text-caption { font-family: var(--sw-font-sans); font-size: 13px; line-height: 18px; font-weight: 400; letter-spacing: -0.08px; }
277
+
278
+ .sw-button {
279
+ appearance: none;
280
+ align-items: center;
281
+ background: none;
282
+ border: 1px solid transparent;
283
+ border-radius: var(--sw-radius-pill);
284
+ box-sizing: border-box;
285
+ cursor: pointer;
286
+ display: inline-flex;
287
+ font-family: var(--sw-font-sans);
288
+ font-size: 15px;
289
+ font-weight: 600;
290
+ justify-content: center;
291
+ letter-spacing: -0.2px;
292
+ line-height: 20px;
293
+ margin: 0;
294
+ }
295
+
296
+ .sw-button:focus-visible {
297
+ outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
298
+ outline-offset: var(--sw-focus-ring-offset);
299
+ }
300
+
301
+ .sw-button:disabled {
302
+ cursor: not-allowed;
303
+ opacity: var(--sw-disabled-opacity);
304
+ }
305
+
306
+ .sw-button-primary { background: var(--sw-color-accent); border-color: transparent; color: var(--sw-color-onAccent); }
307
+ .sw-button-secondary { background: var(--sw-glass-fill); border-color: var(--sw-glass-border); color: var(--sw-color-text); backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate)); -webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate)); }
308
+ .sw-button-ghost { background: transparent; border-color: transparent; color: var(--sw-color-accent); }
309
+ .sw-button-danger { background: var(--sw-color-danger); border-color: transparent; color: var(--sw-color-onDanger); }
310
+ .sw-button-sm { min-height: 32px; padding-inline: 12px; }
311
+ .sw-button-md { min-height: 44px; padding-inline: 16px; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalewing/react",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Scalewing DOM components and package-owned CSS utilities.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "README.md"
35
35
  ],
36
36
  "dependencies": {
37
- "@scalewing/tokens": "0.1.0"
37
+ "@scalewing/tokens": "0.2.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "react": "^19.0.0",