@shipfox/react-ui 0.4.0 → 0.6.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 (103) hide show
  1. package/.storybook/main.ts +20 -10
  2. package/.storybook/preview.tsx +11 -0
  3. package/.storybook/vitest.setup.ts +4 -0
  4. package/.turbo/turbo-build.log +16 -3
  5. package/.turbo/turbo-check.log +2 -2
  6. package/.turbo/turbo-type.log +1 -1
  7. package/CHANGELOG.md +15 -0
  8. package/README.md +56 -1
  9. package/argos.config.ts +33 -0
  10. package/dist/build-css-entry.js +5 -0
  11. package/dist/build-css-entry.js.map +1 -0
  12. package/dist/components/button/button-link.d.ts +14 -0
  13. package/dist/components/button/button-link.d.ts.map +1 -0
  14. package/dist/components/button/button-link.js +63 -0
  15. package/dist/components/button/button-link.js.map +1 -0
  16. package/dist/components/button/button-link.stories.js +127 -0
  17. package/dist/components/button/button-link.stories.js.map +1 -0
  18. package/dist/components/button/button.d.ts +1 -1
  19. package/dist/components/button/button.d.ts.map +1 -1
  20. package/dist/components/button/button.js +7 -6
  21. package/dist/components/button/button.js.map +1 -1
  22. package/dist/components/button/button.stories.js +1 -13
  23. package/dist/components/button/button.stories.js.map +1 -1
  24. package/dist/components/button/icon-button.d.ts +14 -0
  25. package/dist/components/button/icon-button.d.ts.map +1 -0
  26. package/dist/components/button/icon-button.js +53 -0
  27. package/dist/components/button/icon-button.js.map +1 -0
  28. package/dist/components/button/icon-button.stories.js +254 -0
  29. package/dist/components/button/icon-button.stories.js.map +1 -0
  30. package/dist/components/button/index.d.ts +2 -0
  31. package/dist/components/button/index.d.ts.map +1 -1
  32. package/dist/components/button/index.js +2 -0
  33. package/dist/components/button/index.js.map +1 -1
  34. package/dist/components/code-block/code-block-footer.d.ts.map +1 -1
  35. package/dist/components/code-block/code-block-footer.js +29 -15
  36. package/dist/components/code-block/code-block-footer.js.map +1 -1
  37. package/dist/components/code-block/code-content.d.ts.map +1 -1
  38. package/dist/components/code-block/code-content.js +2 -2
  39. package/dist/components/code-block/code-content.js.map +1 -1
  40. package/dist/components/dynamic-item/dynamic-item.stories.js +1 -1
  41. package/dist/components/dynamic-item/dynamic-item.stories.js.map +1 -1
  42. package/dist/components/icon/icon.d.ts +3 -0
  43. package/dist/components/icon/icon.d.ts.map +1 -1
  44. package/dist/components/icon/icon.js +5 -2
  45. package/dist/components/icon/icon.js.map +1 -1
  46. package/dist/components/index.d.ts +1 -0
  47. package/dist/components/index.d.ts.map +1 -1
  48. package/dist/components/index.js +1 -0
  49. package/dist/components/index.js.map +1 -1
  50. package/dist/components/modal/index.d.ts +3 -0
  51. package/dist/components/modal/index.d.ts.map +1 -0
  52. package/dist/components/modal/index.js +3 -0
  53. package/dist/components/modal/index.js.map +1 -0
  54. package/dist/components/modal/modal.d.ts +37 -0
  55. package/dist/components/modal/modal.d.ts.map +1 -0
  56. package/dist/components/modal/modal.js +262 -0
  57. package/dist/components/modal/modal.js.map +1 -0
  58. package/dist/components/modal/modal.stories.js +497 -0
  59. package/dist/components/modal/modal.stories.js.map +1 -0
  60. package/dist/components/moving-border/index.d.ts +2 -0
  61. package/dist/components/moving-border/index.d.ts.map +1 -0
  62. package/dist/components/moving-border/index.js +3 -0
  63. package/dist/components/moving-border/index.js.map +1 -0
  64. package/dist/components/typography/text.d.ts.map +1 -1
  65. package/dist/components/typography/text.js +1 -1
  66. package/dist/components/typography/text.js.map +1 -1
  67. package/dist/hooks/index.d.ts +1 -0
  68. package/dist/hooks/index.d.ts.map +1 -1
  69. package/dist/hooks/index.js +1 -0
  70. package/dist/hooks/index.js.map +1 -1
  71. package/dist/hooks/useMediaQuery.d.ts +2 -0
  72. package/dist/hooks/useMediaQuery.d.ts.map +1 -0
  73. package/dist/hooks/useMediaQuery.js +74 -0
  74. package/dist/hooks/useMediaQuery.js.map +1 -0
  75. package/dist/onboarding/sign-in.stories.js +93 -0
  76. package/dist/onboarding/sign-in.stories.js.map +1 -0
  77. package/dist/styles.css +1 -0
  78. package/index.css +30 -4
  79. package/package.json +19 -7
  80. package/src/build-css-entry.ts +3 -0
  81. package/src/components/button/button-link.stories.tsx +86 -0
  82. package/src/components/button/button-link.tsx +76 -0
  83. package/src/components/button/button.stories.tsx +1 -7
  84. package/src/components/button/button.tsx +8 -6
  85. package/src/components/button/icon-button.stories.tsx +182 -0
  86. package/src/components/button/icon-button.tsx +69 -0
  87. package/src/components/button/index.ts +2 -0
  88. package/src/components/code-block/code-block-footer.tsx +37 -30
  89. package/src/components/code-block/code-content.tsx +5 -2
  90. package/src/components/dynamic-item/dynamic-item.stories.tsx +1 -1
  91. package/src/components/icon/icon.tsx +6 -0
  92. package/src/components/index.ts +1 -0
  93. package/src/components/modal/index.ts +23 -0
  94. package/src/components/modal/modal.stories.tsx +384 -0
  95. package/src/components/modal/modal.tsx +309 -0
  96. package/src/components/moving-border/index.ts +1 -0
  97. package/src/components/typography/text.tsx +9 -1
  98. package/src/hooks/index.ts +1 -0
  99. package/src/hooks/useMediaQuery.ts +87 -0
  100. package/src/onboarding/sign-in.stories.tsx +73 -0
  101. package/tsconfig.build.json +7 -1
  102. package/vite.css.config.ts +30 -0
  103. package/vitest.config.ts +30 -3
