@sakura-ui/sakura-ui 0.3.0 → 0.4.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 (133) hide show
  1. package/README.md +71 -0
  2. package/package.json +26 -25
  3. package/packages/core/package.json +10 -8
  4. package/packages/core/src/components/Button.tsx +1 -1
  5. package/packages/core/src/components/Card.tsx +8 -3
  6. package/packages/core/src/components/IconButton.tsx +1 -1
  7. package/packages/core/src/components/LangSelector.tsx +2 -2
  8. package/packages/core/src/components/Link.tsx +0 -1
  9. package/packages/core/src/components/LinkCard.tsx +87 -52
  10. package/packages/core/src/components/MenuButton.tsx +2 -2
  11. package/packages/core/src/components/NavigationItem.tsx +1 -1
  12. package/packages/core/src/components/NotificationBanner.tsx +20 -0
  13. package/packages/core/src/components/PopoverMenu.tsx +1 -0
  14. package/packages/core/src/components/buttonStyle.ts +1 -1
  15. package/packages/core/src/components/index.ts +1 -1
  16. package/packages/core/src/icons/index.ts +1 -1
  17. package/packages/core/src/index.ts +1 -0
  18. package/packages/core/vite.config.ts +2 -1
  19. package/packages/forms/.turbo/turbo-build.log +12 -22
  20. package/packages/forms/dist/index.cjs.js +52 -79
  21. package/packages/forms/dist/index.es.js +455 -646
  22. package/packages/forms/dist/types/components/Checkbox.d.ts +2 -2
  23. package/packages/forms/dist/types/components/Checkbox.d.ts.map +1 -1
  24. package/packages/forms/dist/types/components/FieldsetControl.d.ts +2 -2
  25. package/packages/forms/dist/types/components/FieldsetControl.d.ts.map +1 -1
  26. package/packages/forms/dist/types/components/FileInput.d.ts +2 -2
  27. package/packages/forms/dist/types/components/FileInput.d.ts.map +1 -1
  28. package/packages/forms/dist/types/components/Input.d.ts +2 -2
  29. package/packages/forms/dist/types/components/Input.d.ts.map +1 -1
  30. package/packages/forms/dist/types/components/LabelControl.d.ts +2 -2
  31. package/packages/forms/dist/types/components/LabelControl.d.ts.map +1 -1
  32. package/packages/forms/dist/types/components/Radio.d.ts +2 -2
  33. package/packages/forms/dist/types/components/Radio.d.ts.map +1 -1
  34. package/packages/forms/dist/types/components/Select.d.ts +2 -2
  35. package/packages/forms/dist/types/components/Select.d.ts.map +1 -1
  36. package/packages/forms/dist/types/components/Textarea.d.ts +2 -2
  37. package/packages/forms/dist/types/components/Textarea.d.ts.map +1 -1
  38. package/packages/forms/dist/types/components/controlled/CheckboxGroup.d.ts +1 -1
  39. package/packages/forms/dist/types/components/controlled/RadioGroup.d.ts +1 -1
  40. package/packages/forms/dist/types/components/inputStyle.d.ts +1 -1
  41. package/packages/forms/dist/types/components/inputStyle.d.ts.map +1 -1
  42. package/packages/forms/node_modules/.bin/autoprefixer +44 -6
  43. package/packages/forms/package.json +9 -7
  44. package/packages/forms/src/components/Checkbox.tsx +1 -2
  45. package/packages/forms/src/components/FileInput.tsx +3 -3
  46. package/packages/forms/src/components/Input.tsx +0 -1
  47. package/packages/forms/src/components/Radio.tsx +0 -1
  48. package/packages/forms/src/components/Select.tsx +0 -1
  49. package/packages/forms/src/components/Textarea.tsx +0 -1
  50. package/packages/forms/tests/FieldsetControl.test.tsx +8 -2
  51. package/packages/forms/tests/FileInput.test.tsx +30 -5
  52. package/packages/forms/tests/LabelControl.test.tsx +8 -2
  53. package/packages/forms/vite.config.ts +2 -1
  54. package/packages/helper/.turbo/turbo-build.log +12 -23
  55. package/packages/helper/dist/index.cjs.js +7 -9
  56. package/packages/helper/dist/index.es.js +23 -23
  57. package/packages/helper/dist/types/calc.d.ts.map +1 -1
  58. package/packages/helper/dist/types/cx.d.ts.map +1 -1
  59. package/packages/helper/dist/types/styles.d.ts +9 -9
  60. package/packages/helper/dist/types/styles.d.ts.map +1 -1
  61. package/packages/helper/dist/types/treefy.d.ts.map +1 -1
  62. package/packages/helper/node_modules/.bin/vitest +55 -0
  63. package/packages/helper/package.json +13 -3
  64. package/packages/helper/src/cx.ts +1 -1
  65. package/packages/helper/src/styles.ts +2 -4
  66. package/packages/helper/src/treefy.ts +3 -1
  67. package/packages/helper/tests/calc.test.ts +22 -0
  68. package/packages/helper/tests/cx.test.ts +30 -0
  69. package/packages/helper/tests/querySelector.test.ts +24 -0
  70. package/packages/helper/tests/treefy.test.ts +111 -0
  71. package/packages/helper/tests/vitest.setup.ts +2 -0
  72. package/packages/markdown/.turbo/turbo-build.log +12 -22
  73. package/packages/markdown/dist/index.cjs.js +37 -63
  74. package/packages/markdown/dist/index.es.js +4287 -4425
  75. package/packages/markdown/dist/types/components/Markdown.d.ts.map +1 -1
  76. package/packages/markdown/dist/types/plugins/attr.d.ts.map +1 -1
  77. package/packages/markdown/dist/types/plugins/card.d.ts.map +1 -1
  78. package/packages/markdown/dist/types/plugins/cell.d.ts.map +1 -1
  79. package/packages/markdown/dist/types/plugins/faq.d.ts.map +1 -1
  80. package/packages/markdown/dist/types/plugins/grid.d.ts.map +1 -1
  81. package/packages/markdown/dist/types/plugins/headings.d.ts +3 -1
  82. package/packages/markdown/dist/types/plugins/headings.d.ts.map +1 -1
  83. package/packages/markdown/dist/types/plugins/helper.d.ts.map +1 -1
  84. package/packages/markdown/dist/types/plugins/linkButton.d.ts.map +1 -1
  85. package/packages/markdown/dist/types/plugins/youtube.d.ts.map +1 -1
  86. package/packages/markdown/node_modules/.bin/autoprefixer +44 -6
  87. package/packages/markdown/package.json +16 -15
  88. package/packages/markdown/src/components/Markdown.tsx +4 -0
  89. package/packages/markdown/src/plugins/grid.ts +4 -1
  90. package/packages/markdown/src/plugins/headings.ts +6 -3
  91. package/packages/markdown/src/plugins/linkButton.ts +2 -1
  92. package/packages/markdown/src/plugins/youtube.ts +5 -4
  93. package/packages/tailwind-theme-plugin/#package.json# +51 -0
  94. package/packages/tailwind-theme-plugin/.turbo/turbo-build.log +12 -22
  95. package/packages/tailwind-theme-plugin/dist/index.cjs.js +1 -1
  96. package/packages/tailwind-theme-plugin/dist/index.es.js +1111 -1477
  97. package/packages/tailwind-theme-plugin/dist/types/index.d.ts +1 -4
  98. package/packages/tailwind-theme-plugin/dist/types/index.d.ts.map +1 -1
  99. package/packages/tailwind-theme-plugin/node_modules/.bin/autoprefixer +44 -6
  100. package/packages/tailwind-theme-plugin/package.json +8 -6
  101. package/packages/tailwind-theme-plugin/src/index.ts +15 -58
  102. package/packages/tailwind-theme-plugin/vite.config.ts +2 -0
  103. package/packages/forms/node_modules/.bin/tailwind +0 -17
  104. package/packages/forms/node_modules/.bin/tailwindcss +0 -17
  105. package/packages/forms/node_modules/.bin/ts-node +0 -17
  106. package/packages/forms/node_modules/.bin/ts-node-cwd +0 -17
  107. package/packages/forms/node_modules/.bin/ts-node-esm +0 -17
  108. package/packages/forms/node_modules/.bin/ts-node-script +0 -17
  109. package/packages/forms/node_modules/.bin/ts-node-transpile-only +0 -17
  110. package/packages/forms/node_modules/.bin/ts-script +0 -17
  111. package/packages/forms/node_modules/.bin/tsc +0 -17
  112. package/packages/forms/node_modules/.bin/tsserver +0 -17
  113. package/packages/forms/node_modules/.vite/vitest/results.json +0 -1
  114. package/packages/markdown/node_modules/.bin/tailwind +0 -17
  115. package/packages/markdown/node_modules/.bin/tailwindcss +0 -17
  116. package/packages/markdown/node_modules/.bin/ts-node +0 -17
  117. package/packages/markdown/node_modules/.bin/ts-node-cwd +0 -17
  118. package/packages/markdown/node_modules/.bin/ts-node-esm +0 -17
  119. package/packages/markdown/node_modules/.bin/ts-node-script +0 -17
  120. package/packages/markdown/node_modules/.bin/ts-node-transpile-only +0 -17
  121. package/packages/markdown/node_modules/.bin/ts-script +0 -17
  122. package/packages/markdown/node_modules/.bin/tsc +0 -17
  123. package/packages/markdown/node_modules/.bin/tsserver +0 -17
  124. package/packages/tailwind-theme-plugin/node_modules/.bin/tailwind +0 -17
  125. package/packages/tailwind-theme-plugin/node_modules/.bin/tailwindcss +0 -17
  126. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node +0 -17
  127. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node-cwd +0 -17
  128. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node-esm +0 -17
  129. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node-script +0 -17
  130. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-node-transpile-only +0 -17
  131. package/packages/tailwind-theme-plugin/node_modules/.bin/ts-script +0 -17
  132. package/packages/tailwind-theme-plugin/node_modules/.bin/tsc +0 -17
  133. package/packages/tailwind-theme-plugin/node_modules/.bin/tsserver +0 -17
