@dalcvil/steam-green-react 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/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dalcvi
4
+
5
+ This project contains styles derived from VGUI.css
6
+ (https://github.com/AlpyneDreams/vgui.css), Copyright (c) 2021 Jeffrey Ellison,
7
+ licensed under the MIT License.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # @dalcvil/steam-green-react
2
+
3
+ React components for the classic Green Steam (VGUI) look, ported from
4
+ [VGUI.css](https://github.com/AlpyneDreams/vgui.css).
5
+
6
+ - **Tree-shakable ESM build** — the output mirrors `src/`, so importing one
7
+ component never pulls in the others.
8
+ - **Per-component CSS** — each component imports its own stylesheet; the global
9
+ theme is opt-in.
10
+ - **Storybook** — every component ships with stories, published to GitHub Pages.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pnpm add @dalcvil/steam-green-react
16
+ # or: npm install @dalcvil/steam-green-react
17
+ ```
18
+
19
+ `react` and `react-dom` (`^18` or `^19`) are peer dependencies.
20
+
21
+ ## Usage
22
+
23
+ ```tsx
24
+ import { GreenButton } from '@dalcvil/steam-green-react'
25
+
26
+ // Optional: the global Green Steam theme (background, typography, links…)
27
+ import '@dalcvil/steam-green-react/styles/theme.css'
28
+
29
+ export function App() {
30
+ return <GreenButton onClick={() => alert('Hello')}>Click me</GreenButton>
31
+ }
32
+ ```
33
+
34
+ Component styles come along with the component — there is nothing else to
35
+ import.
36
+
37
+ > The package is **ESM-only**. CJS output cannot be tree-shaken and would
38
+ > duplicate the colocated CSS, so it is intentionally not published. Use a
39
+ > bundler (Vite, webpack, Rollup, esbuild) or Node's native ESM.
40
+
41
+ ## Components
42
+
43
+ | Component | Description |
44
+ | --- | --- |
45
+ | `GreenButton` | Classic VGUI push button. Supports `fullWidth` on top of all `<button>` props. |
46
+
47
+ More components are on the way; each one will get its own CSS file plus a
48
+ Storybook story.
49
+
50
+ ## Development
51
+
52
+ Node 24 is required. `.nvmrc` pins the exact version and is also what the
53
+ workflows read via `node-version-file`, so the local toolchain and CI cannot
54
+ drift apart. pnpm 12 is pinned through the `packageManager` field.
55
+
56
+ ```bash
57
+ pnpm install
58
+ pnpm storybook # Storybook on http://localhost:6006
59
+ pnpm run build # library -> dist/
60
+ pnpm run build-storybook # static Storybook -> storybook-static/
61
+ pnpm run typecheck # tsc --noEmit
62
+ pnpm changeset # describe a change for the next release
63
+ ```
64
+
65
+ ### How the build works
66
+
67
+ `pnpm run build` runs two steps:
68
+
69
+ 1. **`vite build`** bundles the components in library mode. Stylesheets are
70
+ declared `external` so that `import './X.css'` survives in the emitted
71
+ JavaScript, then copied into `dist/` beside their component — Vite's library
72
+ mode would otherwise extract them into anonymous hashed assets and drop the
73
+ import. A bare `.css.d.ts` is written next to each one, because TypeScript
74
+ keeps the stylesheet import in the declarations it emits and a consumer
75
+ compiling with `skipLibCheck: false` needs that import to resolve.
76
+ 2. **`tsc -p tsconfig.build.json`** emits the `.d.ts` declarations using
77
+ TypeScript's own output — no third-party declaration bundler. The base
78
+ `tsconfig.json` stays `noEmit` for typechecking; `tsconfig.build.json`
79
+ extends it with `emitDeclarationOnly` and `outDir: dist`, and excludes
80
+ stories.
81
+
82
+ ### Project layout
83
+
84
+ ```
85
+ src/
86
+ index.ts # public entry point
87
+ styles/theme.css # global theme (opt-in)
88
+ components/
89
+ GreenButton/
90
+ GreenButton.tsx
91
+ GreenButton.css # colocated styles, imported by the component
92
+ GreenButton.stories.tsx
93
+ index.ts
94
+ ```
95
+
96
+ To add a component: create a folder under `src/components/`, export it from its
97
+ own `index.ts` **and** from `src/index.ts`, and add a story next to it.
98
+
99
+ ## CI/CD
100
+
101
+ | Workflow | Trigger | What it does |
102
+ | --- | --- | --- |
103
+ | `.github/workflows/ci.yml` | push to `main`, PRs | Typechecks, builds the library and Storybook, uploads `dist` as an artifact. |
104
+ | `.github/workflows/pages.yml` | push to `main` | Builds Storybook and deploys it to GitHub Pages. |
105
+ | `.github/workflows/release.yml` | push to `main` | Opens/updates the *“chore: version packages”* PR, then publishes to npm **with provenance** and creates the GitHub release once that PR is merged. |
106
+
107
+ ### Releasing
108
+
109
+ Releases are managed by [Changesets](https://changesets.dev) — the version in
110
+ `package.json` is only ever changed by CI.
111
+
112
+ 1. Add a changeset to your PR describing the change and the bump it needs:
113
+
114
+ ```bash
115
+ pnpm changeset
116
+ ```
117
+
118
+ This writes a Markdown file into `.changeset/`; commit it with your code.
119
+ 2. When that PR lands on `main`, the release workflow opens (or updates) the
120
+ **“chore: version packages”** pull request, which applies the bumps,
121
+ regenerates `CHANGELOG.md` and deletes the consumed changeset files.
122
+ 3. Merge that pull request. The next release run finds no pending changesets, so
123
+ it publishes to npm, pushes the `@dalcvil/steam-green-react@<version>` tag and
124
+ creates a GitHub release.
125
+
126
+ Nothing is published while no changeset exists, so `main` can sit unreleased
127
+ indefinitely — with one exception: `@dalcvil/steam-green-react` is not on the
128
+ registry yet, so the first release run publishes the current `0.1.0` directly.
129
+
130
+ ### First-time setup
131
+
132
+ 1. **GitHub Pages** — set **Settings → Pages → Source** to **GitHub Actions**.
133
+ This cannot be automated: `GITHUB_TOKEN` is denied the Pages-creation API
134
+ (*Resource not accessible by integration*), and the *Deploy from a branch*
135
+ default runs a Jekyll build that serves the README instead. Once the source
136
+ is set, the Pages workflow publishes Storybook to
137
+ `https://<owner>.github.io/<repo>/`.
138
+ 2. **npm publishing** — create an npm **Automation** token for the `@dalcvil`
139
+ scope and store it as the repository secret `NPM_TOKEN`
140
+ (**Settings → Secrets and variables → Actions**). The release workflow
141
+ exports it as `NODE_AUTH_TOKEN`, which `actions/setup-node` picks up.
142
+ 3. **Allow the version PR** — enable **Settings → Actions → General →
143
+ *Allow GitHub Actions to create and approve pull requests***, otherwise the
144
+ workflow cannot open the “chore: version packages” pull request.
145
+
146
+ > **Note:** commits and pull requests created with the default `GITHUB_TOKEN`
147
+ > do not trigger other workflows, so the “chore: version packages” PR shows no
148
+ > CI checks. If CI is a required status check on `main`, pass a personal access
149
+ > token to the action's `github-token` input so that PR triggers CI.
150
+
151
+ ## Credits
152
+
153
+ Styles are derived from [VGUI.css](https://github.com/AlpyneDreams/vgui.css) by
154
+ Jeffrey Ellison (MIT). See [LICENSE](./LICENSE).
155
+
156
+ ## License
157
+
158
+ MIT © Dalcvi
@@ -0,0 +1,47 @@
1
+ /*
2
+ * Green Steam button.
3
+ *
4
+ * The upstream VGUI.css targets the bare `button` element. As a component we
5
+ * scope the same declarations to `.greensteam-button` so the component can be
6
+ * dropped into any page without restyling every button on it.
7
+ */
8
+
9
+ .greensteam-button {
10
+ color: white;
11
+ background-color: #4c5844;
12
+ height: 25px;
13
+ min-width: 75px;
14
+ padding: 0 8px;
15
+ cursor: pointer;
16
+ border-top: solid 1px #899281;
17
+ border-bottom: solid 1px #292d23;
18
+ border-left: solid 1px #899281;
19
+ border-right: solid 1px #292d23;
20
+ font-family: inherit;
21
+ font-size: inherit;
22
+ font-weight: lighter;
23
+ text-align: left;
24
+ -webkit-font-smoothing: none;
25
+ }
26
+
27
+ .greensteam-button:active {
28
+ border-top: solid 1px #292d23;
29
+ border-bottom: solid 1px #899281;
30
+ border-left: solid 1px #292d23;
31
+ border-right: solid 1px #899281;
32
+ }
33
+
34
+ .greensteam-button:focus-visible {
35
+ outline: 1px dashed #292d23;
36
+ outline-offset: -4px;
37
+ }
38
+
39
+ .greensteam-button:disabled {
40
+ color: #8b9481;
41
+ cursor: default;
42
+ }
43
+
44
+ .greensteam-button--full-width {
45
+ display: block;
46
+ width: 100%;
47
+ }
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,8 @@
1
+ import type { ButtonHTMLAttributes } from 'react';
2
+ import './GreenButton.css';
3
+ export interface GreenButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
4
+ /** Stretch the button across the full width of its container. */
5
+ fullWidth?: boolean;
6
+ }
7
+ export declare const GreenButton: import("react").ForwardRefExoticComponent<GreenButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
8
+ //# sourceMappingURL=GreenButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GreenButton.d.ts","sourceRoot":"","sources":["../../../src/components/GreenButton/GreenButton.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAEjD,OAAO,mBAAmB,CAAA;AAE1B,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC/E,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,eAAO,MAAM,WAAW,gHAStB,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { forwardRef } from "react";
2
+ import "./GreenButton.css";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/components/GreenButton/GreenButton.tsx
5
+ var GreenButton = forwardRef(function GreenButton({ className, type = "button", fullWidth = false, ...rest }, ref) {
6
+ const classes = ["greensteam-button"];
7
+ if (fullWidth) classes.push("greensteam-button--full-width");
8
+ if (className) classes.push(className);
9
+ return /* @__PURE__ */ jsx("button", {
10
+ ref,
11
+ type,
12
+ className: classes.join(" "),
13
+ ...rest
14
+ });
15
+ });
16
+ GreenButton.displayName = "GreenButton";
17
+ //#endregion
18
+ export { GreenButton };
19
+
20
+ //# sourceMappingURL=GreenButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GreenButton.js","names":[],"sources":["../../../src/components/GreenButton/GreenButton.tsx"],"sourcesContent":["import { forwardRef } from 'react'\r\nimport type { ButtonHTMLAttributes } from 'react'\r\n\r\nimport './GreenButton.css'\r\n\r\nexport interface GreenButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\r\n /** Stretch the button across the full width of its container. */\r\n fullWidth?: boolean\r\n}\r\n\r\nexport const GreenButton = forwardRef<HTMLButtonElement, GreenButtonProps>(function GreenButton(\r\n { className, type = 'button', fullWidth = false, ...rest },\r\n ref,\r\n) {\r\n const classes = ['greensteam-button']\r\n if (fullWidth) classes.push('greensteam-button--full-width')\r\n if (className) classes.push(className)\r\n\r\n return <button ref={ref} type={type} className={classes.join(' ')} {...rest} />\r\n})\r\n\r\nGreenButton.displayName = 'GreenButton'\r\n"],"mappings":";;;;AAUA,IAAa,cAAc,WAAgD,SAAS,YAClF,EAAE,WAAW,OAAO,UAAU,YAAY,OAAO,GAAG,QACpD,KACA;CACA,MAAM,UAAU,CAAC,mBAAmB;CACpC,IAAI,WAAW,QAAQ,KAAK,+BAA+B;CAC3D,IAAI,WAAW,QAAQ,KAAK,SAAS;CAErC,OAAO,oBAAC,UAAD;EAAa;EAAW;EAAM,WAAW,QAAQ,KAAK,GAAG;EAAG,GAAI;CAAO,CAAA;AAChF,CAAC;AAED,YAAY,cAAc"}
@@ -0,0 +1,3 @@
1
+ export { GreenButton } from './GreenButton';
2
+ export type { GreenButtonProps } from './GreenButton';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/GreenButton/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @dalcvil/steam-green-react
3
+ *
4
+ * Public entry point. Every component is re-exported from here, but the build
5
+ * preserves the module graph so importing one component never pulls in the
6
+ * rest:
7
+ *
8
+ * ```tsx
9
+ * import { GreenButton } from '@dalcvil/steam-green-react'
10
+ * ```
11
+ *
12
+ * The global theme (`@dalcvil/steam-green-react/styles/theme.css`) is opt-in;
13
+ * per-component styles ship with their component.
14
+ */
15
+ export { GreenButton } from './components/GreenButton';
16
+ export type { GreenButtonProps } from './components/GreenButton';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { GreenButton } from "./components/GreenButton/GreenButton.js";
2
+ export { GreenButton };
@@ -0,0 +1,122 @@
1
+ /*
2
+ * Global Green Steam (VGUI) theme.
3
+ *
4
+ * Only document-level rules live here — the element defaults and shared layout
5
+ * helpers that every component inherits. Anything that belongs to a specific
6
+ * component is colocated with that component instead (see
7
+ * `components/GreenButton/GreenButton.css`).
8
+ *
9
+ * Derived from VGUI.css <https://github.com/AlpyneDreams/vgui.css> (MIT).
10
+ */
11
+
12
+ body {
13
+ background-color: #3e4637;
14
+ font-family: "Trebuchet MS", "Verdana", sans-serif;
15
+ color: #d8ded3;
16
+ font-size: 14px;
17
+ image-rendering: pixelated;
18
+ margin: 20px 20px;
19
+ }
20
+
21
+ ::selection {
22
+ background-color: #96892d;
23
+ }
24
+
25
+ h1,
26
+ h2,
27
+ h3,
28
+ h4,
29
+ h5,
30
+ h6 {
31
+ margin: 3px 12px 12px;
32
+ }
33
+
34
+ h1,
35
+ h2 {
36
+ color: #c4b550;
37
+ }
38
+
39
+ h1 {
40
+ font-size: 18px;
41
+ }
42
+
43
+ h2 {
44
+ font-size: 16px;
45
+ }
46
+
47
+ p {
48
+ text-align: left;
49
+ margin: 12px 12px 12px;
50
+ color: #d8ded3;
51
+ }
52
+
53
+ a {
54
+ text-decoration: none;
55
+ color: #aaaaaa;
56
+ }
57
+
58
+ a:hover {
59
+ text-decoration: underline;
60
+ }
61
+
62
+ code {
63
+ background: #3e4637;
64
+ padding: 0 3px;
65
+ font-family: monospace;
66
+ }
67
+
68
+ hr {
69
+ margin: 20px 0;
70
+ border: none;
71
+ height: 1px;
72
+ background-color: #3e4637;
73
+ }
74
+
75
+ img {
76
+ object-fit: contain;
77
+ margin: 2px;
78
+ border: solid 2px #7b8484;
79
+ }
80
+
81
+ fieldset {
82
+ border-top: solid 1px #292d23;
83
+ border-bottom: solid 1px #899281;
84
+ border-left: solid 1px #292d23;
85
+ border-right: solid 1px #899281;
86
+ }
87
+
88
+ legend {
89
+ text-transform: uppercase;
90
+ letter-spacing: 2px;
91
+ font-size: 12px;
92
+ color: white;
93
+ font-weight: bold;
94
+ }
95
+
96
+ /* Shared layout helpers */
97
+
98
+ .flex-row {
99
+ display: flex;
100
+ flex-direction: row;
101
+ align-items: flex-start;
102
+ }
103
+
104
+ .flex-column {
105
+ display: flex;
106
+ flex-direction: column;
107
+ align-items: flex-start;
108
+ }
109
+
110
+ .border {
111
+ border-top: solid 1px #899281;
112
+ border-bottom: solid 1px #292d23;
113
+ border-left: solid 1px #899281;
114
+ border-right: solid 1px #292d23;
115
+ }
116
+
117
+ .border-inverted {
118
+ border-top: solid 1px #292d23;
119
+ border-bottom: solid 1px #899281;
120
+ border-left: solid 1px #292d23;
121
+ border-right: solid 1px #899281;
122
+ }
@@ -0,0 +1 @@
1
+ export {}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@dalcvil/steam-green-react",
3
+ "version": "0.1.0",
4
+ "description": "Tree-shakable React components for the classic Green Steam (VGUI) theme.",
5
+ "keywords": [
6
+ "react",
7
+ "components",
8
+ "ui",
9
+ "steam",
10
+ "vgui",
11
+ "greensteam",
12
+ "retro"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "Dalcvi",
16
+ "homepage": "https://github.com/Dalcvi/steam-style-react",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/Dalcvi/steam-style-react.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/Dalcvi/steam-style-react/issues"
23
+ },
24
+ "type": "module",
25
+ "packageManager": "pnpm@12.4.1",
26
+ "sideEffects": [
27
+ "**/*.css"
28
+ ],
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "main": "./dist/index.js",
33
+ "module": "./dist/index.js",
34
+ "types": "./dist/index.d.ts",
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/index.d.ts",
38
+ "import": "./dist/index.js",
39
+ "default": "./dist/index.js"
40
+ },
41
+ "./styles/theme.css": "./dist/styles/theme.css",
42
+ "./package.json": "./package.json"
43
+ },
44
+ "scripts": {
45
+ "build": "vite build && tsc -p tsconfig.build.json",
46
+ "typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.node.json",
47
+ "storybook": "storybook dev -p 6006",
48
+ "build-storybook": "storybook build",
49
+ "changeset": "changeset",
50
+ "version-packages": "changeset version",
51
+ "release": "changeset publish",
52
+ "prepublishOnly": "pnpm run typecheck && pnpm run build"
53
+ },
54
+ "peerDependencies": {
55
+ "react": "^18.0.0 || ^19.0.0",
56
+ "react-dom": "^18.0.0 || ^19.0.0"
57
+ },
58
+ "devDependencies": {
59
+ "@changesets/changelog-github": "^1.0.1",
60
+ "@changesets/cli": "^3.0.2",
61
+ "@storybook/addon-a11y": "^10.6.0",
62
+ "@storybook/addon-docs": "^10.6.0",
63
+ "@storybook/react-vite": "^10.6.0",
64
+ "@types/node": "^24.10.0",
65
+ "@types/react": "^19.3.0",
66
+ "@types/react-dom": "^19.3.0",
67
+ "@vitejs/plugin-react": "^6.1.1",
68
+ "react": "^19.3.0",
69
+ "react-dom": "^19.3.0",
70
+ "storybook": "^10.6.0",
71
+ "typescript": "^7.0.2",
72
+ "vite": "^8.3.0"
73
+ }
74
+ }