@sakura-ui/sakura-ui 0.1.21 → 0.3.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 (264) hide show
  1. package/README.md +16 -6
  2. package/package.json +26 -20
  3. package/packages/core/package.json +30 -18
  4. package/packages/core/src/components/Button.tsx +33 -32
  5. package/packages/core/src/components/Card.tsx +38 -20
  6. package/packages/core/src/components/Code.tsx +6 -4
  7. package/packages/core/src/components/Faq.tsx +13 -7
  8. package/packages/core/src/components/Heading.tsx +42 -32
  9. package/packages/core/src/components/Icon.tsx +43 -13
  10. package/packages/core/src/components/IconButton.tsx +56 -45
  11. package/packages/core/src/components/LangSelector.tsx +135 -0
  12. package/packages/core/src/components/Link.tsx +38 -65
  13. package/packages/core/src/components/LinkCard.tsx +91 -0
  14. package/packages/core/src/components/List.tsx +14 -12
  15. package/packages/core/src/components/MenuButton.tsx +112 -0
  16. package/packages/core/src/components/NavigationItem.tsx +41 -0
  17. package/packages/core/src/components/OverflowContainer.tsx +24 -0
  18. package/packages/core/src/components/PopoverMenu.tsx +81 -0
  19. package/packages/core/src/components/Pre.tsx +6 -4
  20. package/packages/core/src/components/Table.tsx +35 -28
  21. package/packages/core/src/components/buttonStyle.ts +55 -38
  22. package/packages/core/src/components/index.ts +13 -28
  23. package/packages/core/src/icons/Close.tsx +21 -0
  24. package/packages/core/src/icons/CloseMobile.tsx +43 -0
  25. package/packages/core/src/icons/KeyboardArrowDown.tsx +24 -0
  26. package/packages/core/src/icons/Language.tsx +25 -0
  27. package/packages/core/src/icons/LanguageMobile.tsx +40 -0
  28. package/packages/core/src/icons/Menu.tsx +24 -0
  29. package/packages/core/src/icons/MenuMobile.tsx +40 -0
  30. package/packages/core/src/icons/index.ts +8 -0
  31. package/packages/core/src/icons/props.ts +5 -0
  32. package/packages/core/src/index.ts +9 -29
  33. package/packages/core/src/type.d.ts +1 -0
  34. package/packages/core/tests/Button.test.tsx +40 -0
  35. package/packages/core/tests/Card.test.tsx +36 -8
  36. package/packages/core/tests/IconButton.test.tsx +57 -0
  37. package/packages/core/tests/Link.test.tsx +60 -0
  38. package/packages/core/tests/vitest.setup.ts +2 -0
  39. package/packages/core/tsconfig.node.json +3 -2
  40. package/packages/core/vite.config.ts +3 -2
  41. package/packages/forms/.turbo/turbo-build.log +22 -0
  42. package/packages/forms/dist/index.cjs.js +242 -152
  43. package/packages/forms/dist/index.es.js +947 -1010
  44. package/packages/forms/dist/types/components/Checkbox.d.ts +10 -3
  45. package/packages/forms/dist/types/components/Checkbox.d.ts.map +1 -1
  46. package/packages/forms/dist/types/components/FieldsetControl.d.ts +14 -9
  47. package/packages/forms/dist/types/components/FieldsetControl.d.ts.map +1 -1
  48. package/packages/forms/dist/types/components/FileInput.d.ts +10 -3
  49. package/packages/forms/dist/types/components/FileInput.d.ts.map +1 -1
  50. package/packages/forms/dist/types/components/Input.d.ts +10 -3
  51. package/packages/forms/dist/types/components/Input.d.ts.map +1 -1
  52. package/packages/forms/dist/types/components/LabelControl.d.ts +13 -8
  53. package/packages/forms/dist/types/components/LabelControl.d.ts.map +1 -1
  54. package/packages/forms/dist/types/components/Radio.d.ts +10 -3
  55. package/packages/forms/dist/types/components/Radio.d.ts.map +1 -1
  56. package/packages/forms/dist/types/components/Select.d.ts +10 -3
  57. package/packages/forms/dist/types/components/Select.d.ts.map +1 -1
  58. package/packages/forms/dist/types/components/Textarea.d.ts +8 -3
  59. package/packages/forms/dist/types/components/Textarea.d.ts.map +1 -1
  60. package/packages/forms/dist/types/components/controlled/CheckboxGroup.d.ts +18 -11
  61. package/packages/forms/dist/types/components/controlled/CheckboxGroup.d.ts.map +1 -1
  62. package/packages/forms/dist/types/components/controlled/RadioGroup.d.ts +19 -12
  63. package/packages/forms/dist/types/components/controlled/RadioGroup.d.ts.map +1 -1
  64. package/packages/forms/dist/types/components/controlled/index.d.ts +0 -2
  65. package/packages/forms/dist/types/components/controlled/index.d.ts.map +1 -1
  66. package/packages/forms/dist/types/components/index.d.ts +8 -8
  67. package/packages/forms/dist/types/components/index.d.ts.map +1 -1
  68. package/packages/forms/dist/types/components/inputStyle.d.ts +13 -0
  69. package/packages/forms/dist/types/components/inputStyle.d.ts.map +1 -0
  70. package/packages/forms/dist/types/index.d.ts +1 -2
  71. package/packages/forms/dist/types/index.d.ts.map +1 -1
  72. package/packages/forms/node_modules/.bin/autoprefixer +2 -2
  73. package/packages/forms/node_modules/.bin/tailwind +2 -2
  74. package/packages/forms/node_modules/.bin/tailwindcss +2 -2
  75. package/packages/forms/node_modules/.bin/ts-node +4 -4
  76. package/packages/forms/node_modules/.bin/ts-node-cwd +4 -4
  77. package/packages/forms/node_modules/.bin/ts-node-esm +4 -4
  78. package/packages/forms/node_modules/.bin/ts-node-script +4 -4
  79. package/packages/forms/node_modules/.bin/ts-node-transpile-only +4 -4
  80. package/packages/forms/node_modules/.bin/ts-script +4 -4
  81. package/packages/forms/node_modules/.bin/tsc +17 -0
  82. package/packages/forms/node_modules/.bin/tsserver +17 -0
  83. package/packages/forms/node_modules/.vite/vitest/results.json +1 -0
  84. package/packages/forms/package.json +21 -17
  85. package/packages/forms/src/components/Checkbox.tsx +82 -64
  86. package/packages/forms/src/components/FieldsetControl.tsx +21 -28
  87. package/packages/forms/src/components/FileInput.tsx +88 -62
  88. package/packages/forms/src/components/Input.tsx +35 -41
  89. package/packages/forms/src/components/LabelControl.tsx +19 -25
  90. package/packages/forms/src/components/Radio.tsx +73 -61
  91. package/packages/forms/src/components/Select.tsx +71 -61
  92. package/packages/forms/src/components/Textarea.tsx +50 -54
  93. package/packages/forms/src/components/controlled/CheckboxGroup.tsx +25 -19
  94. package/packages/forms/src/components/controlled/RadioGroup.tsx +22 -20
  95. package/packages/forms/src/components/controlled/index.ts +0 -2
  96. package/packages/forms/src/components/index.ts +8 -8
  97. package/packages/forms/src/components/inputStyle.ts +82 -0
  98. package/packages/forms/src/index.ts +1 -17
  99. package/packages/forms/tests/Checkbox.test.tsx +44 -0
  100. package/packages/forms/tests/FieldsetControl.test.tsx +63 -12
  101. package/packages/forms/tests/FileInput.test.tsx +25 -0
  102. package/packages/forms/tests/Input.test.tsx +13 -84
  103. package/packages/forms/tests/LabelControl.test.tsx +83 -21
  104. package/packages/forms/tests/Radio.test.tsx +24 -79
  105. package/packages/forms/tests/Select.test.tsx +30 -0
  106. package/packages/forms/tests/Textarea.test.tsx +25 -0
  107. package/packages/forms/tests/vitest.setup.ts +2 -0
  108. package/packages/forms/tsconfig.node.json +3 -2
  109. package/packages/forms/vite.config.ts +3 -2
  110. package/packages/helper/.turbo/turbo-build.log +23 -0
  111. package/packages/helper/dist/index.cjs.js +78 -0
  112. package/packages/helper/dist/index.es.js +119 -0
  113. package/packages/helper/dist/types/calc.d.ts +2 -0
  114. package/packages/helper/dist/types/calc.d.ts.map +1 -0
  115. package/packages/{forms/dist/types/utils/class.d.ts → helper/dist/types/cx.d.ts} +1 -1
  116. package/packages/helper/dist/types/cx.d.ts.map +1 -0
  117. package/packages/helper/dist/types/index.d.ts +6 -0
  118. package/packages/helper/dist/types/index.d.ts.map +1 -0
  119. package/packages/helper/dist/types/querySelector.d.ts +2 -0
  120. package/packages/helper/dist/types/querySelector.d.ts.map +1 -0
  121. package/packages/helper/dist/types/styles.d.ts +22 -0
  122. package/packages/helper/dist/types/styles.d.ts.map +1 -0
  123. package/packages/helper/dist/types/treefy.d.ts +8 -0
  124. package/packages/helper/dist/types/treefy.d.ts.map +1 -0
  125. package/packages/{config → helper}/package.json +13 -19
  126. package/packages/helper/src/calc.ts +1 -0
  127. package/packages/{core/src/libs → helper/src}/cx.ts +1 -0
  128. package/packages/helper/src/index.ts +5 -0
  129. package/packages/helper/src/querySelector.ts +20 -0
  130. package/packages/helper/src/styles.ts +116 -0
  131. package/packages/helper/src/treefy.ts +22 -0
  132. package/packages/helper/vite.config.ts +26 -0
  133. package/packages/markdown/.turbo/turbo-build.log +22 -0
  134. package/packages/markdown/README.md +129 -0
  135. package/packages/markdown/dist/index.cjs.js +175 -0
  136. package/packages/markdown/dist/index.es.js +17098 -0
  137. package/packages/markdown/dist/types/components/Markdown.d.ts +15 -0
  138. package/packages/markdown/dist/types/components/Markdown.d.ts.map +1 -0
  139. package/packages/markdown/dist/types/components/index.d.ts +2 -0
  140. package/packages/markdown/dist/types/components/index.d.ts.map +1 -0
  141. package/packages/markdown/dist/types/index.d.ts +2 -0
  142. package/packages/markdown/dist/types/index.d.ts.map +1 -0
  143. package/packages/markdown/dist/types/plugins/attr.d.ts +3 -0
  144. package/packages/markdown/dist/types/plugins/attr.d.ts.map +1 -0
  145. package/packages/markdown/dist/types/plugins/card.d.ts +3 -0
  146. package/packages/markdown/dist/types/plugins/card.d.ts.map +1 -0
  147. package/packages/markdown/dist/types/plugins/cell.d.ts +3 -0
  148. package/packages/markdown/dist/types/plugins/cell.d.ts.map +1 -0
  149. package/packages/markdown/dist/types/plugins/faq.d.ts +3 -0
  150. package/packages/markdown/dist/types/plugins/faq.d.ts.map +1 -0
  151. package/packages/markdown/dist/types/plugins/grid.d.ts +3 -0
  152. package/packages/markdown/dist/types/plugins/grid.d.ts.map +1 -0
  153. package/packages/markdown/dist/types/plugins/headings.d.ts +9 -0
  154. package/packages/markdown/dist/types/plugins/headings.d.ts.map +1 -0
  155. package/packages/markdown/dist/types/plugins/helper.d.ts +9 -0
  156. package/packages/markdown/dist/types/plugins/helper.d.ts.map +1 -0
  157. package/packages/markdown/dist/types/plugins/index.d.ts +9 -0
  158. package/packages/markdown/dist/types/plugins/index.d.ts.map +1 -0
  159. package/packages/markdown/dist/types/plugins/linkButton.d.ts +3 -0
  160. package/packages/markdown/dist/types/plugins/linkButton.d.ts.map +1 -0
  161. package/packages/markdown/dist/types/plugins/youtube.d.ts +3 -0
  162. package/packages/markdown/dist/types/plugins/youtube.d.ts.map +1 -0
  163. package/packages/markdown/node_modules/.bin/autoprefixer +17 -0
  164. package/packages/markdown/node_modules/.bin/tailwind +17 -0
  165. package/packages/markdown/node_modules/.bin/tailwindcss +17 -0
  166. package/packages/markdown/node_modules/.bin/ts-node +17 -0
  167. package/packages/markdown/node_modules/.bin/ts-node-cwd +17 -0
  168. package/packages/markdown/node_modules/.bin/ts-node-esm +17 -0
  169. package/packages/markdown/node_modules/.bin/ts-node-script +17 -0
  170. package/packages/markdown/node_modules/.bin/ts-node-transpile-only +17 -0
  171. package/packages/markdown/node_modules/.bin/ts-script +17 -0
  172. package/packages/markdown/node_modules/.bin/tsc +17 -0
  173. package/packages/markdown/node_modules/.bin/tsserver +17 -0
  174. package/packages/markdown/package.json +83 -0
  175. package/packages/markdown/src/components/Markdown.tsx +361 -0
  176. package/packages/markdown/src/components/index.ts +1 -0
  177. package/packages/markdown/src/global.d.ts +9 -0
  178. package/packages/markdown/src/index.ts +1 -0
  179. package/packages/markdown/src/plugins/attr.ts +19 -0
  180. package/packages/markdown/src/plugins/card.ts +57 -0
  181. package/packages/markdown/src/plugins/cell.ts +47 -0
  182. package/packages/markdown/src/plugins/faq.ts +40 -0
  183. package/packages/markdown/src/plugins/grid.ts +51 -0
  184. package/packages/markdown/src/plugins/headings.ts +35 -0
  185. package/packages/markdown/src/plugins/helper.ts +27 -0
  186. package/packages/markdown/src/plugins/index.ts +8 -0
  187. package/packages/markdown/src/plugins/linkButton.ts +25 -0
  188. package/packages/markdown/src/plugins/youtube.ts +48 -0
  189. package/packages/markdown/tsconfig.json +13 -0
  190. package/packages/markdown/tsconfig.node.json +7 -0
  191. package/packages/{config → markdown}/vite.config.ts +6 -2
  192. package/packages/tailwind-theme-plugin/.turbo/turbo-build.log +22 -0
  193. package/packages/tailwind-theme-plugin/dist/index.cjs.js +1 -1
  194. package/packages/tailwind-theme-plugin/dist/index.es.js +5358 -6115
  195. package/packages/tailwind-theme-plugin/dist/types/index.d.ts +1 -1
  196. package/packages/tailwind-theme-plugin/dist/types/index.d.ts.map +1 -1
  197. package/packages/tailwind-theme-plugin/node_modules/.bin/autoprefixer +4 -4
  198. package/packages/tailwind-theme-plugin/node_modules/.bin/tailwind +4 -4
  199. package/packages/tailwind-theme-plugin/node_modules/.bin/tailwindcss +4 -4
  200. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node +4 -4
  201. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node-cwd +4 -4
  202. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node-esm +4 -4
  203. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node-script +4 -4
  204. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node-transpile-only +4 -4
  205. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-script +4 -4
  206. package/packages/tailwind-theme-plugin/node_modules/.bin/tsc +17 -0
  207. package/packages/tailwind-theme-plugin/node_modules/.bin/tsserver +17 -0
  208. package/packages/tailwind-theme-plugin/package.json +10 -7
  209. package/packages/tailwind-theme-plugin/src/index.ts +232 -297
  210. package/packages/tailwind-theme-plugin/vite.config.ts +1 -1
  211. package/packages/config/src/index.ts +0 -347
  212. package/packages/config/tests/index.test.ts +0 -13
  213. package/packages/core/.eslintrc.json +0 -25
  214. package/packages/core/src/components/InfoCard.tsx +0 -50
  215. package/packages/core/src/libs/forward-ref.ts +0 -41
  216. package/packages/core/src/types/component.ts +0 -82
  217. package/packages/forms/coverage/clover.xml +0 -209
  218. package/packages/forms/coverage/coverage-final.json +0 -18
  219. package/packages/forms/coverage/lcov-report/base.css +0 -224
  220. package/packages/forms/coverage/lcov-report/block-navigation.js +0 -87
  221. package/packages/forms/coverage/lcov-report/favicon.png +0 -0
  222. package/packages/forms/coverage/lcov-report/index.html +0 -161
  223. package/packages/forms/coverage/lcov-report/prettify.css +0 -1
  224. package/packages/forms/coverage/lcov-report/prettify.js +0 -2
  225. package/packages/forms/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  226. package/packages/forms/coverage/lcov-report/sorter.js +0 -196
  227. package/packages/forms/coverage/lcov-report/src/components/Checkbox.tsx.html +0 -295
  228. package/packages/forms/coverage/lcov-report/src/components/FieldsetControl.tsx.html +0 -295
  229. package/packages/forms/coverage/lcov-report/src/components/LabelControl.tsx.html +0 -289
  230. package/packages/forms/coverage/lcov-report/src/components/Radio.tsx.html +0 -262
  231. package/packages/forms/coverage/lcov-report/src/components/Select.tsx.html +0 -259
  232. package/packages/forms/coverage/lcov-report/src/components/Text.tsx.html +0 -220
  233. package/packages/forms/coverage/lcov-report/src/components/Textarea.tsx.html +0 -229
  234. package/packages/forms/coverage/lcov-report/src/components/context.ts.html +0 -136
  235. package/packages/forms/coverage/lcov-report/src/components/controlled/CheckboxGroup.tsx.html +0 -244
  236. package/packages/forms/coverage/lcov-report/src/components/controlled/RadioGroup.tsx.html +0 -265
  237. package/packages/forms/coverage/lcov-report/src/components/controlled/SelectControl.tsx.html +0 -205
  238. package/packages/forms/coverage/lcov-report/src/components/controlled/TextControl.tsx.html +0 -202
  239. package/packages/forms/coverage/lcov-report/src/components/controlled/TextareaControl.tsx.html +0 -205
  240. package/packages/forms/coverage/lcov-report/src/components/controlled/index.html +0 -191
  241. package/packages/forms/coverage/lcov-report/src/components/controlled/index.ts.html +0 -100
  242. package/packages/forms/coverage/lcov-report/src/components/index.html +0 -236
  243. package/packages/forms/coverage/lcov-report/src/components/index.ts.html +0 -106
  244. package/packages/forms/coverage/lcov-report/src/index.html +0 -116
  245. package/packages/forms/coverage/lcov-report/src/index.ts.html +0 -136
  246. package/packages/forms/coverage/lcov-report/src/utils/index.html +0 -116
  247. package/packages/forms/coverage/lcov-report/src/utils/index.ts.html +0 -88
  248. package/packages/forms/coverage/lcov.info +0 -434
  249. package/packages/forms/dist/types/components/controlled/SelectControl.d.ts +0 -10
  250. package/packages/forms/dist/types/components/controlled/SelectControl.d.ts.map +0 -1
  251. package/packages/forms/dist/types/components/controlled/TextareaControl.d.ts +0 -10
  252. package/packages/forms/dist/types/components/controlled/TextareaControl.d.ts.map +0 -1
  253. package/packages/forms/dist/types/utils/class.d.ts.map +0 -1
  254. package/packages/forms/jest.config.ts +0 -11
  255. package/packages/forms/node_modules/.bin/browserslist +0 -17
  256. package/packages/forms/node_modules/.bin/eslint +0 -17
  257. package/packages/forms/node_modules/.bin/vitest +0 -17
  258. package/packages/forms/node_modules/.vitest/results.json +0 -1
  259. package/packages/forms/src/components/controlled/SelectControl.tsx +0 -42
  260. package/packages/forms/src/components/controlled/TextareaControl.tsx +0 -42
  261. package/packages/forms/src/utils/class.ts +0 -1
  262. package/packages/tailwind-theme-plugin/node_modules/.bin/browserslist +0 -17
  263. /package/packages/{config → helper}/tsconfig.json +0 -0
  264. /package/packages/{config → helper}/tsconfig.node.json +0 -0