package/README.md CHANGED
@@ -128,5 +128,76 @@ export default App
128
128
  - LabelControl
129
129
  - FieldsetControl
130
130
 
131
+ Every form control takes its accessible name from the label it is associated with, so wrap it in `LabelControl` — or `FieldsetControl` for a group of radios or checkboxes. A control rendered without a label has no name for assistive technology.
132
+
133
+ ```tsx
134
+ <LabelControl labelText="添付書類" isRequired>
135
+ <FileInput />
136
+ </LabelControl>
137
+ ```
138
+
139
+ If a visible label is not an option, pass `aria-label` yourself; it is forwarded to the underlying element.
140
+
131
141
  ## Markdwon extension
132
142
  - Markdown
143
+
144
+ ## Development
145
+
146
+ ### Setup
147
+ ```
148
+ $ pnpm install
149
+ ```
150
+
151
+ ### Run the example app
152
+ `examples` resolves each package to its `src` through Vite aliases, so **no build step is required**. Changes under `packages/*/src` are reflected through HMR.
153
+
154
+ ```
155
+ $ pnpm dev
156
+ ```
157
+
158
+ Then open http://localhost:5173/sakura-ui/
159
+
160
+ ### Build
161
+ ```
162
+ $ pnpm build
163
+ ```
164
+
165
+ Builds go through turbo, which resolves the dependency order — `@sakura-ui/helper` is built before `core` / `forms` / `markdown`. To build a single package, use a filter so that its dependencies are built as well.
166
+
167
+ ```
168
+ $ pnpm build --filter @sakura-ui/core
169
+ ```
170
+
171
+ Running `pnpm build` inside a package directory (e.g. `cd packages/core && pnpm build`) fails while `@sakura-ui/helper` has not been built yet.
172
+
173
+ ### Test
174
+ ```
175
+ $ pnpm test
176
+ ```
177
+
178
+ Runs every package through turbo. To watch a single package while working on it:
179
+
180
+ ```
181
+ $ pnpm --filter @sakura-ui/core test:watch
182
+ ```
183
+
184
+ ### Lint
185
+ ```
186
+ $ pnpm lint
187
+ ```
188
+
189
+ `pnpm lint`, `pnpm build` and `pnpm test` all run on pull requests through the `CI` workflow.
190
+
191
+ ### Publish
192
+ Releases go through npm trusted publishing (OIDC), so no npm token is stored anywhere.
193
+
194
+ 1. Bump the `version` field of the packages to release and merge that to `main`
195
+ 2. Publish a GitHub Release
196
+
197
+ The `Publish` workflow then builds the packages and runs `pnpm publish -r`, which walks the workspace in dependency order and skips versions that are already on npm — `@sakura-ui/helper` goes out before the packages that depend on it.
198
+
199
+ To rehearse without releasing anything, run the workflow manually from the Actions tab: manual runs default to a dry run.
200
+
201
+ Each package needs this repository and `.github/workflows/publish.yaml` registered as its trusted publisher on npmjs.com.
202
+
203
+ Publishing by hand is not supported. npm requires 2FA for direct publishes, and `npm publish` would upload `"@sakura-ui/helper": "workspace:*"` verbatim, since only pnpm expands the workspace protocol at publish time.
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@sakura-ui/sakura-ui",
3
- "version": "0.3.0",
3
+ "version": "0.4.2",
4
4
  "keywords": [],
