@ippon-ui/ui 0.0.2

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 (246) hide show
  1. package/.agents/agents/component-library-create-from-pattern-library.agent.md +37 -0
  2. package/.agents/agents/patten-library-create-component.agent.md +30 -0
  3. package/.agents/skills/component-library/SKILL.md +169 -0
  4. package/.agents/skills/pattern-library/SKILL.md +277 -0
  5. package/.github/workflows/build.yml +34 -0
  6. package/.gitlab-ci.yml +12 -0
  7. package/.prettierignore +6 -0
  8. package/AGENTS.md +50 -0
  9. package/LICENSE +202 -0
  10. package/ci/build.yml +15 -0
  11. package/ci/common.yml +42 -0
  12. package/ci/deploy.yml +20 -0
  13. package/icons/LICENCE +202 -0
  14. package/icons/index.ts +69 -0
  15. package/icons/package.json +25 -0
  16. package/icons/tsconfig.json +11 -0
  17. package/lefthook.yml +10 -0
  18. package/mise.toml +55 -0
  19. package/package.json +26 -0
  20. package/pnpm-workspace.yaml +9 -0
  21. package/prettier.config.mts +8 -0
  22. package/react/LICENCE +202 -0
  23. package/react/README.md +75 -0
  24. package/react/eslint.config.js +22 -0
  25. package/react/package.json +63 -0
  26. package/react/src/CAP.ts +14 -0
  27. package/react/src/Card.ts +2 -0
  28. package/react/src/DataSelectable.ts +7 -0
  29. package/react/src/Grid.ts +33 -0
  30. package/react/src/IpponBadge.tsx +62 -0
  31. package/react/src/IpponButton.tsx +93 -0
  32. package/react/src/IpponButtonCard.tsx +34 -0
  33. package/react/src/IpponCard.tsx +30 -0
  34. package/react/src/IpponContainer.tsx +15 -0
  35. package/react/src/IpponGrid.tsx +56 -0
  36. package/react/src/IpponHSpace.tsx +56 -0
  37. package/react/src/IpponIcon.tsx +15 -0
  38. package/react/src/IpponImportFile.tsx +128 -0
  39. package/react/src/IpponIon.tsx +45 -0
  40. package/react/src/IpponMeter.tsx +43 -0
  41. package/react/src/IpponProgress.tsx +45 -0
  42. package/react/src/IpponText.tsx +56 -0
  43. package/react/src/IpponTitle.tsx +45 -0
  44. package/react/src/IpponVSpace.tsx +43 -0
  45. package/react/src/Optional.ts +177 -0
  46. package/react/src/Tokens.ts +36 -0
  47. package/react/src/index.ts +16 -0
  48. package/react/test/File.fixture.ts +13 -0
  49. package/react/test/IpponBadge.spec.tsx +245 -0
  50. package/react/test/IpponButton.spec.tsx +666 -0
  51. package/react/test/IpponButtonCard.spec.tsx +162 -0
  52. package/react/test/IpponCard.spec.tsx +133 -0
  53. package/react/test/IpponContainer.spec.tsx +56 -0
  54. package/react/test/IpponGrid.spec.tsx +140 -0
  55. package/react/test/IpponHSpace.spec.tsx +107 -0
  56. package/react/test/IpponIcon.spec.tsx +37 -0
  57. package/react/test/IpponImportFile.spec.tsx +431 -0
  58. package/react/test/IpponIon.spec.tsx +52 -0
  59. package/react/test/IpponMeter.spec.tsx +59 -0
  60. package/react/test/IpponProgress.spec.tsx +68 -0
  61. package/react/test/IpponText.spec.tsx +149 -0
  62. package/react/test/IpponTitle.spec.tsx +242 -0
  63. package/react/test/IpponVSpace.spec.tsx +91 -0
  64. package/react/tsconfig.app.json +24 -0
  65. package/react/tsconfig.json +4 -0
  66. package/react/tsconfig.node.json +23 -0
  67. package/react/vite.config.ts +30 -0
  68. package/react/vitest.config.ts +21 -0
  69. package/styles/.editorconfig +12 -0
  70. package/styles/.stylelintrc.json +75 -0
  71. package/styles/LICENCE +202 -0
  72. package/styles/README.md +107 -0
  73. package/styles/logo.svg +26 -0
  74. package/styles/package.json +67 -0
  75. package/styles/src/atom/_atom.scss +9 -0
  76. package/styles/src/atom/atom.pug +34 -0
  77. package/styles/src/atom/badge/_badge.scss +108 -0
  78. package/styles/src/atom/badge/badge.code.pug +29 -0
  79. package/styles/src/atom/badge/badge.md +1 -0
  80. package/styles/src/atom/badge/badge.mixin.pug +24 -0
  81. package/styles/src/atom/badge/badge.render.pug +7 -0
  82. package/styles/src/atom/button/_button.scss +242 -0
  83. package/styles/src/atom/button/button.code.pug +38 -0
  84. package/styles/src/atom/button/button.md +31 -0
  85. package/styles/src/atom/button/button.mixin.pug +30 -0
  86. package/styles/src/atom/button/button.render.pug +13 -0
  87. package/styles/src/atom/icon/_icon.scss +8 -0
  88. package/styles/src/atom/icon/icon.code.pug +5 -0
  89. package/styles/src/atom/icon/icon.md +11 -0
  90. package/styles/src/atom/icon/icon.mixin.pug +8 -0
  91. package/styles/src/atom/icon/icon.render.pug +7 -0
  92. package/styles/src/atom/ion/ion.code.pug +8 -0
  93. package/styles/src/atom/ion/ion.md +11 -0
  94. package/styles/src/atom/ion/ion.mixin.pug +8 -0
  95. package/styles/src/atom/ion/ion.render.pug +7 -0
  96. package/styles/src/atom/meter/_meter.scss +23 -0
  97. package/styles/src/atom/meter/meter.code.pug +8 -0
  98. package/styles/src/atom/meter/meter.md +7 -0
  99. package/styles/src/atom/meter/meter.mixin.pug +12 -0
  100. package/styles/src/atom/meter/meter.render.pug +5 -0
  101. package/styles/src/atom/progress/_progress.scss +23 -0
  102. package/styles/src/atom/progress/progress.code.pug +8 -0
  103. package/styles/src/atom/progress/progress.md +7 -0
  104. package/styles/src/atom/progress/progress.mixin.pug +14 -0
  105. package/styles/src/atom/progress/progress.render.pug +5 -0
  106. package/styles/src/atom/tab/_tab.scss +48 -0
  107. package/styles/src/atom/tab/tab.code.pug +5 -0
  108. package/styles/src/atom/tab/tab.md +1 -0
  109. package/styles/src/atom/tab/tab.mixin.pug +14 -0
  110. package/styles/src/atom/tab/tab.render.pug +4 -0
  111. package/styles/src/atom/text/_text.scss +74 -0
  112. package/styles/src/atom/text/text.code.pug +19 -0
  113. package/styles/src/atom/text/text.md +5 -0
  114. package/styles/src/atom/text/text.mixin.pug +12 -0
  115. package/styles/src/atom/text/text.render.pug +7 -0
  116. package/styles/src/atom/title/_title.scss +68 -0
  117. package/styles/src/atom/title/title.code.pug +25 -0
  118. package/styles/src/atom/title/title.md +9 -0
  119. package/styles/src/atom/title/title.mixin.pug +12 -0
  120. package/styles/src/atom/title/title.render.pug +5 -0
  121. package/styles/src/atom/title-display/_title-display.scss +26 -0
  122. package/styles/src/atom/title-display/title-display.code.pug +9 -0
  123. package/styles/src/atom/title-display/title-display.md +5 -0
  124. package/styles/src/atom/title-display/title-display.mixin.pug +6 -0
  125. package/styles/src/atom/title-display/title-display.render.pug +4 -0
  126. package/styles/src/doc.scss +2 -0
  127. package/styles/src/favicon.ico +0 -0
  128. package/styles/src/function/_conversion.scss +9 -0
  129. package/styles/src/index.pug +59 -0
  130. package/styles/src/layout-documentation.pug +14 -0
  131. package/styles/src/layout.pug +17 -0
  132. package/styles/src/molecule/_molecule.scss +2 -0
  133. package/styles/src/molecule/import-file/_import-file.scss +38 -0
  134. package/styles/src/molecule/import-file/import-file.code.pug +4 -0
  135. package/styles/src/molecule/import-file/import-file.md +1 -0
  136. package/styles/src/molecule/import-file/import-file.mixin.pug +15 -0
  137. package/styles/src/molecule/import-file/import-file.render.pug +5 -0
  138. package/styles/src/molecule/molecule.pug +20 -0
  139. package/styles/src/molecule/tabs/_tabs.scss +4 -0
  140. package/styles/src/molecule/tabs/tabs.code.pug +9 -0
  141. package/styles/src/molecule/tabs/tabs.md +1 -0
  142. package/styles/src/molecule/tabs/tabs.mixin.pug +4 -0
  143. package/styles/src/molecule/tabs/tabs.render.pug +4 -0
  144. package/styles/src/molecule/toggle/_toggle.scss +68 -0
  145. package/styles/src/molecule/toggle/toggle.code.pug +26 -0
  146. package/styles/src/molecule/toggle/toggle.md +1 -0
  147. package/styles/src/molecule/toggle/toggle.mixin.pug +36 -0
  148. package/styles/src/molecule/toggle/toggle.render.pug +5 -0
  149. package/styles/src/organism/_abstract-card.scss +36 -0
  150. package/styles/src/organism/_docorganism.scss +1 -0
  151. package/styles/src/organism/_organism.scss +8 -0
  152. package/styles/src/organism/button-card/_button-card.scss +22 -0
  153. package/styles/src/organism/button-card/button-card.code.pug +31 -0
  154. package/styles/src/organism/button-card/button-card.md +28 -0
  155. package/styles/src/organism/button-card/button-card.mixin.pug +8 -0
  156. package/styles/src/organism/button-card/button-card.render.pug +7 -0
  157. package/styles/src/organism/card/_card.scss +6 -0
  158. package/styles/src/organism/card/card.code.pug +9 -0
  159. package/styles/src/organism/card/card.md +23 -0
  160. package/styles/src/organism/card/card.mixin.pug +7 -0
  161. package/styles/src/organism/card/card.render.pug +7 -0
  162. package/styles/src/organism/container/_container.scss +3 -0
  163. package/styles/src/organism/container/container.code.pug +13 -0
  164. package/styles/src/organism/container/container.md +5 -0
  165. package/styles/src/organism/container/container.mixin.pug +3 -0
  166. package/styles/src/organism/container/container.render.pug +4 -0
  167. package/styles/src/organism/grid/_docgrid.scss +11 -0
  168. package/styles/src/organism/grid/_grid.scss +84 -0
  169. package/styles/src/organism/grid/grid.code.pug +25 -0
  170. package/styles/src/organism/grid/grid.md +1 -0
  171. package/styles/src/organism/grid/grid.mixin.pug +7 -0
  172. package/styles/src/organism/grid/grid.render.pug +5 -0
  173. package/styles/src/organism/h-space/_h-space.scss +49 -0
  174. package/styles/src/organism/h-space/h-space.code.pug +56 -0
  175. package/styles/src/organism/h-space/h-space.md +22 -0
  176. package/styles/src/organism/h-space/h-space.mixin.pug +14 -0
  177. package/styles/src/organism/h-space/h-space.render.pug +5 -0
  178. package/styles/src/organism/header/_header.scss +8 -0
  179. package/styles/src/organism/header/header.code.pug +14 -0
  180. package/styles/src/organism/header/header.md +1 -0
  181. package/styles/src/organism/header/header.mixin.pug +7 -0
  182. package/styles/src/organism/header/header.render.pug +4 -0
  183. package/styles/src/organism/modal/_modal.scss +58 -0
  184. package/styles/src/organism/modal/modal.code.pug +68 -0
  185. package/styles/src/organism/modal/modal.md +1 -0
  186. package/styles/src/organism/modal/modal.mixin.pug +25 -0
  187. package/styles/src/organism/modal/modal.render.pug +4 -0
  188. package/styles/src/organism/organism.pug +30 -0
  189. package/styles/src/organism/v-space/_v-space.scss +45 -0
  190. package/styles/src/organism/v-space/v-space.code.pug +41 -0
  191. package/styles/src/organism/v-space/v-space.md +20 -0
  192. package/styles/src/organism/v-space/v-space.mixin.pug +7 -0
  193. package/styles/src/organism/v-space/v-space.render.pug +5 -0
  194. package/styles/src/quark/_breakpoint.scss +12 -0
  195. package/styles/src/quark/_font.scss +38 -0
  196. package/styles/src/quark/_gap.scss +34 -0
  197. package/styles/src/quark/_placeholder.scss +27 -0
  198. package/styles/src/quark/_shadow.scss +13 -0
  199. package/styles/src/quark/_typography.scss +146 -0
  200. package/styles/src/template/_template.scss +1 -0
  201. package/styles/src/template/layout/_layout.scss +20 -0
  202. package/styles/src/template/layout/layout.code.pug +11 -0
  203. package/styles/src/template/layout/layout.md +1 -0
  204. package/styles/src/template/layout/layout.mixin.pug +11 -0
  205. package/styles/src/template/layout/layout.render.pug +4 -0
  206. package/styles/src/template/template.pug +16 -0
  207. package/styles/src/tikui.scss +5 -0
  208. package/styles/src/token/_doctable.scss +14 -0
  209. package/styles/src/token/_doctoken.scss +1 -0
  210. package/styles/src/token/_size.scss +9 -0
  211. package/styles/src/token/_token.scss +5 -0
  212. package/styles/src/token/color/_color.scss +9 -0
  213. package/styles/src/token/color/color/_base.scss +65 -0
  214. package/styles/src/token/color/color/_brand.scss +13 -0
  215. package/styles/src/token/color/color/_error.scss +13 -0
  216. package/styles/src/token/color/color/_information-2.scss +13 -0
  217. package/styles/src/token/color/color/_information.scss +13 -0
  218. package/styles/src/token/color/color/_neutral.scss +20 -0
  219. package/styles/src/token/color/color/_semantic.scss +69 -0
  220. package/styles/src/token/color/color/_success.scss +13 -0
  221. package/styles/src/token/color/color/_warning.scss +13 -0
  222. package/styles/src/token/color/color.js +31 -0
  223. package/styles/src/token/color/color.mixin.pug +19 -0
  224. package/styles/src/token/color/color.pug +9 -0
  225. package/styles/src/token/color/color.render.pug +13 -0
  226. package/styles/src/token/radius/_radius.scss +8 -0
  227. package/styles/src/token/radius/radius.js +54 -0
  228. package/styles/src/token/radius/radius.mixin.pug +14 -0
  229. package/styles/src/token/radius/radius.pug +9 -0
  230. package/styles/src/token/radius/radius.render.pug +11 -0
  231. package/styles/src/token/shadow/_shadow.scss +22 -0
  232. package/styles/src/token/shadow/shadow.js +45 -0
  233. package/styles/src/token/shadow/shadow.mixin.pug +13 -0
  234. package/styles/src/token/shadow/shadow.pug +9 -0
  235. package/styles/src/token/shadow/shadow.render.pug +9 -0
  236. package/styles/src/token/token.js +38 -0
  237. package/styles/src/token/token.pug +25 -0
  238. package/styles/src/token/typography/_typography.scss +103 -0
  239. package/styles/src/token/typography/typography.js +32 -0
  240. package/styles/src/token/typography/typography.mixin.pug +17 -0
  241. package/styles/src/token/typography/typography.pug +9 -0
  242. package/styles/src/token/typography/typography.render.pug +19 -0
  243. package/styles/test/function/conversion.test.scss +20 -0
  244. package/styles/test/function/sass.spec.ts +6 -0
  245. package/styles/tikuiconfig.json +14 -0
  246. package/styles/tsconfig.json +10 -0