@@ -24,7 +24,15 @@ export type TextProps = PropsWithChildren<HTMLAttributes<HTMLParagraphElement>>
24
24
  bold?: boolean;
25
25
  };
26
26
 
27
- export function Text({children, className, size, as, compact, bold, ...props}: TextProps) {
27
+ export function Text({
28
+ children,
29
+ className,
30
+ size,
31
+ as,
32
+ compact = true,
33
+ bold = false,
34
+ ...props
35
+ }: TextProps) {
28
36
  const Component = as ?? 'p';
29
37
  return (
30
38
  <Component
@@ -1,4 +1,5 @@
1
1
  export * from './useCopyToClipboard';
2
+ export * from './useMediaQuery';
2
3
  export * from './useResolvedTheme';
3
4
  export * from './useShikiHighlight';
4
5
  export * from './useShikiStyleInjection';
@@ -0,0 +1,87 @@
1
+ import {useEffect, useState} from 'react';
2
+
3
+ class MediaQueryManager {
4
+ private queries = new Map<string, MediaQueryList>();
5
+ private listeners = new Map<string, Set<() => void>>();
6
+ private changeHandlers = new Map<string, () => void>();
7
+
8
+ getMatches(query: string): boolean {
9
+ if (typeof window === 'undefined') return false;
10
+
11
+ if (!this.queries.has(query)) {
12
+ this.queries.set(query, window.matchMedia(query));
13
+ this.listeners.set(query, new Set());
14
+ }
15
+
16
+ const mediaQuery = this.queries.get(query);
17
+ return mediaQuery ? mediaQuery.matches : false;
18
+ }
19
+
20
+ subscribe(query: string, callback: () => void): () => void {
21
+ if (typeof window === 'undefined') {
22
+ return () => {
23
+ // Cleanup function for SSR - no-op
24
+ };
25
+ }
26
+
27
+ if (!this.queries.has(query)) {
28
+ this.queries.set(query, window.matchMedia(query));
29
+ this.listeners.set(query, new Set());
30
+ }
31
+
32
+ const mediaQuery = this.queries.get(query);
33
+ const listeners = this.listeners.get(query);
34
+
35
+ if (!mediaQuery || !listeners) {
36
+ return () => {
37
+ // Cleanup function - no-op if query wasn't found
38
+ };
39
+ }
40
+
41
+ listeners.add(callback);
42
+
43
+ if (listeners.size === 1) {
44
+ const changeHandler = () => {
45
+ for (const cb of listeners) {
46
+ cb();
47
+ }
48
+ };
49
+ this.changeHandlers.set(query, changeHandler);
50
+ mediaQuery.addEventListener('change', changeHandler);
51
+ }
52
+
53
+ return () => {
54
+ listeners.delete(callback);
55
+
56
+ if (listeners.size === 0) {
57
+ const changeHandler = this.changeHandlers.get(query);
58
+ if (changeHandler) {
59
+ mediaQuery.removeEventListener('change', changeHandler);
60
+ this.changeHandlers.delete(query);
61
+ }
62
+ this.queries.delete(query);
63
+ this.listeners.delete(query);
64
+ }
65
+ };
66
+ }
67
+ }
68
+
69
+ const mediaQueryManager = new MediaQueryManager();
70
+
71
+ export function useMediaQuery(query: string): boolean {
72
+ const [matches, setMatches] = useState(() => mediaQueryManager.getMatches(query));
73
+
74
+ useEffect(() => {
75
+ const updateMatches = () => {
76
+ setMatches(mediaQueryManager.getMatches(query));
77
+ };
78
+
79
+ const unsubscribe = mediaQueryManager.subscribe(query, updateMatches);
80
+
81
+ updateMatches();
82
+
83
+ return unsubscribe;
84
+ }, [query]);
85
+
86
+ return matches;
87
+ }
@@ -0,0 +1,73 @@
1
+ import {argosScreenshot} from '@argos-ci/storybook/vitest';
2
+ import type {Meta, StoryObj} from '@storybook/react';
3
+ import {Avatar} from 'components/avatar';
4
+ import {Button} from 'components/button';
5
+ import {Header, Text} from 'components/typography';
6
+
7
+ const meta = {
8
+ title: 'Onboarding/Signin',
9
+ parameters: {
10
+ layout: 'fullscreen',
11
+ },
12
+ } satisfies Meta;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Default: Story = {
18
+ play: async (ctx) => {
19
+ await argosScreenshot(ctx, 'example-screenshot');
20
+ },
21
+ render: () => {
22
+ return (
23
+ <div className="flex min-h-screen items-center justify-center bg-background-subtle-base">
24
+ {/* Background illustration - simplified decorative element */}
25
+ <div className="pointer-events-none absolute left-1/2 top-0 -translate-x-1/2 -translate-y-[120px]">
26
+ <div
27
+ className="h-[332px] w-[800px] opacity-20"
28
+ style={{
29
+ backgroundImage: `radial-gradient(circle, rgba(255, 75, 0, 0.3) 1px, transparent 1px)`,
30
+ backgroundSize: '24px 24px',
31
+ backgroundPosition: '-80px 31px',
32
+ }}
33
+ />
34
+ </div>
35
+
36
+ {/* Main content */}
37
+ <div className="relative flex w-full max-w-[384px] flex-col items-center gap-32 px-24 pb-80 pt-24">
38
+ {/* Logo and title section */}
39
+ <div className="flex flex-col items-center gap-16">
40
+ <Avatar content="logo" size="xl" radius="rounded" logoName="shipfox" />
41
+ <div className="flex min-w-[128px] flex-col items-center gap-4 text-center">
42
+ <Header
43
+ variant="h1"
44
+ className="text-[28px] font-medium leading-[44px] text-foreground-neutral-base"
45
+ >
46
+ Connect to Shipfox
47
+ </Header>
48
+ <Text
49
+ size="sm"
50
+ className="text-sm font-normal leading-[24px] text-foreground-neutral-subtle"
51
+ >
52
+ Log in to access Shipfox.
53
+ </Text>
54
+ </div>
55
+ </div>
56
+
57
+ {/* Action buttons */}
58
+ <div className="flex w-full flex-col gap-20">
59
+ <Button variant="primary" size="md" iconLeft="google" className="w-full">
60
+ Continue with Google
61
+ </Button>
62
+ <Button variant="primary" size="md" iconLeft="microsoft" className="w-full">
63
+ Continue with Microsoft
64
+ </Button>
65
+ <Button variant="transparent" size="md" className="w-full">
66
+ Connect with Enterprise SSO
67
+ </Button>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ );
72
+ },
73
+ };
@@ -9,5 +9,11 @@
9
9
  "types": ["@shipfox/vite/client"]
10
10
  },
11
11
  "include": ["src"],
12
- "exclude": ["**/*.test.tsx", "**/*.test.ts", "**/*.stories.tsx", "**/*.stories.ts"]
12
+ "exclude": [
13
+ "**/*.test.tsx",
14
+ "**/*.test.ts",
15
+ "**/*.stories.tsx",
16
+ "**/*.stories.ts",
17
+ "**/build-css-entry.ts"
18
+ ]
13
19
  }
@@ -0,0 +1,30 @@
1
+ import {dirname, resolve} from 'node:path';
2
+ import {fileURLToPath} from 'node:url';
3
+ import {defineConfig} from '@shipfox/vite';
4
+ import tailwindcss from '@tailwindcss/vite';
5
+ import react from '@vitejs/plugin-react';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ export default defineConfig(
11
+ {
12
+ plugins: [react(), tailwindcss()],
13
+ build: {
14
+ outDir: 'dist',
15
+ emptyOutDir: false,
16
+ cssCodeSplit: false,
17
+ rollupOptions: {
18
+ input: resolve(__dirname, 'src/build-css-entry.ts'),
19
+ output: {
20
+ entryFileNames: 'css-entry.js',
21
+ assetFileNames: 'styles.css',
22
+ },
23
+ },
24
+ },
25
+ css: {
26
+ minify: true,
27
+ },
28
+ },
29
+ import.meta.url,
30
+ );
package/vitest.config.ts CHANGED
@@ -1,6 +1,14 @@
1
+ import * as path from 'node:path';
2
+ import {fileURLToPath} from 'node:url';
3
+ import {argosVitestPlugin} from '@argos-ci/storybook/vitest-plugin';
1
4
  import {defineConfig} from '@shipfox/vitest';
5
+ import {storybookTest} from '@storybook/addon-vitest/vitest-plugin';
2
6
  import tailwindcss from '@tailwindcss/vite';
3
7
  import react from '@vitejs/plugin-react';
8
+ import {playwright} from '@vitest/browser-playwright';
9
+
10
+ const dirname =
11
+ typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
4
12
 
5
13
  // https://vitejs.dev/config/
6
14
  export default defineConfig(
@@ -8,9 +16,28 @@ export default defineConfig(
8
16
  plugins: [react(), tailwindcss()],
9
17
  css: {},
10
18
  test: {
11
- environment: 'jsdom',
12
- setupFiles: ['./test/setup.ts'],
13
- globalSetup: './test/global.ts',
19
+ projects: [
20
+ {
21
+ extends: true,
22
+ plugins: [
23
+ storybookTest({configDir: path.join(dirname, '.storybook')}),
24
+ argosVitestPlugin({
25
+ uploadToArgos: !!process.env.CI,
26
+ token: process.env.ARGOS_TOKEN,
27
+ }),
28
+ ],
29
+ test: {
30
+ name: 'storybook',
31
+ browser: {
32
+ enabled: true,
33
+ headless: true,
34
+ provider: playwright(),
35
+ instances: [{browser: 'chromium'}],
36
+ },
37
+ setupFiles: ['.storybook/vitest.setup.ts'],
38
+ },
39
+ },
40
+ ],
14
41
  },
15
42
  },
16
43
  import.meta.url,