5
5
  "author": "glassonion1",
6
6
  "homepage": "https://github.com/glassonion1/sakura-ui",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+ssh://git@github.com:glassonion1/sakura-ui.git"
9
+ "url": "git+https://github.com/glassonion1/sakura-ui.git"
10
10
  },
11
11
  "license": "MIT",
12
12
  "files": [
@@ -15,35 +15,36 @@
15
15
  "publishConfig": {
16
16
  "access": "public"
17
17
  },
18
- "scripts": {
19
- "build": "turbo build"
20
- },
21
- "packageManager": "pnpm@9.15.1",
22
18
  "engines": {
23
19
  "pnpm": ">=9.15.1"
24
20
  },
25
21
  "dependencies": {
26
- "@sakura-ui/core": "workspace:*",
27
- "@sakura-ui/forms": "workspace:*",
28
- "@sakura-ui/helper": "workspace:*",
29
- "@sakura-ui/tailwind-theme-plugin": "workspace:*"
22
+ "@sakura-ui/forms": "0.4.2",
23
+ "@sakura-ui/helper": "0.0.9",
24
+ "@sakura-ui/core": "0.4.1",
25
+ "@sakura-ui/tailwind-theme-plugin": "0.4.1"
30
26
  },
31
27
  "peerDependencies": {
32
- "react": "^19.0.0",
33
- "react-dom": "^19.0.0",
34
- "tailwindcss": "^3.4.5"
28
+ "react": "^19.2.1",
29
+ "react-dom": "^19.2.1",
30
+ "tailwindcss": "^4.1.17"
35
31
  },
36
32
  "devDependencies": {
37
- "@biomejs/biome": "^1.9.4",
38
- "@types/node": "^22.10.2",
39
- "@vitejs/plugin-react-swc": "^3.7.2",
40
- "npm-run-all2": "^7.0.1",
41
- "rimraf": "^6.0.1",
42
- "ts-node": "^10.9.2",
43
- "tsc-alias": "^1.8.10",
44
- "turbo": "^2.3.3",
45
- "typescript": "^5.7.2",
46
- "vite": "^6.0.3",
47
- "vitest": "^2.1.8"
33
+ "@biomejs/biome": "^2.5.9",
34
+ "@types/node": "^24.13.3",
35
+ "@vitejs/plugin-react-swc": "^4.3.3",
36
+ "npm-run-all2": "^9.0.3",
37
+ "rimraf": "^6.1.3",
38
+ "tsc-alias": "^1.9.2",
39
+ "turbo": "^2.10.11",
40
+ "typescript": "^5.9.3",
41
+ "vite": "^7.3.6",
42
+ "vitest": "^4.1.11"
43
+ },
44
+ "scripts": {
45
+ "build": "turbo build",
46
+ "dev": "pnpm --filter examples dev",
47
+ "lint": "biome lint ./",
48
+ "test": "turbo test"
48
49
  }
49
- }
50
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sakura-ui/core",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "react",
@@ -14,7 +14,7 @@
14
14
  "homepage": "https://github.com/glassonion1/sakura-ui",
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "git+ssh://git@github.com:glassonion1/sakura-ui.git",
17
+ "url": "git+https://github.com/glassonion1/sakura-ui.git",
18
18
  "directory": "packages/core"
