Skip to content

Commit 3b4b223

Browse files
committed
initial commit
0 parents  commit 3b4b223

File tree

115 files changed

+12210
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+12210
-0
lines changed

.github/workflows/lint.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Lint
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- main
8+
pull_request:
9+
branches:
10+
- "*"
11+
12+
jobs:
13+
lint:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
18+
- name: Set up Node.js
19+
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4
20+
with:
21+
node-version: '20.x'
22+
cache: 'yarn'
23+
- name: Install deps
24+
run: yarn install --frozen-lockfile
25+
- name: Run lint
26+
run: yarn lint
27+
- name: Run formatter check
28+
run: |
29+
yarn run --silent format-check || ( \
30+
echo "Run this command on your local device to fix the error:" && \
31+
echo "" && \
32+
echo " yarn run format" && \
33+
echo "" && exit 1)

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules
2+
.env
3+
.DS_Store
4+
dist
5+
storybook-static
6+
tsconfig.tsbuildinfo
7+
8+
*storybook.log

.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@tailscale:registry=https://npm.pkg.github.com/

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dist
2+
yarn.lock
3+
package.json

.storybook/main.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { StorybookConfig } from '@storybook/react-vite';
2+
import tsconfigPaths from 'vite-tsconfig-paths';
3+
4+
const config: StorybookConfig = {
5+
"stories": [
6+
'../src/**/*.mdx',
7+
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'
8+
],
9+
"addons": [
10+
"@chromatic-com/storybook",
11+
"@storybook/addon-docs",
12+
"@storybook/addon-onboarding",
13+
"@storybook/addon-a11y",
14+
"@storybook/addon-vitest",
15+
"@storybook/addon-designs",
16+
],
17+
staticDirs: ['../src/assets'],
18+
"framework": {
19+
"name": "@storybook/react-vite",
20+
"options": {}
21+
},
22+
async viteFinal(config) {
23+
config.plugins = [...(config.plugins || []), tsconfigPaths()];
24+
return config;
25+
},
26+
};
27+
export default config;

.storybook/preview.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { Preview } from "@storybook/react";
2+
import '../src/tailwind.css';
3+
4+
const preview: Preview = {
5+
parameters: {
6+
controls: {
7+
matchers: {
8+
color: /(background|color)$/i,
9+
date: /Date$/i,
10+
},
11+
},
12+
},
13+
tags: ['autodocs'],
14+
};
15+
16+
export default preview;

.storybook/vitest.setup.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
2+
import { setProjectAnnotations } from '@storybook/react-vite';
3+
import * as projectAnnotations from './preview';
4+
5+
// This is an important step to apply the right configuration when testing your stories.
6+
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
7+
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);