@@ -1,32 +1,62 @@
1
1
  import React from 'react'
2
- import { cx } from '../libs/cx'
2
+ import { cx } from '@sakura-ui/helper'
3
3
 
4
- export interface IconProps extends React.ComponentPropsWithRef<'span'> {
5
- icon: string
6
- srText?: string
4
+ export namespace Icon {
5
+ export interface Props extends React.ComponentPropsWithRef<'span'> {
6
+ opticalSize?: 16 | 20 | 24 | 40 | 44 | 48
7
+ altText?: string
8
+ }
7
9
  }
8
10
 
9
- export const Icon = React.forwardRef<HTMLElement, IconProps>((props, ref) => {
10
- const { className, icon, srText, ...restProps } = props
11
+ export const Icon = React.forwardRef<HTMLElement, Icon.Props>((props, ref) => {
12
+ const { className, altText = '', opticalSize = 24, children, ...rest } = props
13
+
14
+ const size = {
15
+ 16: '!text-[16px]',
16
+ 20: '!text-[20px]',
17
+ 24: '!text-[24px]',
18
+ 40: '!text-[40px]',
19
+ 44: '!text-[44px]',
20
+ 48: '!text-[48px]'
21
+ }
22
+
23
+ const fontSize = size[opticalSize]
24
+
25
+ // @see: https://developers.google.com/fonts/docs/material_symbols
26
+ //.material-symbols-outlined {
27
+ // font-family: 'Material Symbols Outlined';
28
+ // font-weight: normal;
29
+ // font-style: normal;
30
+ // font-size: 24px; /* Preferred icon size */
31
+ // display: inline-block;
32
+ // line-height: 1;
33
+ // text-transform: none;
34
+ // letter-spacing: normal;
35
+ // word-wrap: normal;
36
+ // white-space: nowrap;
37
+ // direction: ltr;
38
+ //}
11
39
 
12
40
  const style = `
13
- inline
14
- align-middle
15
41
  font-icon
16
- antialiased
42
+ font-light
43
+ inline-block
44
+ leading-none
45
+ align-middle
46
+ whitespace-nowrap
17
47
  `
18
48
 
19
49
  return (
20
50
  <>
21
51
  <span
22
52
  aria-hidden="true"
23
- className={cx(style, className)}
24
- {...restProps}
53
+ className={cx(className, fontSize, style)}
54
+ {...rest}
25
55
  ref={ref}
26
56
  >
27
- {icon}
57
+ {children}
28
58
  </span>
29
- <span className="sr-only">{srText}</span>
59
+ <span className="sr-only">{altText}</span>
30
60
  </>
31
61
  )
32
62
  })
@@ -1,33 +1,43 @@
1
- import { cx } from '../libs/cx'
2
- import { ComponentWithAs } from '../types/component'
3
- import { forwardRef } from '../libs/forward-ref'
4
- import { base, getVariantStyle, getSizeStyle } from './buttonStyle'
1
+ import React, { type ComponentProps } from 'react'
2
+ import { cx } from '@sakura-ui/helper'
3
+ import {
4
+ base,
5
+ getVariantStyle,
6
+ getSizeStyle,
7
+ type ButtonVariant,
8
+ type ButtonSize
9
+ } from './buttonStyle'
5
10
 
6
- export interface IconButtonProps {
7
- variant?: 'primary' | 'secondary'
8
- size?: 'lg' | 'md' | 'sm' | 'xs'
9
- iconLayout?: 'left' | 'right'
10
- icon: string
11
- rounded?: string
11
+ export namespace IconButton {
12
+ export interface Props<T extends React.ElementType> {
13
+ as?: T
14
+ variant?: ButtonVariant
15
+ size?: ButtonSize
16
+ iconLayout?: 'left' | 'right'
17
+ icon: string
18
+ rounded?: string
19
+ }
12
20
  }
13
21
 
14
- export const IconButton: ComponentWithAs<'button', IconButtonProps> =
15
- forwardRef((props, ref) => {
16
- const {
17
- as: Component = 'button',
18
- variant = 'primary',
19
- size = 'lg',
20
- iconLayout = 'left',
21
- icon,
22
- rounded,
23
- className,
24
- children,
25
- ...restProps
26
- } = props
22
+ export const IconButton = <T extends React.ElementType = 'button'>(
23
+ props: IconButton.Props<T> &
24
+ Omit<React.ComponentProps<T>, keyof IconButton.Props<T>>
25
+ ) => {
26
+ const {
27
+ as: Component = 'button',
28
+ variant = 'solid-fill',
29
+ size = 'lg',
30
+ iconLayout = 'left',
31
+ icon,
32
+ rounded,
33
+ className,
34
+ children,
35
+ ...restProps
36
+ } = props
27
37
 
28
- const styleFontSize = `${size === 'xs' ? `scale-105` : `scale-125`}`
38
+ const styleFontSize = `${size === 'xs' ? 'scale-105' : 'scale-125'}`
29
39
 
30
- const styleIcon = `
40
+ const styleIcon = `
31
41
  inline-block
32
42
  align-middle
33
43
  mb-1
@@ -37,24 +47,24 @@ export const IconButton: ComponentWithAs<'button', IconButtonProps> =
37
47
  antialiased
38
48
  `
39
49
 
40
- const styleRounded = `${rounded ? `aspect-square !rounded-full !py-0` : ''}`
50
+ const styleRounded = `${rounded ? 'aspect-square !rounded-full !py-0' : ''}`
41
51
 
42
- // When text is specified on a button, set the 'aria-hidden' attribute of the icon to true.
43
- const ariaHidden = children ? true : false
52
+ // When text is specified on a button, set the 'aria-hidden' attribute of the icon to true.
53
+ const ariaHidden = !!children
44
54
 
45
- return (
46
- <Component
47
- className={cx(
48
- base,
49
- getVariantStyle(variant),
50
- getSizeStyle(size),
51
- styleRounded,
52
- className
53
- )}
54
- {...restProps}
55
- ref={ref}
56
- >
57
- {iconLayout == 'left' && (
55
+ return (
56
+ <Component
57
+ className={cx(
58
+ base,
59
+ getVariantStyle(variant),
60
+ getSizeStyle(size),
61
+ styleRounded,
62
+ className
63
+ )}
64
+ {...restProps}
65
+ >
66
+ <span>
67
+ {iconLayout === 'left' && (
58
68
  <span
59
69
  className={cx(styleIcon, styleFontSize)}
60
70
  aria-hidden={ariaHidden}
@@ -63,7 +73,7 @@ export const IconButton: ComponentWithAs<'button', IconButtonProps> =
63
73
  </span>
64
74
  )}
65
75
  {children && <span className="mx-1">{children}</span>}
66
- {iconLayout == 'right' && (
76
+ {iconLayout === 'right' && (
67
77
  <span
68
78
  className={cx(styleIcon, styleFontSize)}
69
79
  aria-hidden={ariaHidden}
@@ -71,8 +81,9 @@ export const IconButton: ComponentWithAs<'button', IconButtonProps> =
71
81
  {icon}
72
82
  </span>
73
83
  )}
74
- </Component>
75
- )
76
- })
84
+ </span>
85
+ </Component>
86
+ )
87
+ }
77
88
 
78
89
  IconButton.displayName = 'IconButton'
@@ -0,0 +1,135 @@
1
+ import React from 'react'
2
+ import { cx, mod, focusableSelector, Style } from '@sakura-ui/helper'
3
+ import { Language, LanguageMobile, KeyboadArrowDown } from '@/icons'
4
+ import { PopoverMenu, PopoverMenuItem } from './PopoverMenu'
5
+
6
+ export namespace LangSelector {
7
+ interface Lang {
8
+ code: string
9
+ title: string
10
+ path: string
11
+ }
12
+ // Tailwind 3.4.5 or higher is required to use anchor-name.
13
+ // https://github.com/tailwindlabs/tailwindcss/issues/13818
14
+ export interface Props extends React.ComponentPropsWithRef<'button'> {
15
+ current: string
16
+ langs: Lang[]
17
+ }
18
+ }
19
+
20
+ export const LangSelector = ({
21
+ current,
22
+ langs,
23
+ className,
24
+ ...restProps
25
+ }: LangSelector.Props) => {
26
+ const styleRoot = `
27
+ relative
28
+ group
29
+ `
30
+
31
+ const styleAnchorName = `
32
+ [anchor-name:--target]
33
+ `
34
+
35
+ // height: text-base(16px)*1.375 + p-3(12px)*2 + border(1px)*2 = 48px
36
+ const styleButton = `
37
+ w-fit
38
+ py-[1px]
39
+ sm:py-3
40
+ text-base
41
+ leading-snug
42
+ ${Style.clickable}
43
+ ${Style.focusRoundedWithBg}
44
+ ${Style.hoverUnderline}
45
+ ${styleAnchorName}
46
+ flex items-center
47
+ `
48
+
49
+ const stylePositionBottomRight = `
50
+ absolute
51
+ top-[anchor(--target_bottom)]
52
+ right-[anchor(--target_right)]
53
+ position-try-options:flip-block]
54
+ inset-[unset]
55
+ `
56
+
57
+ const targetId = React.useId()
58
+
59
+ const menuRef = React.useRef<HTMLUListElement>(null)
60
+
61
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
62
+ if (e.key === 'Tab') {
63
+ e.preventDefault()
64
+
65
+ const focusables: HTMLElement[] = Array.from(
66
+ menuRef.current?.querySelectorAll(focusableSelector) || []
67
+ )
68
+ if (focusables.length === 0) return
69
+
70
+ const tabIndex = focusables.findIndex(
71
+ (el) => el === document.activeElement
72
+ )
73
+ // If there is no focused element, focus the first element
74
+ if (tabIndex === -1) {
75
+ focusables[0].focus()
76
+ return
77
+ }
78
+ const nextIndex = mod(tabIndex + (e.shiftKey ? -1 : 1), focusables.length)
79
+ focusables[nextIndex].focus()
80
+
81
+ return
82
+ }
83
+ }
84
+
85
+ React.useEffect(() => {
86
+ const handleToggle = () => {
87
+ const focusable: HTMLElement | null | undefined =
88
+ menuRef.current?.querySelector(focusableSelector)
89
+ if (!focusable) return
90
+ focusable.focus()
91
+ }
92
+
93
+ menuRef.current?.addEventListener('toggle', handleToggle)
94
+
95
+ return () => menuRef.current?.removeEventListener('toggle', handleToggle)
96
+ }, [])
97
+
98
+ return (
99
+ <div className={cx(className, styleRoot)}>
100
+ <button
101
+ popoverTarget={targetId}
102
+ type="button"
103
+ className={styleButton}
104
+ {...restProps}
105
+ >
106
+ <Language size={20} className="hidden sm:mt-0.5 sm:inline-block" />
107
+ <span className="hidden sm:mx-1 sm:inline">Language</span>
108
+ <LanguageMobile size={44} className="inline-block sm:hidden" />
109
+ <KeyboadArrowDown
110
+ size={16}
111
+ className="inline-block sm:mt-1 group-[:has(:popover-open)]:rotate-180"
112
+ />
113
+ </button>
114
+ <PopoverMenu
115
+ ref={menuRef}
116
+ id={targetId}
117
+ popover="auto"
118
+ onKeyDown={handleKeyDown}
119
+ className={stylePositionBottomRight}
120
+ >
121
+ {langs.map((lang) => (
122
+ <PopoverMenuItem
123
+ key={lang.code}
124
+ aria-current={current === lang.code}
125
+ href={lang.path}
126
+ >
127
+ {lang.title}
128
+ </PopoverMenuItem>
129
+ ))}
130
+ </PopoverMenu>
131
+ </div>
132
+ )
133
+ }
134
+
135
+ LangSelector.displayName = 'LangSelector'
@@ -1,78 +1,51 @@
1
- import { cx } from '../libs/cx'
2
- import { ComponentWithAs } from '../types/component'
3
- import { forwardRef } from '../libs/forward-ref'
1
+ import React from 'react'
2
+ import { cx, Style } from '@sakura-ui/helper'
3
+ import { Icon } from './Icon'
4
4
 
5
- export interface LinkProps {}
6
-
7
- export const Link: ComponentWithAs<'a', LinkProps> = forwardRef(
8
- (props, ref) => {
9
- const {
10
- as: Component = 'a',
11
- href,
12
- className,
13
- children,
14
- ...restProps
15
- } = props
16
-
17
- const styleUnderLine = `
18
- underline
19
- underline-offset-[0.125em]
20
- `
5
+ export namespace Link {
6
+ export interface Props<T extends React.ElementType> {
7
+ as?: T
8
+ }
9
+ }
21
10
 
22
- // Make lines break at each word
23
- const style = `
24
- rounded-sm
25
- cursor-pointer
26
- text-sea-600
27
- hover:text-sea-800
28
- active:text-sea-800
29
- visited:text-sea-900
30
- focus:outline
31
- focus:outline-2
32
- focus:outline-wood-500
33
- disabled:border-sumi-500
34
- [overflow-wrap:anywhere]
35
- `
11
+ export const Link = <T extends React.ElementType = 'a'>(
12
+ props: Link.Props<T> & Omit<React.ComponentProps<T>, keyof Link.Props<T>>
13
+ ) => {
14
+ const { as: Component = 'a', className, children, ...restProps } = props
36
15
 
37
- const styleIcon = `
38
- align-middle
39
- ml-0.5
40
- text-sumi-700
41
- font-icon
42
- font-light
43
- leading-4
44
- antialiased
45
- `
16
+ // Make lines break at each word
17
+ const style = `
18
+ cursor-pointer
19
+ text-blue-1000
20
+ active:text-orange-700
21
+ visited:text-magenta-900
22
+ ${Style.focusRoundedWithBg}
23
+ ${Style.underline}
24
+ disabled:border-solid-gray-500
25
+ [overflow-wrap:anywhere]
26
+ `
46
27
 
47
- if (href?.startsWith('http')) {
48
- return (
49
- <Component
50
- className={cx(style, className)}
51
- href={href}
52
- target="_blank"
53
- rel="noopener noreferrer"
54
- {...restProps}
55
- ref={ref}
56
- >
57
- <span className={styleUnderLine}>{children}</span>
58
- <span className={cx(styleIcon)} aria-hidden="true">
59
- open_in_new
60
- </span>
61
- <span className="sr-only">Opens in new tab</span>
62
- </Component>
63
- )
64
- }
28
+ if (restProps.href?.startsWith('http') || restProps.target === '_blank') {
65
29
  return (
66
30
  <Component
67
- className={cx(style, styleUnderLine, className)}
68
- href={href}
31
+ className={cx(style, className)}
32
+ target="_blank"
33
+ rel="noopener noreferrer"
69
34
  {...restProps}
70
- ref={ref}
71
35
  >
72
- {children}
36
+ <span>{children}</span>
37
+ <Icon opticalSize={16} altText="Opens in new tab" className="ml-0.5">
38
+ open_in_new
39
+ </Icon>
73
40
  </Component>
74
41
  )
75
42
  }
76
- )
43
+
44
+ return (
45
+ <Component className={cx(style, className)} {...restProps}>
46
+ {children}
47
+ </Component>
48
+ )
49
+ }
77
50
 
78
51
  Link.displayName = 'Link'
@@ -0,0 +1,91 @@
1
+ import React from 'react'
2
+ import { cx, Style } from '@sakura-ui/helper'
3
+ import { Card, CardHeader } from './Card'
4
+ import { Icon } from './Icon'
5
+
6
+ interface LinkContextType {
7
+ href: string
8
+ }
9
+ const LinkContext = React.createContext<LinkContextType>({ href: '' })
10
+
11
+ export namespace LinkCard {
12
+ export interface Props extends React.ComponentProps<'article'> {
13
+ href: string
14
+ }
15
+ }
16
+
17
+ export const LinkCard = ({
18
+ href,
19
+ className,
20
+ children,
21
+ ...rest
22
+ }: LinkCard.Props) => {
23
+ const styleLink = `
24
+ grid
25
+ outline-offset-4
26
+ rounded-2xl
27
+ sm:rounded-3xl
28
+ w-full h-full
29
+ ${Style.focusCard}
30
+ `
31
+
32
+ const styleHover = `
33
+ hover:text-blue-1000
34
+ hover:border-blue-1000
35
+ `
36
+
37
+ const isExternal = href?.startsWith('https://')
38
+
39
+ return (
40
+ <LinkContext.Provider value={{ href: href }}>
41
+ <a
42
+ className={cx(styleLink)}
43
+ href={href}
44
+ target={isExternal ? '_blank' : ''}
45
+ >
46
+ <Card className={cx(styleHover, className)} {...rest}>
47
+ {children}
48
+ </Card>
49
+ </a>
50
+ </LinkContext.Provider>
51
+ )
52
+ }
53
+
54
+ export interface LinkCardHeaderProps extends React.ComponentProps<'div'> {}
55
+
56
+ export const LinkCardHeader = ({
57
+ className,
58
+ children
59
+ }: LinkCardHeaderProps) => {
60
+ const { href } = React.useContext(LinkContext)
61
+
62
+ const styleHeading = `
63
+ flex
64
+ justify-between
65
+ items-center
66
+ `
67
+
68
+ const isExternal = href.startsWith('https://')
69
+
70
+ return (
71
+ <CardHeader className={cx(className, styleHeading)}>
72
+ {href === '' ? (
73
+ children
74
+ ) : (
75
+ <>
76
+ <span>
77
+ {children}
78
+ {isExternal ? (
79
+ <Icon opticalSize={16} className="ml-1">
80
+ open_in_new
81
+ </Icon>
82
+ ) : (
83
+ ''
84
+ )}
85
+ </span>
86
+ {isExternal ? '' : <Icon opticalSize={16}>arrow_forward</Icon>}
87
+ </>
88
+ )}
89
+ </CardHeader>
90
+ )
91
+ }
@@ -1,17 +1,18 @@
1
1
  import React from 'react'
2
- import { cx } from '../libs/cx'
2
+ import { cx } from '@sakura-ui/helper'
3
3
 
4
- export interface UlProps extends React.ComponentPropsWithoutRef<'ul'> {}
4
+ export namespace Ul {
5
+ export interface Props extends React.ComponentPropsWithoutRef<'ul'> {}
6
+ }
5
7
 
6
- export const Ul = (props: UlProps) => {
8
+ export const Ul = (props: Ul.Props) => {
7
9
  const { className, children, ...restProps } = props
8
10
 
9
11
  const style = `
10
12
  list-disc
11
- list-inside
12
- -indent-4
13
- pl-4
14
- marker:text-base-sm
13
+ [&_&]:list-circle
14
+ [&_&_&]:list-square
15
+ pl-8
15
16
  `
16
17
  return (
17
18
  <ul className={cx(style, className)} {...restProps}>
@@ -20,16 +21,17 @@ export const Ul = (props: UlProps) => {
20
21
  )
21
22
  }
22
23
 
23
- export interface OlProps extends React.ComponentPropsWithoutRef<'ol'> {}
24
+ export namespace Ol {
25
+ export interface Props extends React.ComponentPropsWithoutRef<'ol'> {}
26
+ }
24
27
 
25
- export const Ol = (props: OlProps) => {
28
+ export const Ol = (props: Ol.Props) => {
26
29
  const { className, children, ...restProps } = props
27
30
 
28
31
  const style = `
29
32
  list-decimal
30
- list-inside
31
- -indent-4
32
- pl-4
33
+ [&_&]:list-lower-latin
34
+ pl-8
33
35
  `
34
36
  return (
35
37
  <ol className={cx(style, className)} {...restProps}>