19
19
  },
20
20
  "license": "MIT",
@@ -43,23 +43,25 @@
43
43
  "build": "run-p build:*",
44
44
  "build:scripts": "vite build",
45
45
  "build:types": "tsc && tsc-alias",
46
- "test": "vitest"
46
+ "test": "vitest run",
47
+ "test:watch": "vitest"
47
48
  },
48
49
  "peerDependencies": {
49
- "react": "^19.0.0",
50
- "react-dom": "^19.0.0",
51
- "tailwindcss": "^3.4.5"
50
+ "react": "^19.2.1",
51
+ "react-dom": "^19.2.1",
52
+ "tailwindcss": "^4.1.17"
52
53
  },
53
54
  "dependencies": {
54
- "@sakura-ui/helper": "0.0.5"
55
+ "@sakura-ui/helper": "workspace:*"
55
56
  },
56
57
  "devDependencies": {
57
58
  "@testing-library/jest-dom": "catalog:",
58
59
  "@testing-library/react": "catalog:",
59
60
  "@types/react": "catalog:",
60
61
  "@types/react-dom": "catalog:",
62
+ "@tailwindcss/vite": "catalog:",
61
63
  "autoprefixer": "catalog:",
62
- "happy-dom": "^15.11.7",
64
+ "happy-dom": "catalog:",
63
65
  "postcss": "catalog:",
64
66
  "react": "catalog:",
65
67
  "react-dom": "catalog:",
@@ -17,7 +17,7 @@ export namespace Button {
17
17
  }
18
18
 
19
19
  export const Button = <T extends React.ElementType = 'button'>(
20
- props: Button.Props<T> & Omit<React.ComponentProps<T>, keyof Button.Props<T>>
20
+ props: Button.Props<T> & Omit<ComponentProps<T>, keyof Button.Props<T>>
21
21
  ) => {
22
22
  const {
23
23
  as: Component = 'button',
@@ -28,7 +28,7 @@ export const Card = (props: Card.Props) => {
28
28
  `
29
29
 
30
30
  return (
31
- <IdContext.Provider value={ctx}>
31
+ <IdContext value={ctx}>
32
32
  <article
33
33
  aria-labelledby={ctx.id}
34
34
  aria-describedby={`${ctx.id}-desc`}
@@ -37,7 +37,7 @@ export const Card = (props: Card.Props) => {
37
37
  >
38
38
  {children}
39
39
  </article>
40
- </IdContext.Provider>
40
+ </IdContext>
41
41
  )
42
42
  }
43
43
 
@@ -115,6 +115,11 @@ export namespace CardFooter {
115
115
  export const CardFooter = (props: CardFooter.Props) => {
116
116
  const { className, children, ...restProps } = props
117
117
 
118
+ const stylePosition = `
119
+ sticky
120
+ top-full
121
+ `
122
+
118
123
  const style = `
119
124
  text-base-sm
120
125
  leading-[1.85rem]
@@ -125,7 +130,7 @@ export const CardFooter = (props: CardFooter.Props) => {
125
130
  `
126
131
 
127
132
  return (
128
- <div className={cx(style, className)} {...restProps}>
133
+ <div className={cx(stylePosition, style, className)} {...restProps}>
129
134
  {children}
130
135
  </div>
131
136
  )
@@ -1,4 +1,4 @@
1
- import React, { type ComponentProps } from 'react'
1
+ import React from 'react'
2
2
  import { cx } from '@sakura-ui/helper'
3
3
  import {
4
4
  base,
@@ -67,8 +67,8 @@ export const LangSelector = ({
67
67
  )
68
68
  if (focusables.length === 0) return
69
69
 
70
- const tabIndex = focusables.findIndex(
71
- (el) => el === document.activeElement
70
+ const tabIndex = focusables.indexOf(
71
+ document.activeElement as HTMLElement
72
72
  )
73
73
  // If there is no focused element, focus the first element
74
74
  if (tabIndex === -1) {
@@ -30,7 +30,6 @@ export const Link = <T extends React.ElementType = 'a'>(
30
30
  <Component
31
31
  className={cx(style, className)}
32
32
  target="_blank"
33
- rel="noopener noreferrer"
34
33
  {...restProps}
35
34
  >
36
35
  <span>{children}</span>
@@ -1,25 +1,29 @@
1
1
  import React from 'react'
2
2
  import { cx, Style } from '@sakura-ui/helper'
3
- import { Card, CardHeader } from './Card'
3
+ import { Card, CardFooter, CardHeader } from './Card'
4
4
  import { Icon } from './Icon'
5
5
 
6
- interface LinkContextType {
7
- href: string
8
- }
9
- const LinkContext = React.createContext<LinkContextType>({ href: '' })
10
-
11
6
  export namespace LinkCard {
12
- export interface Props extends React.ComponentProps<'article'> {
7
+ export interface Props<T extends React.ElementType>
8
+ extends React.ComponentProps<'article'> {
13
9
  href: string
10
+ target?: string
11
+ linkAs?: T
14
12
  }
15
13
  }
16
14
 
17
- export const LinkCard = ({
18
- href,
19
- className,
20
- children,
21
- ...rest
22
- }: LinkCard.Props) => {
15
+ export const LinkCard = <T extends React.ElementType = 'a'>(
16
+ props: LinkCard.Props<T>
17
+ ) => {
18
+ const {
19
+ href,
20
+ target,
21
+ linkAs: Component = 'a',
22
+ className,
23
+ children,
24
+ ...rest
25
+ } = props
26
+
23
27
  const styleLink = `
24
28
  grid
25
29
  outline-offset-4
@@ -27,65 +31,96 @@ export const LinkCard = ({
27
31
  sm:rounded-3xl
28
32
  w-full h-full
29
33
  ${Style.focusCard}
34
+ group
30
35
  `
31
36
 
32
37
  const styleHover = `
33
- hover:text-blue-1000
34
- hover:border-blue-1000
38
+ group-hover:outline
39
+ group-hover:outline-blue-900
40
+ group-hover:outline-4
41
+ group-hover:outline-offset-[-1px]
35
42
  `
36
43
 
37
- const isExternal = href?.startsWith('https://')
38
-
39
44
  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>
45
+ <Component className={cx(styleLink)} href={href} target={target}>
46
+ <Card className={cx(styleHover, className)} {...rest}>
47
+ {children}
48
+ </Card>
49
+ </Component>
51
50
  )
52
51
  }
53
52
 
54
- export interface LinkCardHeaderProps extends React.ComponentProps<'div'> {}
53
+ export namespace LinkCardHeader {
54
+ export interface Props extends React.ComponentProps<'div'> {
55
+ target?: string
56
+ }
57
+ }
55
58
 
56
59
  export const LinkCardHeader = ({
60
+ target,
57
61
  className,
58
62
  children
59
- }: LinkCardHeaderProps) => {
60
- const { href } = React.useContext(LinkContext)
61
-
63
+ }: LinkCardHeader.Props) => {
62
64
  const styleHeading = `
65
+ decoration-blue-900
66
+ underline
67
+ underline-offset-[calc(3/16*1rem)]
68
+ `
69
+ const styleHover = `
70
+ group-hover:text-blue-900
71
+ group-hover:decoration-[calc(3/16*1rem)]
72
+ `
73
+
74
+ return (
75
+ <CardHeader className={cx(className, styleHeading, styleHover)}>
76
+ <span>
77
+ {children}
78
+ {target === '_blank' && (
79
+ <Icon opticalSize={16} className="ml-1">
80
+ open_in_new
81
+ </Icon>
82
+ )}
83
+ </span>
84
+ </CardHeader>
85
+ )
86
+ }
87
+
88
+ export namespace LinkCardFooter {
89
+ export interface Props extends React.ComponentProps<'div'> {}
90
+ }
91
+
92
+ export const LinkCardFooter = ({
93
+ className,
94
+ children
95
+ }: LinkCardFooter.Props) => {
96
+ const style = `
63
97
  flex
64
98
  justify-between
65
99
  items-center
66
100
  `
67
101
 
68
- const isExternal = href.startsWith('https://')
102
+ const styleIcon = `
103
+ inline-flex
104
+ items-center
105
+ justify-center
106
+ w-6 h-6
107
+ text-blue-1000
108
+ border
109
+ border-blue-1000
110
+ rounded-full
111
+ `
112
+
113
+ const styleIconHover = `
114
+ group-hover:bg-blue-1000
115
+ group-hover:text-white
116
+ `
69
117
 
70
118
  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>
119
+ <CardFooter className={cx(className, style)}>
120
+ <span>{children}</span>
121
+ <span className={cx(styleIcon, styleIconHover)}>
122
+ <Icon opticalSize={16}>arrow_forward</Icon>
123
+ </span>
124
+ </CardFooter>
90
125
  )
91
126
  }
@@ -48,8 +48,8 @@ export const MenuButton = ({
48
48
  )
49
49
  if (focusables.length === 0) return
50
50
 
51
- const tabIndex = focusables.findIndex(
52
- (el) => el === document.activeElement
51
+ const tabIndex = focusables.indexOf(
52
+ document.activeElement as HTMLElement
53
53
  )
54
54
  // If there is no focused element, focus the first element
55
55
  if (tabIndex === -1) {
@@ -1,4 +1,4 @@
1
- import React, { type ComponentProps } from 'react'
1
+ import React from 'react'
2
2
  import { cx, Style } from '@sakura-ui/helper'
3
3
 
4
4
  export namespace NavigationItem {
@@ -0,0 +1,20 @@
1
+ import React from 'react'
2
+ import { cx } from '@sakura-ui/helper'
3
+ import { Card } from './Card'
4
+
5
+ export namespace NotificationBanner {
6
+ export interface Props extends React.ComponentPropsWithoutRef<'article'> {}
7
+ }
8
+
9
+ export const NotificationBanner = (props: NotificationBanner.Props) => {
10
+ const { className, children, ...restProps } = props
11
+
12
+ const style = `
13
+ `
14
+
15
+ return (
16
+ <Card className={cx(style, className)} {...restProps}>
17
+ {children}
18
+ </Card>
19
+ )
20
+ }
@@ -26,6 +26,7 @@ export const PopoverMenu = React.forwardRef<
26
26
  `
27
27
 
28
28
  return (
29
+ // biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: the WAI-ARIA authoring practices build menus from a ul with role="menu"
29
30
  <ul ref={ref} role="menu" className={cx(className, style)} {...rest}>
30
31
  {children}
31
32
  </ul>
@@ -102,7 +102,7 @@ const params: { [key in ButtonSize]: string } = {
102
102
  py-1.5
103
103
  my-2
104
104
  text-button-sm
105
- rounded
105
+ rounded-sm
106
106
  `
107
107
  }
108
108
 
@@ -1,7 +1,7 @@
1
1
  export { Button } from './Button'
2
2
  export { MenuButton } from './MenuButton'
3
3
  export { Card, CardImg, CardHeader, CardBody, CardFooter } from './Card'
4
- export { LinkCard, LinkCardHeader } from './LinkCard'
4
+ export { LinkCard, LinkCardHeader, LinkCardFooter } from './LinkCard'
5
5
  export { Code } from './Code'
6
6
  export { Faq, Question, Answer } from './Faq'
7
7
  export { H1, H2, H3, H4, H5, H6 } from './Heading'
@@ -5,4 +5,4 @@ export { MenuMobile } from './MenuMobile'
5
5
  export { KeyboadArrowDown } from './KeyboardArrowDown'
6
6
  export { Language } from './Language'
7
7
  export { LanguageMobile } from './LanguageMobile'
8
- export { type IconProps } from './props'
8
+ export type { IconProps } from './props'
@@ -8,6 +8,7 @@ export {
8
8
  CardFooter,
9
9
  LinkCard,
10
10
  LinkCardHeader,
11
+ LinkCardFooter,
11
12
  Code,
12
13
  Faq,
13
14
  Question,
@@ -3,10 +3,11 @@ import { resolve } from 'node:path'
3
3
  import { defineConfig } from 'vite'
4
4
  import react from '@vitejs/plugin-react-swc'
5
5
  import { peerDependencies } from './package.json'
6
+ import tailwindcss from '@tailwindcss/vite'
6
7
 
7
8
  // https://vitejs.dev/config/
8
9
  export default defineConfig({
9
- plugins: [react()],
10
+ plugins: [react(), tailwindcss()],
10
11
  resolve: {
11
12
  alias: {
12
13
  '@': resolve(__dirname, 'src')
@@ -1,22 +1,12 @@
1
-
2
- 
3
- > @sakura-ui/forms@0.3.0 prebuild /Users/t.fujita/Documents/Repos/sakura-ui/packages/forms
4
- > rimraf dist
5
-
6
-
7
- > @sakura-ui/forms@0.3.0 build /Users/t.fujita/Documents/Repos/sakura-ui/packages/forms
8
- > run-p build:*
9
-
10
-
11
- > @sakura-ui/forms@0.3.0 build:types /Users/t.fujita/Documents/Repos/sakura-ui/packages/forms
12
- > tsc && tsc-alias
13
-
14
-
15
- > @sakura-ui/forms@0.3.0 build:scripts /Users/t.fujita/Documents/Repos/sakura-ui/packages/forms
16
- > vite build
17
-
18
- vite v6.0.3 building for production...
19
- transforming (1) src/index.ts✓ 25 modules transformed.
20
- rendering chunks (1)...computing gzip size (0)...computing gzip size (1)...dist/index.es.js 31.87 kB │ gzip: 8.19 kB
21
- rendering chunks (1)...computing gzip size (1)...dist/index.cjs.js 21.92 kB │ gzip: 7.09 kB
22
- ✓ built in 170ms
1
+ $ rimraf dist
2
+ $ run-p build:*
3
+ $ tsc && tsc-alias
4
+ $ vite build
5
+ vite v7.3.6 building client environment for production...
6
+ transforming...
7
+ ✓ 25 modules transformed.
8
+ rendering chunks...
9
+ computing gzip size...
10
+ dist/index.es.js 24.36 kB │ gzip: 6.13 kB
11
+ dist/index.cjs.js 16.94 kB │ gzip: 5.27 kB
12
+ ✓ built in 582ms