LICENSE

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2020 Tailscale Inc & AUTHORS.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
1. Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
11+
2. Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
15+
3. Neither the name of the copyright holder nor the names of its
16+
contributors may be used to endorse or promote products derived from
17+
this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# tailscale-ui-components
2+
3+
Tailscale UI component library used by Tailscale web projects. Not maintained for external use.
4+
5+
## Development Setup
6+
7+
### Prerequisites
8+
9+
Ensure you have the following tools installed:
10+
11+
- **Node.js 22.14.0** (use `nvm` to manage Node versions)
12+
```bash
13+
nvm use 22.14.0
14+
```
15+
- **Yarn 1.22.19** (package manager)
16+
```bash
17+
npm install -g [email protected]
18+
```
19+
20+
### Getting Started
21+
22+
1. **Clone the repository**
23+
```bash
24+
git clone https://github.com/tailscale/tailscale-ui-components.git
25+
cd tailscale-ui-components
26+
```
27+
28+
2. **Install dependencies**
29+
```bash
30+
yarn install
31+
```
32+
33+
3. **Start Storybook for development**
34+
```bash
35+
yarn storybook
36+
```
37+
This will start Storybook on `http://localhost:6006` (or the next available port)
38+
39+
### Available Scripts
40+
41+
- `yarn storybook` - Start Storybook development server
42+
- `yarn build-storybook` - Build Storybook for production
43+
- `yarn build` - Build the component library for production
44+
- `yarn test` - Run tests with Vitest
45+
46+
### Environment Compatibility
47+
48+
This project has been tested and works with:
49+
- **Node.js 22.14.0** (recommended for team consistency)
50+
51+
### Package Management
52+
53+
This project uses **Yarn v1** as the package manager. The `yarn.lock` file should be committed, and `package-lock.json` should be ignored/removed if present.
54+
55+
### Component Development
56+
57+
Components are located in `src/components/` and follow these patterns:
58+
59+
1. **OSS-ready structure** with proper style mappings
60+
2. **Comprehensive TypeScript types** and exported constants
61+
3. **Accessibility features** with proper ARIA attributes
62+
4. **Storybook stories** for documentation and testing
63+
64+
Example component structure:
65+
```
66+
src/components/button/
67+
├── button.tsx # Main component
68+
├── button.stories.tsx # Storybook stories
69+
```
70+
71+
### Styling Guidelines
72+
73+
- Use the `.button`, `.input`, and other base CSS classes from `src/tailwind.css`
74+
- Follow the established design tokens and color system
75+
- Ensure components have rounded corners and consistent spacing
76+
- Support both light and dark themes
77+
78+
### Troubleshooting
79+
80+
**Node.js Version Issues:**
81+
If you encounter build errors, ensure you're using Node.js 22.14.0:
82+
```bash
83+
node --version # Should output v22.14.0
84+
```
85+
86+
**Package Manager Issues:**
87+
If dependencies fail to install, try:
88+
```bash
89+
rm -rf node_modules yarn.lock
90+
yarn install
91+
```