@@ -0,0 +1,149 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { render, screen, configure, cleanup } from '@testing-library/react';
3
+ import '@testing-library/jest-dom/vitest';
4
+ import { IpponText } from '../src';
5
+
6
+ configure({
7
+ testIdAttribute: 'data-selector',
8
+ });
9
+
10
+ const expectToHaveClasses = (...classes: string[]) => {
11
+ const ipponText = screen.getByTestId('ippon-text');
12
+
13
+ expect(ipponText).toHaveClass('ippon-text', ...classes);
14
+ };
15
+
16
+ describe('IpponText', () => {
17
+ beforeEach(cleanup);
18
+
19
+ describe('Body', () => {
20
+ describe('Medium', () => {
21
+ it('should be minimal', () => {
22
+ render(
23
+ <IpponText variant="body" dataSelector="ippon-text">
24
+ Content
25
+ </IpponText>,
26
+ );
27
+
28
+ expectToHaveClasses('-body');
29
+ });
30
+
31
+ it('should be bold', () => {
32
+ render(
33
+ <IpponText variant="body" weight="bold" dataSelector="ippon-text">
34
+ Content
35
+ </IpponText>,
36
+ );
37
+
38
+ expectToHaveClasses('-body', '-bold');
39
+ });
40
+ });
41
+ describe('Small', () => {
42
+ it('should be minimal', () => {
43
+ render(
44
+ <IpponText variant="body" size="small" dataSelector="ippon-text">
45
+ Content
46
+ </IpponText>,
47
+ );
48
+
49
+ expectToHaveClasses('-body', '-small');
50
+ });
51
+
52
+ it('should be bold', () => {
53
+ render(
54
+ <IpponText variant="body" weight="bold" size="small" dataSelector="ippon-text">
55
+ Content
56
+ </IpponText>,
57
+ );
58
+
59
+ expectToHaveClasses('-body', '-bold', '-small');
60
+ });
61
+ });
62
+
63
+ describe('Large', () => {
64
+ it('should be minimal', () => {
65
+ render(
66
+ <IpponText variant="body" size="large" dataSelector="ippon-text">
67
+ Content
68
+ </IpponText>,
69
+ );
70
+
71
+ expectToHaveClasses('-body', '-large');
72
+ });
73
+
74
+ it('should be bold', () => {
75
+ render(
76
+ <IpponText variant="body" weight="bold" size="large" dataSelector="ippon-text">
77
+ Content
78
+ </IpponText>,
79
+ );
80
+
81
+ expectToHaveClasses('-body', '-bold', '-large');
82
+ });
83
+ });
84
+ });
85
+
86
+ describe('Label', () => {
87
+ it('should be medium', () => {
88
+ render(
89
+ <IpponText variant="label" dataSelector="ippon-text">
90
+ Content
91
+ </IpponText>,
92
+ );
93
+
94
+ expectToHaveClasses('-label');
95
+ });
96
+
97
+ it('should be small', () => {
98
+ render(
99
+ <IpponText variant="label" size="small" dataSelector="ippon-text">
100
+ Content
101
+ </IpponText>,
102
+ );
103
+
104
+ expectToHaveClasses('-label', '-small');
105
+ });
106
+
107
+ it('should be large', () => {
108
+ render(
109
+ <IpponText variant="label" size="large" dataSelector="ippon-text">
110
+ Content
111
+ </IpponText>,
112
+ );
113
+
114
+ expectToHaveClasses('-label', '-large');
115
+ });
116
+ });
117
+
118
+ describe('Placeholder', () => {
119
+ it('should display placeholder class for body variant', () => {
120
+ render(
121
+ <IpponText variant="body" placeholder dataSelector="ippon-text">
122
+ Content
123
+ </IpponText>,
124
+ );
125
+
126
+ expectToHaveClasses('-body', '-placeholder');
127
+ });
128
+
129
+ it('should display placeholder class for label variant', () => {
130
+ render(
131
+ <IpponText variant="label" placeholder dataSelector="ippon-text">
132
+ Content
133
+ </IpponText>,
134
+ );
135
+
136
+ expectToHaveClasses('-label', '-placeholder');
137
+ });
138
+
139
+ it('should display placeholder with size modifier for body variant', () => {
140
+ render(
141
+ <IpponText variant="body" size="large" placeholder dataSelector="ippon-text">
142
+ Content
143
+ </IpponText>,
144
+ );
145
+
146
+ expectToHaveClasses('-body', '-large', '-placeholder');
147
+ });
148
+ });
149
+ });
@@ -0,0 +1,242 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { render, screen, configure, cleanup } from '@testing-library/react';
3
+ import '@testing-library/jest-dom/vitest';
4
+ import { IpponTitle } from '../src';
5
+
6
+ configure({
7
+ testIdAttribute: 'data-selector',
8
+ });
9
+
10
+ describe('IpponTitle', () => {
11
+ beforeEach(cleanup);
12
+
13
+ describe('HTML Tags', () => {
14
+ it('should render as div by default', () => {
15
+ render(
16
+ <IpponTitle level={1} dataSelector="ippon-title">
17
+ Title
18
+ </IpponTitle>,
19
+ );
20
+ const title = screen.getByTestId('ippon-title');
21
+ expect(title.tagName).toBe('DIV');
22
+ expect(title).toHaveClass('ippon-title');
23
+ });
24
+
25
+ it('should render as h1 when specified', () => {
26
+ render(
27
+ <IpponTitle tag="h1" dataSelector="ippon-title">
28
+ Title
29
+ </IpponTitle>,
30
+ );
31
+ const title = screen.getByTestId('ippon-title');
32
+ expect(title.tagName).toBe('H1');
33
+ expect(title).toHaveClass('ippon-title');
34
+ });
35
+
36
+ it('should render as h2 when specified', () => {
37
+ render(
38
+ <IpponTitle tag="h2" dataSelector="ippon-title">
39
+ Title
40
+ </IpponTitle>,
41
+ );
42
+ const title = screen.getByTestId('ippon-title');
43
+ expect(title.tagName).toBe('H2');
44
+ expect(title).toHaveClass('ippon-title');
45
+ });
46
+
47
+ it('should render as h3 when specified', () => {
48
+ render(
49
+ <IpponTitle tag="h3" dataSelector="ippon-title">
50
+ Title
51
+ </IpponTitle>,
52
+ );
53
+ const title = screen.getByTestId('ippon-title');
54
+ expect(title.tagName).toBe('H3');
55
+ expect(title).toHaveClass('ippon-title');
56
+ });
57
+
58
+ it('should render as h4 when specified', () => {
59
+ render(
60
+ <IpponTitle tag="h4" dataSelector="ippon-title">
61
+ Title
62
+ </IpponTitle>,
63
+ );
64
+ const title = screen.getByTestId('ippon-title');
65
+ expect(title.tagName).toBe('H4');
66
+ expect(title).toHaveClass('ippon-title');
67
+ });
68
+
69
+ it('should render as h5 when specified', () => {
70
+ render(
71
+ <IpponTitle tag="h5" dataSelector="ippon-title">
72
+ Title
73
+ </IpponTitle>,
74
+ );
75
+ const title = screen.getByTestId('ippon-title');
76
+ expect(title.tagName).toBe('H5');
77
+ expect(title).toHaveClass('ippon-title');
78
+ });
79
+
80
+ it('should render as p when specified with level', () => {
81
+ render(
82
+ <IpponTitle tag="p" level={1} dataSelector="ippon-title">
83
+ Title
84
+ </IpponTitle>,
85
+ );
86
+ const title = screen.getByTestId('ippon-title');
87
+ expect(title.tagName).toBe('P');
88
+ expect(title).toHaveClass('ippon-title');
89
+ });
90
+
91
+ it('should render as span when specified with level', () => {
92
+ render(
93
+ <IpponTitle tag="span" level={2} dataSelector="ippon-title">
94
+ Title
95
+ </IpponTitle>,
96
+ );
97
+ const title = screen.getByTestId('ippon-title');
98
+ expect(title.tagName).toBe('SPAN');
99
+ expect(title).toHaveClass('ippon-title');
100
+ });
101
+
102
+ it('should render as h6 when specified with level', () => {
103
+ render(
104
+ <IpponTitle tag="h6" level={3} dataSelector="ippon-title">
105
+ Title
106
+ </IpponTitle>,
107
+ );
108
+ const title = screen.getByTestId('ippon-title');
109
+ expect(title.tagName).toBe('H6');
110
+ expect(title).toHaveClass('ippon-title');
111
+ });
112
+ });
113
+
114
+ describe('Level Variants', () => {
115
+ it('should not have level class when level is not specified with heading tag', () => {
116
+ render(
117
+ <IpponTitle tag="h1" dataSelector="ippon-title">
118
+ Title
119
+ </IpponTitle>,
120
+ );
121
+ const title = screen.getByTestId('ippon-title');
122
+ expect(title).toHaveClass('ippon-title');
123
+ expect(title.className).not.toMatch(/-l\d/);
124
+ });
125
+
126
+ it('should have level 1 class with div', () => {
127
+ render(
128
+ <IpponTitle level={1} dataSelector="ippon-title">
129
+ Title
130
+ </IpponTitle>,
131
+ );
132
+ const title = screen.getByTestId('ippon-title');
133
+ expect(title).toHaveClass('ippon-title', '-l1');
134
+ });
135
+
136
+ it('should have level 1 class with heading tag', () => {
137
+ render(
138
+ <IpponTitle tag="h2" level={1} dataSelector="ippon-title">
139
+ Title
140
+ </IpponTitle>,
141
+ );
142
+ const title = screen.getByTestId('ippon-title');
143
+ expect(title).toHaveClass('ippon-title', '-l1');
144
+ });
145
+
146
+ it('should have level 2 class', () => {
147
+ render(
148
+ <IpponTitle level={2} dataSelector="ippon-title">
149
+ Title
150
+ </IpponTitle>,
151
+ );
152
+ const title = screen.getByTestId('ippon-title');
153
+ expect(title).toHaveClass('ippon-title', '-l2');
154
+ });
155
+
156
+ it('should have level 3 class', () => {
157
+ render(
158
+ <IpponTitle level={3} dataSelector="ippon-title">
159
+ Title
160
+ </IpponTitle>,
161
+ );
162
+ const title = screen.getByTestId('ippon-title');
163
+ expect(title).toHaveClass('ippon-title', '-l3');
164
+ });
165
+
166
+ it('should have level 4 class', () => {
167
+ render(
168
+ <IpponTitle level={4} dataSelector="ippon-title">
169
+ Title
170
+ </IpponTitle>,
171
+ );
172
+ const title = screen.getByTestId('ippon-title');
173
+ expect(title).toHaveClass('ippon-title', '-l4');
174
+ });
175
+
176
+ it('should have level 5 class', () => {
177
+ render(
178
+ <IpponTitle level={5} dataSelector="ippon-title">
179
+ Title
180
+ </IpponTitle>,
181
+ );
182
+ const title = screen.getByTestId('ippon-title');
183
+ expect(title).toHaveClass('ippon-title', '-l5');
184
+ });
185
+ });
186
+
187
+ describe('Placeholder', () => {
188
+ it('should have placeholder class when enabled with div', () => {
189
+ render(
190
+ <IpponTitle level={1} placeholder dataSelector="ippon-title">
191
+ Title
192
+ </IpponTitle>,
193
+ );
194
+ const title = screen.getByTestId('ippon-title');
195
+ expect(title).toHaveClass('ippon-title', '-l1', '-placeholder');
196
+ });
197
+
198
+ it('should have placeholder class with level modifier and heading tag', () => {
199
+ render(
200
+ <IpponTitle tag="h2" level={2} placeholder dataSelector="ippon-title">
201
+ Title
202
+ </IpponTitle>,
203
+ );
204
+ const title = screen.getByTestId('ippon-title');
205
+ expect(title).toHaveClass('ippon-title', '-l2', '-placeholder');
206
+ });
207
+ });
208
+
209
+ describe('Children Rendering', () => {
210
+ it('should render children content', () => {
211
+ render(
212
+ <IpponTitle level={1} dataSelector="ippon-title">
213
+ My Title Content
214
+ </IpponTitle>,
215
+ );
216
+ const title = screen.getByTestId('ippon-title');
217
+ expect(title).toHaveTextContent('My Title Content');
218
+ });
219
+
220
+ it('should render react elements as children', () => {
221
+ render(
222
+ <IpponTitle level={1} dataSelector="ippon-title">
223
+ <span>Title with span</span>
224
+ </IpponTitle>,
225
+ );
226
+ const title = screen.getByTestId('ippon-title');
227
+ expect(title.querySelector('span')).toHaveTextContent('Title with span');
228
+ });
229
+ });
230
+
231
+ describe('Data Selector', () => {
232
+ it('should bind data-selector attribute', () => {
233
+ render(
234
+ <IpponTitle level={1} dataSelector="my-custom-selector">
235
+ Title
236
+ </IpponTitle>,
237
+ );
238
+ const title = screen.getByTestId('my-custom-selector');
239
+ expect(title).toBeInTheDocument();
240
+ });
241
+ });
242
+ });
@@ -0,0 +1,91 @@
1
+ import { cleanup, configure, render, screen } from '@testing-library/react';
2
+ import { afterEach, describe, expect, it } from 'vitest';
3
+ import '@testing-library/jest-dom/vitest';
4
+ import { IpponVSpace } from '../src';
5
+ import { IpponVSpaceSlot } from '../src/IpponVSpace.tsx';
6
+
7
+ configure({
8
+ testIdAttribute: 'data-selector',
9
+ });
10
+
11
+ describe('IpponVSpace', () => {
12
+ afterEach(cleanup);
13
+
14
+ it('should be like pattern library', () => {
15
+ render(<IpponVSpace dataSelector="ippon-v-space">Content</IpponVSpace>);
16
+
17
+ const ipponVSpace = screen.getByTestId('ippon-v-space');
18
+
19
+ expect(ipponVSpace).toHaveClass('ippon-v-space');
20
+ });
21
+
22
+ it.each([2, 16, 32] as const)('should have gap %s', (gap) => {
23
+ render(<IpponVSpace gap={gap} dataSelector="ippon-v-space" />);
24
+
25
+ const ipponVSpace = screen.getByTestId('ippon-v-space');
26
+
27
+ expect(ipponVSpace).toHaveClass(`-gap-${gap}`);
28
+ });
29
+
30
+ it.each(['left', 'right', 'justify', 'center'] as const)(
31
+ 'should have alignment %s',
32
+ (alignment) => {
33
+ render(<IpponVSpace align={alignment} dataSelector="ippon-v-space" />);
34
+
35
+ const ipponVSpace = screen.getByTestId('ippon-v-space');
36
+
37
+ expect(ipponVSpace).toHaveClass(`-${alignment}`);
38
+ },
39
+ );
40
+
41
+ it('should render with default div tag', () => {
42
+ render(<IpponVSpace dataSelector="ippon-v-space">Content</IpponVSpace>);
43
+
44
+ const ipponVSpace = screen.getByTestId('ippon-v-space');
45
+
46
+ expect(ipponVSpace.tagName).toBe('DIV');
47
+ });
48
+
49
+ it('should render with custom tag', () => {
50
+ render(
51
+ <IpponVSpace tag="section" dataSelector="ippon-v-space">
52
+ Content
53
+ </IpponVSpace>,
54
+ );
55
+
56
+ const ipponVSpace = screen.getByTestId('ippon-v-space');
57
+
58
+ expect(ipponVSpace.tagName).toBe('SECTION');
59
+ });
60
+
61
+ describe('Slot', () => {
62
+ it('shouldbe minimal', () => {
63
+ render(
64
+ <IpponVSpace>
65
+ <IpponVSpaceSlot dataSelector="ippon-v-space-slot">Slot</IpponVSpaceSlot>
66
+ </IpponVSpace>,
67
+ );
68
+
69
+ const ipponVSpaceSlot = screen.getByTestId('ippon-v-space-slot');
70
+
71
+ expect(ipponVSpaceSlot).toHaveClass('ippon-v-space--slot');
72
+ });
73
+
74
+ it.each(['left', 'right', 'justify', 'center'] as const)(
75
+ 'should have alignment %s',
76
+ (alignment) => {
77
+ render(
78
+ <IpponVSpace>
79
+ <IpponVSpaceSlot align={alignment} dataSelector="ippon-v-space-slot">
80
+ Slot
81
+ </IpponVSpaceSlot>
82
+ </IpponVSpace>,
83
+ );
84
+
85
+ const ipponVSpaceSlot = screen.getByTestId('ippon-v-space-slot');
86
+
87
+ expect(ipponVSpaceSlot).toHaveClass(`-${alignment}`);
88
+ },
89
+ );
90
+ });
91
+ });
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "es2023",
5
+ "lib": ["ES2023", "DOM"],
6
+ "module": "esnext",
7
+ "types": ["vite/client"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+ "jsx": "react-jsx",
17
+
18
+ /* Linting */
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true
22
+ },
23
+ "include": ["src"]
24
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "files": [],
3
+ "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
4
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "es2023",
5
+ "lib": ["ES2023"],
6
+ "module": "esnext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "noFallthroughCasesInSwitch": true
21
+ },
22
+ "include": ["vite.config.ts"]
23
+ }
@@ -0,0 +1,30 @@
1
+ import { defineConfig } from 'vite';
2
+ import react, { reactCompilerPreset } from '@vitejs/plugin-react';
3
+ import babel from '@rolldown/plugin-babel';
4
+ import dts from 'vite-plugin-dts';
5
+ import { resolve } from 'path';
6
+
7
+ export default defineConfig({
8
+ plugins: [
9
+ react(),
10
+ babel({ presets: [reactCompilerPreset()] }),
11
+ dts({ tsconfigPath: './tsconfig.app.json', include: ['src'], bundleTypes: true }),
12
+ ],
13
+ build: {
14
+ lib: {
15
+ entry: resolve(__dirname, 'src/index.ts'),
16
+ name: 'ippon-react',
17
+ formats: ['es', 'cjs'],
18
+ fileName: (format) => `index.${format === 'es' ? 'mjs' : 'cjs'}`,
19
+ },
20
+ rollupOptions: {
21
+ external: [/^react($|\/)/, /^react-dom($|\/)/],
22
+ output: {
23
+ globals: {
24
+ react: 'React',
25
+ 'react-dom': 'ReactDOM',
26
+ },
27
+ },
28
+ },
29
+ },
30
+ });
@@ -0,0 +1,21 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: 'jsdom',
6
+ coverage: {
7
+ provider: 'istanbul',
8
+ reporter: ['text', 'html', 'cobertura', 'json'],
9
+ clean: true,
10
+ include: ['src/**/*'],
11
+ thresholds: {
12
+ 'src/**/domain/**/*.{ts,tsx}': {
13
+ statements: 100,
14
+ branches: 100,
15
+ functions: 100,
16
+ lines: 100,
17
+ },
18
+ },
19
+ },
20
+ },
21
+ });
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
@@ -0,0 +1,75 @@
1
+ {
2
+ "plugins": ["stylelint-scss", "stylelint-order"],
3
+ "extends": ["stylelint-config-standard-scss", "stylelint-config-concentric-order"],
4
+ "rules": {
5
+ "max-nesting-depth": 3,
6
+ "custom-property-pattern": "^_?[a-zA-Z][a-zA-Z0-9\\-]*$",
7
+ "selector-class-pattern": "^-?([a-z][a-z0-9]*)(-[a-z0-9]+)*$",
8
+ "no-descending-specificity": null,
9
+ "selector-no-qualifying-type": [
10
+ true,
11
+ {
12
+ "ignore": ["class"]
13
+ }
14
+ ],
15
+ "order/order": [
16
+ {
17
+ "type": "at-rule",
18
+ "name": "import"
19
+ },
20
+ "dollar-variables",
21
+ "custom-properties",
22
+ {
23
+ "type": "at-rule",
24
+ "name": "extend"
25
+ },
26
+ {
27
+ "type": "at-rule",
28
+ "name": "mixin"
29
+ },
30
+ {
31
+ "type": "at-rule",
32
+ "name": "add-mixin"
33
+ },
34
+ {
35
+ "type": "at-rule",
36
+ "name": "apply"
37
+ },
38
+ "declarations",
39
+ {
40
+ "type": "rule",
41
+ "selector": "/^&:[\\w-]+/",
42
+ "hasBlock": true
43
+ },
44
+ {
45
+ "type": "rule",
46
+ "selector": "/^&:[\\w-]+/",
47
+ "hasBlock": true
48
+ },
49
+ "rules",
50
+ {
51
+ "type": "at-rule",
52
+ "name": "include",
53
+ "parameter": "/breakpoints?/i",
54
+ "hasBlock": true
55
+ },
56
+ {
57
+ "type": "at-rule",
58
+ "name": "mixin",
59
+ "parameter": "/breakpoints?/i",
60
+ "hasBlock": true
61
+ },
62
+ {
63
+ "type": "at-rule",
64
+ "name": "add-mixin",
65
+ "parameter": "/breakpoints?/i",
66
+ "hasBlock": true
67
+ },
68
+ {
69
+ "type": "at-rule",
70
+ "name": "media",
71
+ "hasBlock": true
72
+ }
73
+ ]
74
+ }
75
+ }