@icebreakers/monorepo-templates 2.0.7 → 2.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.
Files changed (167) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/assets/.agents/skills/repoctl/SKILL.md +4 -2
  4. package/assets/.agents/skills/repoctl/references/commands.md +224 -13
  5. package/assets/.agents/skills/repoctl/references/config.md +70 -6
  6. package/assets/.agents/skills/repoctl/references/dependencies.md +37 -0
  7. package/assets/.agents/skills/repoctl/references/knip.md +34 -0
  8. package/assets/.agents/skills/repoctl/references/templates.md +26 -2
  9. package/assets/.github/workflows/ci.yml +10 -14
  10. package/assets/package.json +8 -16
  11. package/assets/pnpm-workspace.yaml +4 -1
  12. package/assets/repoctl.config.ts +1 -1
  13. package/assets/turbo.json +12 -4
  14. package/dist/cli.mjs +1 -1
  15. package/dist/index.d.mts +281 -1
  16. package/dist/index.mjs +1138 -75
  17. package/dist/{prepare-BapI8ioj.mjs → prepare-BYNSxvoB.mjs} +96 -4
  18. package/package.json +2 -1
  19. package/template-data.mjs +32 -0
  20. package/templates/client/package.json +2 -2
  21. package/templates/next/README.md +31 -0
  22. package/templates/next/eslint.config.js +5 -0
  23. package/templates/next/gitignore +7 -0
  24. package/templates/next/next.config.ts +5 -0
  25. package/templates/next/package.json +36 -0
  26. package/templates/next/src/app/api/health/route.ts +5 -0
  27. package/templates/next/src/app/counter.tsx +19 -0
  28. package/templates/next/src/app/favicon.ico +0 -0
  29. package/templates/next/src/app/globals.css +109 -0
  30. package/templates/next/src/app/layout.tsx +17 -0
  31. package/templates/next/src/app/page.tsx +16 -0
  32. package/templates/next/stylelint.config.js +3 -0
  33. package/templates/next/test/counter.test.tsx +22 -0
  34. package/templates/next/tsconfig.json +40 -0
  35. package/templates/next/turbo.json +24 -0
  36. package/templates/next/vitest.config.js +9 -0
  37. package/templates/nimbus/AGENTS.md +12 -0
  38. package/templates/nimbus/LICENSE +21 -0
  39. package/templates/nimbus/README.md +17 -0
  40. package/templates/nimbus/UPSTREAM.md +16 -0
  41. package/templates/nimbus/astro.config.ts +28 -0
  42. package/templates/nimbus/eslint.config.js +25 -0
  43. package/templates/nimbus/gitignore +5 -0
  44. package/templates/nimbus/nimbus.json +4 -0
  45. package/templates/nimbus/package.json +34 -0
  46. package/templates/nimbus/public/favicon.svg +1 -0
  47. package/templates/nimbus/scripts/check-locales.mjs +11 -0
  48. package/templates/nimbus/src/components/aside.astro +9 -0
  49. package/templates/nimbus/src/components/head.astro +43 -0
  50. package/templates/nimbus/src/components/search/client.ts +62 -0
  51. package/templates/nimbus/src/components/search/index.astro +26 -0
  52. package/templates/nimbus/src/components/sidebar.astro +26 -0
  53. package/templates/nimbus/src/components.ts +3 -0
  54. package/templates/nimbus/src/content/docs/get-started.mdx +36 -0
  55. package/templates/nimbus/src/content/docs/index.mdx +16 -0
  56. package/templates/nimbus/src/content/docs/writing.mdx +35 -0
  57. package/templates/nimbus/src/content/docs/zh/get-started.mdx +36 -0
  58. package/templates/nimbus/src/content/docs/zh/index.mdx +16 -0
  59. package/templates/nimbus/src/content/docs/zh/writing.mdx +35 -0
  60. package/templates/nimbus/src/content.config.ts +6 -0
  61. package/templates/nimbus/src/env.d.ts +6 -0
  62. package/templates/nimbus/src/layouts/docs.astro +70 -0
  63. package/templates/nimbus/src/lib/locale.ts +50 -0
  64. package/templates/nimbus/src/pages/[...slug]/index.md.ts +4 -0
  65. package/templates/nimbus/src/pages/[...slug]/index.mdx.ts +4 -0
  66. package/templates/nimbus/src/pages/[...slug].astro +36 -0
  67. package/templates/nimbus/src/pages/[section]/llms.txt.ts +4 -0
  68. package/templates/nimbus/src/pages/llms-full.txt.ts +4 -0
  69. package/templates/nimbus/src/pages/llms.txt.ts +4 -0
  70. package/templates/nimbus/src/pages/robots.txt.ts +18 -0
  71. package/templates/nimbus/src/styles/base.css +121 -0
  72. package/templates/nimbus/src/styles/site.css +186 -0
  73. package/templates/nimbus/stylelint.config.js +3 -0
  74. package/templates/nimbus/tsconfig.json +10 -0
  75. package/templates/react-lib/LICENSE +21 -0
  76. package/templates/react-lib/README.md +52 -0
  77. package/templates/react-lib/eslint.config.js +5 -0
  78. package/templates/react-lib/gitignore +4 -0
  79. package/templates/react-lib/package.json +48 -0
  80. package/templates/react-lib/src/counter.tsx +28 -0
  81. package/templates/react-lib/src/index.ts +2 -0
  82. package/templates/react-lib/src/style.css +36 -0
  83. package/templates/react-lib/stylelint.config.js +3 -0
  84. package/templates/react-lib/test/counter.test.tsx +28 -0
  85. package/templates/react-lib/test-d/index.test-d.ts +11 -0
  86. package/templates/react-lib/tsconfig.app.json +15 -0
  87. package/templates/react-lib/tsconfig.build.json +12 -0
  88. package/templates/react-lib/tsconfig.json +4 -0
  89. package/templates/react-lib/tsconfig.node.json +11 -0
  90. package/templates/react-lib/vite.config.ts +22 -0
  91. package/templates/react-lib/vitest.config.ts +5 -0
  92. package/templates/react-vite/README.md +27 -0
  93. package/templates/react-vite/eslint.config.js +5 -0
  94. package/templates/react-vite/gitignore +6 -0
  95. package/templates/react-vite/index.html +13 -0
  96. package/templates/react-vite/package.json +36 -0
  97. package/templates/react-vite/src/app.tsx +22 -0
  98. package/templates/react-vite/src/main.tsx +15 -0
  99. package/templates/react-vite/src/style.css +95 -0
  100. package/templates/react-vite/stylelint.config.js +3 -0
  101. package/templates/react-vite/test/app.test.tsx +22 -0
  102. package/templates/react-vite/tsconfig.app.json +26 -0
  103. package/templates/react-vite/tsconfig.json +11 -0
  104. package/templates/react-vite/tsconfig.node.json +18 -0
  105. package/templates/react-vite/vite.config.ts +6 -0
  106. package/templates/react-vite/vitest.config.ts +9 -0
  107. package/templates/server/package.json +1 -1
  108. package/templates/vitepress/.vitepress/config.ts +4 -5
  109. package/templates/vitepress/.vitepress/home/content.ts +2 -2
  110. package/templates/vitepress/.vitepress/home/faq.ts +16 -0
  111. package/templates/vitepress/.vitepress/mermaid/markdown.ts +18 -0
  112. package/templates/vitepress/.vitepress/mermaid/mermaid.vue +66 -0
  113. package/templates/vitepress/.vitepress/mermaid/render.ts +37 -0
  114. package/templates/vitepress/.vitepress/navigation/routes.ts +7 -0
  115. package/templates/vitepress/.vitepress/seo.ts +12 -1
  116. package/templates/vitepress/.vitepress/theme/components/HomePage.vue +2 -16
  117. package/templates/vitepress/.vitepress/theme/index.ts +3 -1
  118. package/templates/vitepress/ai/create.md +1 -1
  119. package/templates/vitepress/package.json +4 -8
  120. package/templates/vitepress/reference/artifacts.md +51 -0
  121. package/templates/vitepress/reference/commands.md +152 -3
  122. package/templates/vitepress/reference/config.md +101 -7
  123. package/templates/vitepress/reference/dependencies.md +116 -0
  124. package/templates/vitepress/reference/dependency-admission.md +67 -0
  125. package/templates/vitepress/reference/devcontainer.md +25 -0
  126. package/templates/vitepress/reference/index.md +1 -0
  127. package/templates/vitepress/reference/install-security.md +51 -0
  128. package/templates/vitepress/reference/knip.md +55 -0
  129. package/templates/vitepress/reference/move.md +39 -0
  130. package/templates/vitepress/reference/organization-presets.md +89 -0
  131. package/templates/vitepress/reference/removal.md +42 -0
  132. package/templates/vitepress/reference/template-assets.md +40 -1
  133. package/templates/vitepress/reference/templates.md +376 -9
  134. package/templates/vitepress/start/diagnose.md +19 -2
  135. package/templates/vitepress/tasks/checks.md +149 -1
  136. package/templates/vitepress/tasks/ci.md +93 -1
  137. package/templates/vitepress/tasks/index.md +1 -1
  138. package/templates/vitepress/tasks/release.md +72 -6
  139. package/templates/vitepress/test/mermaid.test.ts +39 -0
  140. package/templates/vitepress/test/render.test.ts +48 -0
  141. package/templates/vitepress/test/seo.test.ts +19 -0
  142. package/templates/vitepress/tsconfig.json +8 -8
  143. package/templates/vitepress/vitest.config.ts +8 -0
  144. package/templates/vitepress/zh/ai/create.md +1 -1
  145. package/templates/vitepress/zh/learn/monorepo/manage.md +1 -1
  146. package/templates/vitepress/zh/reference/artifacts.md +51 -0
  147. package/templates/vitepress/zh/reference/commands.md +151 -3
  148. package/templates/vitepress/zh/reference/config.md +94 -2
  149. package/templates/vitepress/zh/reference/dependencies.md +116 -0
  150. package/templates/vitepress/zh/reference/dependency-admission.md +67 -0
  151. package/templates/vitepress/zh/reference/devcontainer.md +25 -0
  152. package/templates/vitepress/zh/reference/execution-model.md +1 -1
  153. package/templates/vitepress/zh/reference/index.md +1 -0
  154. package/templates/vitepress/zh/reference/install-security.md +51 -0
  155. package/templates/vitepress/zh/reference/knip.md +55 -0
  156. package/templates/vitepress/zh/reference/move.md +39 -0
  157. package/templates/vitepress/zh/reference/organization-presets.md +89 -0
  158. package/templates/vitepress/zh/reference/removal.md +42 -0
  159. package/templates/vitepress/zh/reference/template-assets.md +22 -6
  160. package/templates/vitepress/zh/reference/templates.md +356 -9
  161. package/templates/vitepress/zh/start/diagnose.md +24 -13
  162. package/templates/vitepress/zh/tasks/checks.md +150 -0
  163. package/templates/vitepress/zh/tasks/ci.md +93 -1
  164. package/templates/vitepress/zh/tasks/index.md +1 -1
  165. package/templates/vitepress/zh/tasks/release.md +72 -6
  166. package/templates/vitepress/zh/tasks/reports.md +1 -1
  167. package/templates/vue-lib/package.json +1 -1