package.json

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
{
2+
"name": "@tailscale/tailscale-ui-components",
3+
"version": "0.0.5",
4+
"author": "Tailscale",
5+
"license": "BSD-3-Clause",
6+
"main": "dist/tailscale-ui-components.umd.js",
7+
"module": "dist/tailscale-ui-components.es.js",
8+
"types": "dist/index.d.ts",
9+
"type": "module",
10+
"files": [
11+
"dist",
12+
"tailwind.preset.js"
13+
],
14+
"exports": {
15+
".": {
16+
"types": "./dist/index.d.ts",
17+
"import": "./dist/tailscale-ui-components.es.js",
18+
"require": "./dist/tailscale-ui-components.umd.js"
19+
},
20+
"./tailwind.preset": {
21+
"import": "./tailwind.preset.cjs",
22+
"require": "./tailwind.preset.cjs",
23+
"default": "./tailwind.preset.cjs"
24+
}
25+
},
26+
"peerDependencies": {
27+
"react": "^18.2.0",
28+
"react-dom": "^18.2.0"
29+
},
30+
"dependencies": {
31+
"@radix-ui/react-checkbox": "^1.3.2",
32+
"@radix-ui/react-collapsible": "^1.1.11",
33+
"@radix-ui/react-dialog": "^1.1.14",
34+
"@radix-ui/react-dropdown-menu": "^2.1.15",
35+
"@radix-ui/react-hover-card": "^1.1.14",
36+
"@radix-ui/react-popover": "^1.1.14",
37+
"@radix-ui/react-select": "^2.2.5",
38+
"@radix-ui/react-tabs": "^1.1.12",
39+
"@radix-ui/react-toast": "^1.2.15",
40+
"@radix-ui/react-toggle-group": "^1.1.10",
41+
"@radix-ui/react-tooltip": "^1.2.7",
42+
"classnames": "^2.5.1",
43+
"date-fns": "^2.28.0",
44+
"date-fns-tz": "^2.0.1",
45+
"downshift": "^9.0.10",
46+
"lucide-react": "^0.536.0"
47+
},
48+
"devDependencies": {
49+
"@chromatic-com/storybook": "^4.1.0",
50+
"@storybook/addon-a11y": "^9.1.1",
51+
"@storybook/addon-docs": "^9.1.1",
52+
"@storybook/addon-onboarding": "^9.1.1",
53+
"@storybook/addon-vitest": "^9.1.1",
54+
"@storybook/react-vite": "^9.1.1",
55+
"@types/node": "^24.2.0",
56+
"@types/react": "^18.2.0",
57+
"@types/react-dom": "^18.2.0",
58+
"@typescript-eslint/eslint-plugin": "^6.2.1",
59+
"@typescript-eslint/parser": "^6.2.1",
60+
"@vitejs/plugin-react-swc": "^3.11.0",
61+
"@vitest/browser": "^3.2.4",
62+
"@vitest/coverage-v8": "^3.2.4",
63+
"autoprefixer": "^10.4.21",
64+
"eslint": "^8.23.1",
65+
"eslint-config-react-app": "^7.0.1",
66+
"eslint-plugin-curly-quotes": "^1.0.4",
67+
"eslint-plugin-unicorn": "^41.0.0",
68+
"playwright": "^1.54.2",
69+
"postcss": "^8.5.6",
70+
"prettier": "^2.5.1",
71+
"prettier-plugin-organize-imports": "^3.2.2",
72+
"react": "^18.2.0",
73+
"react-dom": "^18.2.0",
74+
"storybook": "^9.1.1",
75+
"tailwindcss": "^3.4.0",
76+
"typescript": "^5.9.2",
77+
"vite": "^7.0.6",
78+
"vite-plugin-svgr": "^4.3.0",
79+
"vite-tsconfig-paths": "^5.1.4",
80+
"vitest": "^3.2.4"
81+
},
82+
"scripts": {
83+
"build": "vite build && tsc --emitDeclarationOnly",
84+
"storybook": "storybook dev -p 6006",
85+
"build-storybook": "storybook build",
86+
"format": "prettier --write 'src/**/*.{ts,tsx}'",
87+
"format-check": "prettier --check 'src/**/*.{ts,tsx}'",
88+
"lint": "tsc --noEmit && eslint 'src/**/*.{ts,tsx,js,jsx}' --fix --max-warnings=0"
89+
},
90+
"eslintConfig": {
91+
"extends": [
92+
"react-app",
93+
"plugin:unicorn/recommended"
94+
],
95+
"plugins": [
96+
"curly-quotes",
97+
"react-hooks"
98+
],
99+
"rules": {
100+
"unicorn/catch-error-name": "off",
101+
"unicorn/consistent-function-scoping": "off",
102+
"unicorn/consistent-destructuring": "off",
103+
"unicorn/expiring-todo-comments": "off",
104+
"unicorn/prefer-json-parse-buffer": "off",
105+
"unicorn/prefer-object-from-entries": "off",
106+
"unicorn/prefer-spread": "off",
107+
"unicorn/prevent-abbreviations": "off",
108+
"unicorn/no-array-callback-reference": "off",
109+
"unicorn/no-array-for-each": "off",
110+
"unicorn/no-array-reduce": "off",
111+
"unicorn/no-nested-ternary": "off",
112+
"unicorn/no-null": "off",
113+
"unicorn/no-useless-undefined": [
114+
"error",
115+
{
116+
"checkArguments": false
117+
}
118+
],
119+
"unicorn/numeric-separators-style": "off",
120+
"curly-quotes/no-straight-quotes": "warn",
121+
"react-hooks/rules-of-hooks": "error",
122+
"react-hooks/exhaustive-deps": "error",
123+
"@typescript-eslint/no-restricted-imports": [
124+
"error",
125+
{
126+
"paths": [
127+
{
128+
"name": "lucide-react",
129+
"message": "Use `src/ui/icons` instead of `lucide-react`"
130+
}
131+
]
132+
}
133+
],
134+
"no-restricted-imports": [
135+
"error",
136+
{
137+
"paths": [
138+
{
139+
"name": "lucide-react",
140+
"importNames": [
141+
"*"
142+
],
143+
"message": "Please import only the specific icons you need from 'lucide-react' to enable tree-shaking."
144+
}
145+
]
146+
}
147+
]
148+
}
149+
},
150+
"prettier": {
151+
"semi": false,
152+
"printWidth": 80
153+
}
154+
}

0 commit comments

Comments
 (0)