{"_id":"@12min/ds","_rev":"4-68b5d3ce646a048b10dc019ceb00ef9a","name":"@12min/ds","dist-tags":{"latest":"3.1.0"},"versions":{"0.1.0":{"name":"@12min/ds","version":"0.1.0","_id":"@12min/ds@0.1.0","maintainers":[{"name":"ricardo_opus","email":"ricardo@12min.com"}],"dist":{"shasum":"9e1f3a0ac9cb525f3e76430987b6c3c2765cd7cd","tarball":"https://registry.npmjs.org/@12min/ds/-/ds-0.1.0.tgz","fileCount":25,"integrity":"sha512-ptLF92CRTIz6rS83q9ub1bHzn+FUAiXFK9OO2pnO687xS3tkYh4snj3COGSfqHlReV3lkzWbTMZue+ZkLZCSVw==","signatures":[{"sig":"MEYCIQD2S4Wx4pCjixdDHb63/HaKbi2CHkqAxKgDLjtvF4dSAAIhALc+PNivcpliwwvc8UnpwlT4v9c2/Kng2owqWd2a6P8I","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32858},"main":"./dist/index.web.js","types":"./dist/index.web.d.ts","module":"./dist/index.web.mjs","exports":{".":{"types":"./dist/index.web.d.ts","import":"./dist/index.web.mjs","require":"./dist/index.web.js","react-native":{"types":"./dist/index.native.d.ts","default":"./dist/index.native.js"}},"./tokens":{"types":"./dist/tokens/index.d.ts","import":"./dist/tokens/index.mjs","require":"./dist/tokens/index.js"},"./tailwind/theme.css":"./dist/tailwind/theme.css"},"gitHead":"6b5349934d320d2d981553f7cb2da8d997b2296a","scripts":{"dev":"tsup --watch","lint":"eslint src --ext ts,tsx","build":"pnpm clean && pnpm generate:theme && tsup && mkdir -p dist/tailwind && cp src/tailwind/theme.css dist/tailwind/theme.css","clean":"rm -rf dist","typecheck":"tsc --noEmit","generate:theme":"tsx --tsconfig tsconfig.scripts.json src/tailwind/generateTheme.ts","prepublishOnly":"pnpm build && pnpm typecheck"},"_npmUser":{"name":"ricardo_opus","email":"ricardo@12min.com"},"_npmVersion":"10.9.3","description":"```text  ██╗  ██████╗     ███╗   ███╗  ██╗  ███╗   ██╗              ██████╗   ███████╗ ███║  ╚════██╗    ████╗ ████║  ██║  ████╗  ██║              ██╔══██╗  ██╔════╝ ╚██║   █████╔╝    ██╔████╔██║  ██║  ██╔██╗ ██║    █████╗    ██║  ██║  ███████╗  ██║  ██╔═","directories":{},"sideEffects":["dist/tailwind/theme.css"],"_nodeVersion":"22.20.0","dependencies":{"clsx":"^2.1.1","tailwind-merge":"^3.0.0","class-variance-authority":"^0.7.1"},"react-native":"./dist/index.native.js","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.7.0","tsup":"^8.0.0","eslint":"^9.39.4","typescript":"^5.3.0","@types/node":"^25.6.0","@types/react":"^19.2.14","@types/react-native":"^0.73.0"},"peerDependencies":{"react":">=18","react-dom":">=18","tailwindcss":"^4.0.0","react-native":">=0.72"},"_npmOperationalInternal":{"tmp":"tmp/ds_0.1.0_1777006225746_0.4730269057100258","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@12min/ds","version":"1.0.0","_id":"@12min/ds@1.0.0","maintainers":[{"name":"ricardo_opus","email":"ricardo@12min.com"}],"dist":{"shasum":"aee505ad151b12d07445fafbe01503d7f0ac1370","tarball":"https://registry.npmjs.org/@12min/ds/-/ds-1.0.0.tgz","fileCount":27,"integrity":"sha512-kGlI7Fz0qsrIIQ5iotN4C+6huPnVaorMPlPiDx2OkYaBef4+jRy61Oslv03LbrpSbZvBnVyMQG7Qjy1dVxw9Tg==","signatures":[{"sig":"MEUCIEa4YJTWkjpiConyBth8Q3CQK+I7HC7jPzq0eG/fWinYAiEAk1x9LH841SNAXY9RJChBc6Dhuq6pvlLMkWgU5rIcHPc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":286613},"main":"./dist/index.web.js","types":"./dist/index.web.d.ts","module":"./dist/index.web.mjs","exports":{".":{"types":"./dist/index.web.d.ts","import":"./dist/index.web.mjs","require":"./dist/index.web.js","react-native":{"types":"./dist/index.native.d.ts","default":"./dist/index.native.js"}},"./tokens":{"types":"./dist/tokens/index.d.ts","import":"./dist/tokens/index.mjs","require":"./dist/tokens/index.js"},"./tailwind/theme.css":"./dist/tailwind/theme.css"},"gitHead":"d0c6dbe7ee095025dcc200b60c9ada2b58d7e029","scripts":{"dev":"tsup --watch","lint":"eslint src --ext ts,tsx","build":"pnpm clean && pnpm generate:theme && tsup && mkdir -p dist/tailwind && cp src/tailwind/theme.css dist/tailwind/theme.css","clean":"rm -rf dist","storybook":"storybook dev -p 6006","test:unit":"vitest run","typecheck":"tsc --noEmit","prestorybook":"pnpm generate:theme","generate:theme":"tsx --tsconfig tsconfig.scripts.json src/tailwind/generateTheme.ts","prepublishOnly":"pnpm build && pnpm typecheck","build:storybook":"storybook build --output-dir storybook-static","test:unit:watch":"vitest","prebuild:storybook":"pnpm generate:theme","test:unit:coverage":"vitest run --coverage"},"_npmUser":{"name":"ricardo_opus","email":"ricardo@12min.com"},"_npmVersion":"10.9.3","description":"Single source of truth for 12min's visual language — tokens, styles, and components shared across web and mobile.","directories":{},"sideEffects":["dist/tailwind/theme.css"],"_nodeVersion":"22.20.0","dependencies":{"clsx":"^2.1.1","tailwind-merge":"^3.0.0","class-variance-authority":"^0.7.1"},"react-native":"./dist/index.native.js","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.7.0","tsup":"^8.0.0","vite":"^6.4.2","eslint":"^9.39.4","vitest":"^4.1.5","storybook":"^8.6.18","typescript":"^5.3.0","@types/node":"^25.6.0","tailwindcss":"^4.2.4","@types/react":"^19.2.14","@storybook/react":"^8.6.18","@storybook/blocks":"^8","@tailwindcss/vite":"^4.2.4","@types/react-native":"^0.73.0","@vitest/coverage-v8":"^4.1.5","@vitejs/plugin-react":"^4.7.0","@storybook/addon-a11y":"^8.6.18","@storybook/react-vite":"^8.6.18","@storybook/addon-themes":"^8.6.18","@storybook/addon-essentials":"^8"},"peerDependencies":{"react":">=18","react-dom":">=18","tailwindcss":"^4.0.0","react-native":">=0.72"},"_npmOperationalInternal":{"tmp":"tmp/ds_1.0.0_1777569989244_0.40139418989810016","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@12min/ds","version":"3.0.0","_id":"@12min/ds@3.0.0","maintainers":[{"name":"ricardo_opus","email":"ricardo@12min.com"}],"dist":{"shasum":"98144cc0422d8a2513f98e2c8e0499f74282ebac","tarball":"https://registry.npmjs.org/@12min/ds/-/ds-3.0.0.tgz","fileCount":27,"integrity":"sha512-NWywbmwtCHvI5x7NbnAznoZzW/JCmTDF0hHfrS50/rxGFK9KiqGOhePZ+Y4pUhEm+8fuGuzglpJ+tTELkSPPeQ==","signatures":[{"sig":"MEUCIQC45Lo02QOiIhYPnD8Dsem3JiP/1qSnGTQFjRxMXdGrMAIgYRRu7TGWFDy7KrDqMG+04sfgiV+/zEegI2+XX2TKf9s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":540926},"main":"./dist/index.web.js","types":"./dist/index.web.d.ts","module":"./dist/index.web.mjs","exports":{".":{"types":"./dist/index.web.d.ts","import":"./dist/index.web.mjs","require":"./dist/index.web.js","react-native":{"types":"./dist/index.native.d.ts","default":"./dist/index.native.js"}},"./tokens":{"types":"./dist/tokens/index.d.ts","import":"./dist/tokens/index.mjs","require":"./dist/tokens/index.js"},"./tailwind/theme.css":"./dist/tailwind/theme.css"},"gitHead":"8988c341dec40795dd90581b737b013ba84101f0","scripts":{"dev":"tsup --watch","lint":"eslint src --ext ts,tsx","build":"pnpm clean && pnpm generate:theme && tsup && mkdir -p dist/tailwind && cp src/tailwind/theme.css dist/tailwind/theme.css","clean":"rm -rf dist","storybook":"storybook dev -p 6006","test:unit":"vitest run","typecheck":"tsc --noEmit","prestorybook":"pnpm generate:theme","generate:theme":"tsx --tsconfig tsconfig.scripts.json src/tailwind/generateTheme.ts","prepublishOnly":"pnpm build && pnpm typecheck","build:storybook":"storybook build --output-dir storybook-static","test:unit:watch":"vitest","prebuild:storybook":"pnpm generate:theme","test:unit:coverage":"vitest run --coverage"},"_npmUser":{"name":"ricardo_opus","email":"ricardo@12min.com"},"_npmVersion":"11.4.2","description":"Single source of truth for 12min's visual language — tokens, styles, and components shared across web and mobile.","directories":{},"sideEffects":["dist/tailwind/theme.css"],"_nodeVersion":"24.3.0","dependencies":{"clsx":"^2.1.1","tailwind-merge":"^3.0.0","class-variance-authority":"^0.7.1"},"react-native":"./dist/index.native.js","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.15.1","devDependencies":{"tsx":"^4.7.0","tsup":"^8.0.0","vite":"^6.4.2","eslint":"^9.39.4","vitest":"^4.1.5","storybook":"^8.6.18","typescript":"^5.3.0","@types/node":"^25.6.0","tailwindcss":"^4.2.4","@types/react":"^19.2.14","@storybook/react":"^8.6.18","@storybook/blocks":"^8","@tailwindcss/vite":"^4.2.4","@types/react-native":"^0.73.0","@vitest/coverage-v8":"^4.1.5","@vitejs/plugin-react":"^4.7.0","@storybook/addon-a11y":"^8.6.18","@storybook/react-vite":"^8.6.18","@storybook/addon-themes":"^8.6.18","@storybook/addon-essentials":"^8"},"peerDependencies":{"react":">=18","react-dom":">=18","tailwindcss":"^4.0.0","react-native":">=0.72"},"_npmOperationalInternal":{"tmp":"tmp/ds_3.0.0_1784641544897_0.7193921352631818","host":"s3://npm-registry-packages-npm-production"}},"3.1.0":{"name":"@12min/ds","version":"3.1.0","packageManager":"bun@1.3.9","trustedDependencies":["esbuild"],"sideEffects":["dist/tailwind/theme.css"],"main":"./dist/index.web.js","module":"./dist/index.web.mjs","types":"./dist/index.web.d.ts","react-native":"./dist/index.native.js","exports":{".":{"react-native":{"types":"./dist/index.native.d.ts","default":"./dist/index.native.js"},"types":"./dist/index.web.d.ts","import":"./dist/index.web.mjs","require":"./dist/index.web.js"},"./tokens":{"types":"./dist/tokens/index.d.ts","import":"./dist/tokens/index.mjs","require":"./dist/tokens/index.js"},"./tailwind/theme.css":"./dist/tailwind/theme.css"},"publishConfig":{"access":"public"},"scripts":{"clean":"rm -rf dist","generate:theme":"tsx --tsconfig tsconfig.scripts.json src/tailwind/generateTheme.ts","build":"bun run clean && bun run generate:theme && tsup && mkdir -p dist/tailwind && cp src/tailwind/theme.css dist/tailwind/theme.css","dev":"tsup --watch","typecheck":"tsc --noEmit","lint":"eslint src","prepublishOnly":"bun run build && bun run typecheck","prestorybook":"bun run generate:theme","storybook":"storybook dev -p 6006","prebuild:storybook":"bun run generate:theme","build:storybook":"storybook build --output-dir storybook-static","test:unit":"vitest run","test:unit:watch":"vitest","test:unit:coverage":"vitest run --coverage"},"peerDependencies":{"react":">=18","react-dom":">=18","react-native":">=0.72","tailwindcss":"^4.0.0"},"dependencies":{"class-variance-authority":"^0.7.1","clsx":"^2.1.1","tailwind-merge":"^3.0.0"},"devDependencies":{"@eslint/js":"^10.0.1","@storybook/addon-a11y":"^8.6.18","@storybook/addon-essentials":"^8","@storybook/addon-themes":"^8.6.18","@storybook/blocks":"^8","@storybook/react":"^8.6.18","@storybook/react-vite":"^8.6.18","@tailwindcss/vite":"^4.2.4","@types/node":"^25.6.0","@types/react":"^19.2.14","@types/react-native":"^0.73.0","@vitejs/plugin-react":"^4.7.0","@vitest/coverage-v8":"^4.1.5","eslint":"^9.39.4","eslint-plugin-react":"^7.37.5","eslint-plugin-react-hooks":"^7.1.1","globals":"^17.7.0","storybook":"^8.6.18","tailwindcss":"^4.2.4","tsup":"^8.0.0","tsx":"^4.7.0","typescript":"^5.3.0","typescript-eslint":"^8.65.0","vite":"^6.4.2","vitest":"^4.1.5"},"_id":"@12min/ds@3.1.0","gitHead":"20d76c050687943b49996e24fffd23647e2bd503","description":"Single source of truth for 12min's visual language — tokens, styles, and components shared across web and mobile.","_nodeVersion":"24.3.0","_npmVersion":"11.4.2","dist":{"integrity":"sha512-K16iD6Jw+zeivDbOBuRkmQlY39DV13hyb6CEVs4+dQIsyYgYaLyS4hJYbTyQVdT+pRGdB0kD+F8gQXYov26Ijw==","shasum":"908db4e25ca8acd6de54ebc8c53c19792433c21b","tarball":"https://registry.npmjs.org/@12min/ds/-/ds-3.1.0.tgz","fileCount":27,"unpackedSize":550089,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD/mWiFIqtrWh42erfzruZwqTUZGTBHw9oVyLMKUL8sggIgKF6hWlYWHq8Ij3L0cG+/V3BBCOwNk5ew2s66iuH84bU="}]},"_npmUser":{"name":"ricardo_opus","email":"ricardo@12min.com"},"directories":{},"maintainers":[{"name":"ricardo_opus","email":"ricardo@12min.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ds_3.1.0_1784710803926_0.34791820421780284"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-24T04:50:25.682Z","modified":"2026-07-22T09:00:04.254Z","0.1.0":"2026-04-24T04:50:25.896Z","1.0.0":"2026-04-30T17:26:29.393Z","3.0.0":"2026-07-21T13:45:45.038Z","3.1.0":"2026-07-22T09:00:04.093Z"},"description":"Single source of truth for 12min's visual language — tokens, styles, and components shared across web and mobile.","maintainers":[{"name":"ricardo_opus","email":"ricardo@12min.com"}],"readme":"# `@12min/ds`\n\nSingle source of truth for 12min's visual language — tokens, styles, and components shared across web and mobile.\n\n---\n\n## What's included\n\n| | Status |\n|---|---|\n| Color palette (`marianBlue`, `midnight`, `gray`, `mustard`, `ketchup`, `mint`) | ✅ |\n| Typography tokens (14-entry scale) | ✅ |\n| CSS theme (`theme.css`) — colors + `@utility text-*` blocks | ✅ |\n| Semantic themes (light / dark) | ✅ |\n| Components — Button, Chip, Alert, ProgressBar, Input, Checkbox, RadioItem, RadioGroup, ActionItem, Stepper, RatingScale | ✅ |\n| `DSThemeProvider` + `useTheme` (native programmatic dark mode) | ✅ |\n| Storybook 8 | ✅ |\n\n---\n\n## Installation\n\n```sh\nbun add @12min/ds\n```\n\n**Peer dependencies** — install in the consuming app if not already present:\n\n```sh\n# web\nbun add tailwindcss@^4.0.0\n\n# mobile\nbun add nativewind@5.0.0-preview.3\nbun add --dev tailwindcss@^4.0.0\n```\n\n---\n\n## Usage\n\n### Web — Tailwind v4\n\nImport the generated theme in your global CSS entry point:\n\n```css\n/* globals.css */\n@import \"tailwindcss\";\n@import \"@12min/ds/tailwind/theme.css\";\n```\n\nAll palette tokens are available as Tailwind utilities, and typography utilities are pre-built:\n\n```tsx\n<div className=\"bg-marian-blue-600 text-white\">\n<p className=\"text-body-default\">Body text</p>\n<h1 className=\"text-h1\">Heading</h1>\n```\n\nImport components from `@12min/ds`:\n\n```tsx\nimport { Button, Input, RadioItem, RadioGroup } from '@12min/ds'\n\n<Button variant=\"primary\" size=\"md\">Continue</Button>\n\n<RadioGroup label=\"Pick your profile\">\n  <RadioItem label=\"Leader\" selected={selected === 'leader'} onClick={() => setSelected('leader')} />\n  <RadioItem label=\"Student\" selected={selected === 'student'} onClick={() => setSelected('student')} />\n</RadioGroup>\n```\n\n### Mobile — React Native + NativeWind v5\n\nPoint Metro at the published theme file:\n\n```js\n// metro.config.js\nconst { withNativeWind } = require('nativewind/metro')\n\nmodule.exports = withNativeWind(config, {\n  input: 'node_modules/@12min/ds/dist/tailwind/theme.css',\n})\n```\n\nWrap your app in `DSThemeProvider` for programmatic dark mode:\n\n```tsx\nimport { DSThemeProvider, Button, Input } from '@12min/ds'\n\nexport default function App() {\n  const colorScheme = useColorScheme()\n  return (\n    <DSThemeProvider colorScheme={colorScheme ?? 'light'}>\n      <Button variant=\"primary\" onPress={handlePress}>Continue</Button>\n      <Input placeholder=\"Email\" state=\"default\" />\n    </DSThemeProvider>\n  )\n}\n```\n\nDS typography names the `Poppins` and `Inter` families directly. If your app registers fonts under different names (e.g. expo-google-fonts registers one face per name, like `Poppins_700Bold`), pass a font map so components resolve to the registered faces — define it once, outside the component:\n\n```tsx\nimport { DSThemeProvider, type DSFonts } from '@12min/ds'\n\nconst dsFonts: DSFonts = {\n  poppins: { '600': 'Poppins_600SemiBold', '700': 'Poppins_700Bold' },\n  inter: { '400': 'Inter_400Regular', '500': 'Inter_500Medium', '600': 'Inter_600SemiBold' },\n}\n\n<DSThemeProvider colorScheme={colorScheme ?? 'light'} fonts={dsFonts}>\n```\n\nMapped styles set `fontWeight: 'normal'` — static faces already carry their weight, and a numeric weight would make Android synthesize a fake bold on top.\n\nAccess theme tokens directly via `useTheme()`:\n\n```tsx\nimport { useTheme } from '@12min/ds'\n\nconst { theme } = useTheme()\n// theme.primary, theme.background, theme.error, ...\n```\n\n### Tokens (framework-agnostic)\n\nRaw token values as TypeScript — useful for chart libraries, animations, or any non-Tailwind consumer:\n\n```ts\nimport { colors, typography } from '@12min/ds/tokens'\nimport { lightTheme, darkTheme } from '@12min/ds'\n\n// colors.marianBlue[600] === '#475CBB'\n// typography.bodyDefault.fontSize === 14\n// lightTheme.primary === '#475CBB'\n```\n\n---\n\n## Components\n\nAll components are available on both web and native from the same `@12min/ds` import.\n\n| Component | Props |\n|---|---|\n| `Button` | `variant` (primary/secondary/ghost), `size` (sm/md/lg), `disabled` |\n| `Chip` | `children`, `checked`, `onPress`/`onClick` |\n| `Alert` | `variant` (info/success), `title`, `description` |\n| `ProgressBar` | `value` (0–100) |\n| `Input` | `state` (default/filled/error/disabled), `leadingIcon`, `placeholder` |\n| `Checkbox` | `checked`, `onChange`, `disabled` |\n| `RadioItem` | `label`, `description`, `selected`, `icon`, `onPress`/`onClick` |\n| `RadioGroup` | `label` (for a11y), `className`/`style` — wraps `RadioItem` list |\n| `ActionItem` | `label`, `description`, `selected`, `icon`, `onPress`/`onClick` |\n| `Stepper` | `steps`, `currentStep` |\n| `RatingScale` | `value`, `onChange`, `options` (default: 5 emoji options) |\n\n> Native components accept a `style` prop for layout overrides. Web components accept `className`.\n\n---\n\n## Development\n\n### Requirements\n\n- Bun 1.3+\n\n```sh\nbun install\n```\n\n### Scripts\n\n| Command | Description |\n|---|---|\n| `bun run build` | Clean, generate theme, compile, copy CSS |\n| `bun run dev` | Watch mode (tsup) |\n| `bun run generate:theme` | Regenerate `src/tailwind/theme.css` from tokens |\n| `bun run typecheck` | TypeScript — library code |\n| `bun run test:unit` | Run unit tests (vitest) |\n| `bun run storybook` | Start Storybook on port 6006 |\n| `bun run lint` | ESLint |\n\n### Adding or changing tokens\n\n1. Edit `src/tokens/colors.ts` or `src/tokens/typography.ts`\n2. Run `bun run generate:theme` to regenerate `theme.css`\n3. If adding a new semantic token, update `src/themes/types.ts` first, then both `lightTheme.ts` and `darkTheme.ts`\n4. Run `bun run build` before committing\n\n`theme.css` is gitignored — it is always generated from source.\n\n---\n\n## Releases\n\nVersions follow [semver](https://semver.org). The `./tokens` export is a stable public API — breaking changes to its shape require a major version bump.\n\n```sh\n# bump version and create git tag\nbun pm version patch   # 0.1.0 → 0.1.1\nbun pm version minor   # 0.1.0 → 0.2.0\nbun pm version major   # 0.1.0 → 1.0.0\n\n# push tag to trigger the release workflow\ngit push origin main --tags\n```\n\nThe GitHub Actions CI runs typecheck, build, and unit tests on every push to `main` and on pull requests.\n\n---\n\n## Documentation\n\n| Doc | Description |\n|---|---|\n| [`docs/architecture.md`](docs/architecture.md) | Three-layer model, component structure, platform resolution |\n| [`docs/next-steps.md`](docs/next-steps.md) | Pending decisions, migration guides, release workflow |\n| [`docs/critical-review.md`](docs/critical-review.md) | Architectural decisions log — open and closed |\n","readmeFilename":"README.md"}