@@ -0,0 +1,36 @@
1
+ ---
2
+ import { getDocsPage, getDocsStaticPaths, getSidebar, getTOC, stripBase } from '@cloudflare/nimbus-docs/runtime'
3
+ import { components } from '../components'
4
+ import DocsLayout from '../layouts/docs.astro'
5
+ import { alternatePath, isChinese, localizeSidebar } from '../lib/locale'
6
+
7
+ export const prerender = true
8
+ export const getStaticPaths = getDocsStaticPaths
9
+
10
+ const page = await getDocsPage(Astro)
11
+ if (page instanceof Response) {
12
+ return page
13
+ }
14
+ const { entry, Content, headings, markdownUrl } = page
15
+ const pathname = stripBase(Astro.url.pathname, import.meta.env.BASE_URL)
16
+ const chinese = isChinese(pathname)
17
+ const sidebar = localizeSidebar(await getSidebar(pathname), chinese)
18
+ const toc = entry.data.tableOfContents === false ? false : getTOC(headings, entry.data.tableOfContents)
19
+ ---
20
+
21
+ <DocsLayout
22
+ title={entry.data.title}
23
+ description={entry.data.description}
24
+ sidebar={entry.data.sidebar === false ? false : sidebar}
25
+ headings={toc}
26
+ markdownUrl={markdownUrl}
27
+ collection={entry.collection}
28
+ entryId={entry.id}
29
+ noindex={entry.data.noindex}
30
+ draft={entry.data.draft}
31
+ searchable={entry.data.searchable}
32
+ chinese={chinese}
33
+ alternate={alternatePath(pathname)}
34
+ >
35
+ <Content components={components} />
36
+ </DocsLayout>
@@ -0,0 +1,4 @@
1
+ import { llmsSectionRoute } from '@cloudflare/nimbus-docs/agent-endpoints'
2
+
3
+ export const prerender = true
4
+ export const { GET, getStaticPaths } = llmsSectionRoute()
@@ -0,0 +1,4 @@
1
+ import { llmsFullRoute } from '@cloudflare/nimbus-docs/agent-endpoints'
2
+
3
+ export const prerender = true
4
+ export const { GET } = llmsFullRoute()
@@ -0,0 +1,4 @@
1
+ import { llmsRoute } from '@cloudflare/nimbus-docs/agent-endpoints'
2
+
3
+ export const prerender = true
4
+ export const { GET } = llmsRoute()
@@ -0,0 +1,18 @@
1
+ import { withBase } from '@cloudflare/nimbus-docs/runtime'
2
+ import { config } from 'virtual:nimbus/config'
3
+
4
+ export const prerender = true
5
+
6
+ export function GET() {
7
+ const body = [
8
+ 'User-agent: *',
9
+ 'Allow: /',
10
+ '',
11
+ `Sitemap: ${new URL(withBase('/sitemap-index.xml', import.meta.env.BASE_URL), config.site).href}`,
12
+ '',
13
+ ].join('\n')
14
+
15
+ return new Response(body, {
16
+ headers: { 'Content-Type': 'text/plain; charset=utf-8' },
17
+ })
18
+ }
@@ -0,0 +1,121 @@
1
+ @layer base {
2
+ :root {
3
+ font-family: system-ui, sans-serif;
4
+ line-height: 1.7;
5
+ color: var(--ink);
6
+ color-scheme: light dark;
7
+ background: var(--surface);
8
+
9
+ --surface: #fafbfc;
10
+ --ink: #263247;
11
+ --muted: #5d6b80;
12
+ --line: #dce2eb;
13
+ --accent: #1d4ed8;
14
+ --soft: #edf2fc;
15
+ }
16
+
17
+ * {
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ body {
22
+ margin: 0;
23
+ }
24
+
25
+ a {
26
+ color: var(--accent);
27
+ text-underline-offset: 0.2em;
28
+ }
29
+
30
+ a:hover {
31
+ text-decoration-thickness: 2px;
32
+ }
33
+
34
+ :focus-visible {
35
+ outline: 2px solid var(--accent);
36
+ outline-offset: 4px;
37
+ }
38
+
39
+ h1, h2, h3 {
40
+ line-height: 1.25;
41
+ text-wrap: balance;
42
+ }
43
+
44
+ h1 {
45
+ margin: 0 0 1rem;
46
+ font-family: Charter, Georgia, serif;
47
+ font-size: clamp(2.4rem, 5vw, 3.6rem);
48
+ font-weight: 500;
49
+ }
50
+
51
+ h2 {
52
+ margin-top: 2.5rem;
53
+ font-size: 1.5rem;
54
+ }
55
+
56
+ h3 {
57
+ margin-top: 2rem;
58
+ }
59
+
60
+ p, li {
61
+ overflow-wrap: anywhere;
62
+ }
63
+
64
+ code {
65
+ font-family: ui-monospace, monospace;
66
+ font-size: 0.88em;
67
+ }
68
+
69
+ pre {
70
+ padding: 1.2rem;
71
+ overflow: auto;
72
+ border: 1px solid var(--line);
73
+ border-radius: 0.4rem;
74
+ }
75
+
76
+ :not(pre) > code {
77
+ padding: 0.15rem 0.35rem;
78
+ background: var(--soft);
79
+ border-radius: 0.2rem;
80
+ }
81
+
82
+ img {
83
+ max-width: 100%;
84
+ }
85
+
86
+ table {
87
+ display: block;
88
+ overflow-x: auto;
89
+ border-collapse: collapse;
90
+ }
91
+
92
+ td, th {
93
+ padding: 0.6rem 1rem;
94
+ text-align: start;
95
+ border: 1px solid var(--line);
96
+ }
97
+
98
+ button, input {
99
+ font: inherit;
100
+ }
101
+
102
+ button, summary {
103
+ cursor: pointer;
104
+ }
105
+
106
+ button {
107
+ padding: 0.4rem 0.7rem;
108
+ color: var(--surface);
109
+ background: var(--accent);
110
+ border: 0;
111
+ border-radius: 0.3rem;
112
+ }
113
+
114
+ input {
115
+ width: 100%;
116
+ min-width: 0;
117
+ padding: 0.4rem;
118
+ border: 1px solid var(--line);
119
+ border-radius: 0.3rem;
120
+ }
121
+ }
@@ -0,0 +1,186 @@
1
+ @import './base.css';
2
+
3
+ .site-header {
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: space-between;
7
+ min-height: 4.5rem;
8
+ padding: 0.8rem max(1.5rem, calc((100vw - 90rem) / 2));
9
+ border-bottom: 1px solid var(--line);
10
+ }
11
+
12
+ .brand {
13
+ font-weight: 650;
14
+ color: var(--ink);
15
+ text-decoration: none;
16
+ }
17
+
18
+ .language-link {
19
+ font-size: 0.875rem;
20
+ }
21
+
22
+ .docs-grid {
23
+ display: grid;
24
+ grid-template-columns: 15rem minmax(0, 1fr) 12rem;
25
+ gap: 3rem;
26
+ max-width: 90rem;
27
+ padding: 3rem 1.5rem;
28
+ margin: auto;
29
+ }
30
+
31
+ .site-rail, .page-rail {
32
+ font-size: 0.875rem;
33
+ }
34
+
35
+ .rail-title {
36
+ font-size: 0.75rem;
37
+ font-weight: 650;
38
+ color: var(--muted);
39
+ letter-spacing: 0.04em;
40
+ }
41
+
42
+ .navigation-list {
43
+ padding: 0;
44
+ list-style: none;
45
+ }
46
+
47
+ .navigation-list ul {
48
+ padding-left: 1rem;
49
+ }
50
+
51
+ .navigation-list a {
52
+ display: block;
53
+ padding: 0.3rem 0;
54
+ color: var(--muted);
55
+ text-decoration: none;
56
+ }
57
+
58
+ .navigation-list a[aria-current="page"] {
59
+ font-weight: 650;
60
+ color: var(--accent);
61
+ }
62
+
63
+ .navigation-list a:hover {
64
+ color: var(--accent);
65
+ }
66
+
67
+ .index-link {
68
+ display: inline-block;
69
+ margin-top: 2rem;
70
+ font-family: ui-monospace, monospace;
71
+ }
72
+
73
+ main {
74
+ min-width: 0;
75
+ max-width: 48rem;
76
+ }
77
+
78
+ .description {
79
+ margin-bottom: 2.5rem;
80
+ font-size: 1.15rem;
81
+ color: var(--muted);
82
+ }
83
+
84
+ .callout {
85
+ padding: 1rem 1.25rem;
86
+ margin: 1.5rem 0;
87
+ background: var(--soft);
88
+ border-left: 3px solid var(--accent);
89
+ }
90
+
91
+ .callout p:last-child {
92
+ margin-bottom: 0;
93
+ }
94
+
95
+ footer {
96
+ padding-top: 1rem;
97
+ margin-top: 3rem;
98
+ font-size: 0.875rem;
99
+ border-top: 1px solid var(--line);
100
+ }
101
+
102
+ .search-panel {
103
+ margin-bottom: 2rem;
104
+ }
105
+
106
+ .search-panel form {
107
+ margin-top: 1rem;
108
+ }
109
+
110
+ .search-controls {
111
+ display: flex;
112
+ gap: 0.3rem;
113
+ margin-top: 0.5rem;
114
+ }
115
+
116
+ .search-results {
117
+ padding-left: 1.2rem;
118
+ }
119
+
120
+ .search-results li {
121
+ margin-bottom: 0.6rem;
122
+ }
123
+
124
+ .skip-link {
125
+ position: absolute;
126
+ top: -5rem;
127
+ left: 1rem;
128
+ padding: 0.5rem;
129
+ background: var(--surface);
130
+ }
131
+
132
+ .skip-link:focus {
133
+ top: 1rem;
134
+ }
135
+
136
+ @media (max-width: 72rem) {
137
+ .docs-grid {
138
+ grid-template-columns: 13rem minmax(0, 1fr);
139
+ gap: 2rem;
140
+ }
141
+
142
+ .page-rail {
143
+ display: none;
144
+ }
145
+ }
146
+
147
+ @media (max-width: 48rem) {
148
+ .docs-grid {
149
+ grid-template-columns: minmax(0, 1fr);
150
+ padding-top: 1.5rem;
151
+ }
152
+
153
+ .site-rail {
154
+ padding-bottom: 1rem;
155
+ border-bottom: 1px solid var(--line);
156
+ }
157
+
158
+ .site-rail .navigation-list {
159
+ display: flex;
160
+ flex-wrap: wrap;
161
+ gap: 0.5rem 1rem;
162
+ }
163
+
164
+ .site-rail .navigation-list ul {
165
+ padding-left: 0;
166
+ }
167
+
168
+ .index-link {
169
+ margin-top: 0.5rem;
170
+ }
171
+
172
+ .search-panel {
173
+ margin-bottom: 1rem;
174
+ }
175
+ }
176
+
177
+ @media (prefers-color-scheme: dark) {
178
+ :root {
179
+ --surface: #141c2b;
180
+ --ink: #e3eaf5;
181
+ --muted: #a8b6cc;
182
+ --line: #33415a;
183
+ --accent: #97baff;
184
+ --soft: #222f46;
185
+ }
186
+ }
@@ -0,0 +1,3 @@
1
+ import { defineStylelintConfig } from 'repoctl/tooling'
2
+
3
+ export default await defineStylelintConfig()
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "astro/tsconfigs/strict",
3
+ "compilerOptions": {
4
+ "paths": {
5
+ "@/*": ["./src/*"]
6
+ }
7
+ },
8
+ "include": [".astro/types.d.ts", "**/*"],
9
+ "exclude": ["dist"]
10
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ice breaker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,52 @@
1
+ # React component library
2
+
3
+ An ESM-only React 19.3+ component library. `Counter` and `CounterProps` are exported
4
+ from the package root, and styles have an explicit `./style.css` export. React,
5
+ React DOM and their subpaths (including JSX runtimes) remain external to the bundle.
6
+ CommonJS is not a supported entry point.
7
+ The built JavaScript retains `use client`, so Next App Router Server Components
8
+ can import this stateful component directly. Callback props still belong in a
9
+ consumer Client Component.
10
+
11
+ ```tsx
12
+ import type { CounterProps } from 'your-package-name'
13
+ import { Counter } from 'your-package-name'
14
+ import 'your-package-name/style.css'
15
+
16
+ const props: CounterProps = { initialCount: 2, step: 2 }
17
+ export function Example() {
18
+ return <Counter {...props} onCountChange={console.log} />
19
+ }
20
+ ```
21
+
22
+ Install `react` and `react-dom` in the consuming application. Import the stylesheet
23
+ once in its application entry. `sideEffects` preserves CSS during tree shaking;
24
+ JavaScript does not automatically inject styles. `initialCount` initializes the
25
+ local state and supplies the reset value; this component is uncontrolled.
26
+
27
+ Run these commands from the workspace root, replacing the filter if you rename
28
+ the package. Build before running the tests: they import the built package entry.
29
+
30
+ ```bash
31
+ pnpm --filter @icebreakers/react-lib-template build
32
+ pnpm --filter @icebreakers/react-lib-template lint
33
+ pnpm --filter @icebreakers/react-lib-template typecheck
34
+ pnpm --filter @icebreakers/react-lib-template tsd
35
+ pnpm --filter @icebreakers/react-lib-template test
36
+ ```
37
+
38
+ The generated package starts with `private: true`. Before publishing, set your own
39
+ package name and version, remove `private` (or set it to `false`), review the MIT
40
+ license and run `repo package check` from the workspace root. Only `dist`, this
41
+ README, the license and the package manifest are packed. Validate a tarball in a
42
+ separate application before publishing. Storybook can be added independently;
43
+ it is not required to build or consume this library.
44
+
45
+ ## 中文说明
46
+
47
+ 此模板提供 React 19.3+ 的 ESM 组件库,默认目录为 `packages/react-lib`。
48
+ 组件和 props 类型从包根入口导入,样式从 `包名/style.css` 显式导入。
49
+ React、React DOM 和 JSX runtime 不打进库;消费应用需要安装对应 peer 依赖。
50
+ 默认保留 `private: true`,发布前请修改包名、版本和 private,完成上述构建、
51
+ ESLint/Stylelint、类型及行为验证,再执行 `repo package check` 和实际 tarball 消费验证。
52
+ 本模板不声明 CommonJS 支持,Storybook 是可选扩展。
@@ -0,0 +1,5 @@
1
+ import { defineEslintConfig } from 'repoctl/tooling'
2
+
3
+ export default await defineEslintConfig({
4
+ options: { react: true, typescript: true },
5
+ })
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ dist
3
+ coverage
4
+ *.tsbuildinfo
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@icebreakers/react-lib-template",
3
+ "type": "module",
4
+ "version": "0.0.0",
5
+ "private": true,
6
+ "description": "React component library with explicit JavaScript, types and CSS exports",
7
+ "license": "MIT",
8
+ "sideEffects": ["**/*.css"],
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./style.css": "./dist/style.css"
15
+ },
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "files": ["LICENSE", "README.md", "dist"],
19
+ "engines": { "node": ">=22.13.0" },
20
+ "scripts": {
21
+ "build": "vite build",
22
+ "lint": "eslint . && stylelint \"src/**/*.css\"",
23
+ "lint:fix": "eslint . --fix && stylelint \"src/**/*.css\" --fix",
24
+ "typecheck": "tsc -b",
25
+ "tsd": "tsd --files test-d/**/*.test-d.ts",
26
+ "test": "vitest run",
27
+ "test:dev": "vitest"
28
+ },
29
+ "peerDependencies": {
30
+ "react": "^19.3.0",
31
+ "react-dom": "^19.3.0"
32
+ },
33
+ "devDependencies": {
34
+ "@testing-library/dom": "^10.4.2",
35
+ "@testing-library/react": "^16.3.3",
36
+ "@types/react": "^19.3.0",
37
+ "@types/react-dom": "^19.3.0",
38
+ "@vitejs/plugin-react": "^6.1.1",
39
+ "jsdom": "^30.1.1",
40
+ "react": "^19.3.0",
41
+ "react-dom": "^19.3.0",
42
+ "tsd": "^0.33.0",
43
+ "typescript": "~6.0.3",
44
+ "vite": "^8.3.2",
45
+ "vite-plugin-dts": "^5.1.1",
46
+ "vitest": "~5.0.3"
47
+ }
48
+ }
@@ -0,0 +1,28 @@
1
+ import { useState } from 'react'
2
+ import './style.css'
3
+
4
+ export interface CounterProps {
5
+ /** Accessible name for this counter's current value. */
6
+ label?: string
7
+ /** Initial value, also used by the reset action. */
8
+ initialCount?: number
9
+ step?: number
10
+ disabled?: boolean
11
+ onCountChange?: (count: number) => void
12
+ }
13
+
14
+ export function Counter({ label = 'Count', initialCount = 0, step = 1, disabled = false, onCountChange }: CounterProps) {
15
+ const [count, setCount] = useState(initialCount)
16
+ function update(next: number) {
17
+ setCount(next)
18
+ onCountChange?.(next)
19
+ }
20
+
21
+ return (
22
+ <div className="repoctl-counter">
23
+ <output aria-label={label} aria-live="polite">{count}</output>
24
+ <button type="button" disabled={disabled} onClick={() => update(count + step)}>Increase</button>
25
+ <button type="button" disabled={disabled || count === initialCount} onClick={() => update(initialCount)}>Reset</button>
26
+ </div>
27
+ )
28
+ }
@@ -0,0 +1,2 @@
1
+ export { Counter } from './counter.js'
2
+ export type { CounterProps } from './counter.js'
@@ -0,0 +1,36 @@
1
+ .repoctl-counter {
2
+ display: inline-flex;
3
+ gap: 0.75rem;
4
+ align-items: center;
5
+ padding: 1rem;
6
+ font: inherit;
7
+ color: #14283a;
8
+ border: 1px solid #ccd4dc;
9
+ border-radius: 0.75rem;
10
+ }
11
+
12
+ .repoctl-counter output {
13
+ min-width: 2ch;
14
+ font-variant-numeric: tabular-nums;
15
+ text-align: center;
16
+ }
17
+
18
+ .repoctl-counter button {
19
+ padding: 0.5rem 0.75rem;
20
+ font: inherit;
21
+ color: #fff;
22
+ cursor: pointer;
23
+ background: #14283a;
24
+ border: 0;
25
+ border-radius: 0.375rem;
26
+ }
27
+
28
+ .repoctl-counter button:focus-visible {
29
+ outline: 2px solid #176bb4;
30
+ outline-offset: 3px;
31
+ }
32
+
33
+ .repoctl-counter button:disabled {
34
+ cursor: default;
35
+ opacity: 0.5;
36
+ }
@@ -0,0 +1,3 @@
1
+ import { defineStylelintConfig } from 'repoctl/tooling'
2
+
3
+ export default await defineStylelintConfig()
@@ -0,0 +1,28 @@
1
+ import { cleanup, fireEvent, render, screen } from '@testing-library/react'
2
+ import { afterEach, expect, it, vi } from 'vitest'
3
+ import { Counter } from '..'
4
+
5
+ afterEach(cleanup)
6
+
7
+ it('uses the built public entry to update, notify and reset the initial value', () => {
8
+ const onCountChange = vi.fn()
9
+ render(<Counter label="Items" initialCount={3} step={2} onCountChange={onCountChange} />)
10
+ const count = screen.getByLabelText('Items')
11
+ const reset = screen.getByRole('button', { name: 'Reset' })
12
+ expect(count.textContent).toBe('3')
13
+ expect(reset.hasAttribute('disabled')).toBe(true)
14
+ fireEvent.click(screen.getByRole('button', { name: 'Increase' }))
15
+ expect(count.textContent).toBe('5')
16
+ expect(onCountChange).toHaveBeenLastCalledWith(5)
17
+ fireEvent.click(reset)
18
+ expect(count.textContent).toBe('3')
19
+ expect(onCountChange).toHaveBeenLastCalledWith(3)
20
+ })
21
+
22
+ it('prevents changes when disabled', () => {
23
+ const onCountChange = vi.fn()
24
+ render(<Counter disabled onCountChange={onCountChange} />)
25
+ fireEvent.click(screen.getByRole('button', { name: 'Increase' }))
26
+ expect(screen.getByLabelText('Count').textContent).toBe('0')
27
+ expect(onCountChange).not.toHaveBeenCalled()
28
+ })
@@ -0,0 +1,11 @@
1
+ import type { ComponentProps, ReactElement } from 'react'
2
+ import type { CounterProps } from '..'
3
+ import { createElement } from 'react'
4
+ import { expectAssignable, expectError, expectType } from 'tsd'
5
+ import { Counter } from '..'
6
+
7
+ expectAssignable<CounterProps>({ initialCount: 2, step: 3, onCountChange: count => expectType<number>(count) })
8
+ expectAssignable<ComponentProps<typeof Counter>>({ label: 'Items', disabled: true })
9
+ expectAssignable<ReactElement<CounterProps>>(createElement(Counter, { initialCount: 2 }))
10
+ expectError(createElement(Counter, { initialCount: '2' }))
11
+ expectError(createElement(Counter, { onCountChange: (value: string) => value }))
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5
+ "target": "ES2022",
6
+ "jsx": "react-jsx",
7
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
8
+ "types": ["vite/client"],
9
+ "noUnusedLocals": true,
10
+ "noUnusedParameters": true,
11
+ "verbatimModuleSyntax": true,
12
+ "noUncheckedSideEffectImports": true
13
+ },
14
+ "include": ["src", "test"]
15
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "./tsconfig.app.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "declaration": true,
6
+ "declarationMap": false,
7
+ "emitDeclarationOnly": true,
8
+ "noEmit": false,
9
+ "outDir": "dist"
10
+ },
11
+ "include": ["src"]
12
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }],
3
+ "files": []
4
+ }