webcoreui 1.2.0 → 1.4.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 (82) hide show
  1. package/README.md +14 -6
  2. package/astro.d.ts +9 -0
  3. package/astro.js +6 -0
  4. package/components/Accordion/Accordion.astro +1 -0
  5. package/components/Accordion/Accordion.svelte +1 -1
  6. package/components/Accordion/Accordion.tsx +1 -1
  7. package/components/Accordion/accordion.ts +1 -0
  8. package/components/Avatar/Avatar.astro +4 -2
  9. package/components/Avatar/Avatar.svelte +6 -4
  10. package/components/Avatar/Avatar.tsx +4 -2
  11. package/components/Badge/Badge.astro +2 -0
  12. package/components/Badge/Badge.svelte +2 -0
  13. package/components/Badge/Badge.tsx +2 -0
  14. package/components/Badge/badge.module.scss +26 -0
  15. package/components/Badge/badge.ts +1 -0
  16. package/components/Checkbox/Checkbox.svelte +2 -0
  17. package/components/Checkbox/Checkbox.tsx +0 -2
  18. package/components/Checkbox/checkbox.ts +3 -1
  19. package/components/Collapsible/collapsible.ts +1 -1
  20. package/components/Counter/Counter.astro +164 -0
  21. package/components/Counter/Counter.svelte +141 -0
  22. package/components/Counter/Counter.tsx +161 -0
  23. package/components/Counter/counter.module.scss +155 -0
  24. package/components/Counter/counter.ts +21 -0
  25. package/components/DataTable/DataTable.astro +4 -4
  26. package/components/DataTable/DataTable.svelte +1 -1
  27. package/components/DataTable/DataTable.tsx +2 -2
  28. package/components/Icon/map.ts +2 -0
  29. package/components/Image/Image.astro +45 -0
  30. package/components/Image/Image.svelte +51 -0
  31. package/components/Image/Image.tsx +52 -0
  32. package/components/Image/image.module.scss +47 -0
  33. package/components/Image/image.ts +13 -0
  34. package/components/ImageLoader/ImageLoader.astro +82 -0
  35. package/components/ImageLoader/ImageLoader.svelte +72 -0
  36. package/components/ImageLoader/ImageLoader.tsx +82 -0
  37. package/components/ImageLoader/imageloader.module.scss +13 -0
  38. package/components/ImageLoader/imageloader.ts +6 -0
  39. package/components/Input/input.ts +2 -2
  40. package/components/List/List.astro +3 -0
  41. package/components/List/List.svelte +12 -9
  42. package/components/List/List.tsx +3 -0
  43. package/components/List/list.module.scss +5 -0
  44. package/components/List/list.ts +40 -39
  45. package/components/Menu/Menu.tsx +1 -1
  46. package/components/Pagination/Pagination.tsx +1 -1
  47. package/components/Pagination/pagination.module.scss +1 -0
  48. package/components/Popover/Popover.astro +28 -26
  49. package/components/Popover/Popover.svelte +2 -0
  50. package/components/Popover/Popover.tsx +2 -0
  51. package/components/Popover/popover.module.scss +10 -2
  52. package/components/Popover/popover.ts +17 -16
  53. package/components/Progress/Progress.astro +6 -2
  54. package/components/Progress/Progress.svelte +6 -2
  55. package/components/Progress/Progress.tsx +6 -2
  56. package/components/Progress/progress.module.scss +15 -0
  57. package/components/Progress/progress.ts +1 -0
  58. package/components/RangeSlider/RangeSlider.astro +5 -0
  59. package/components/RangeSlider/RangeSlider.svelte +3 -3
  60. package/components/RangeSlider/RangeSlider.tsx +1 -1
  61. package/components/RangeSlider/rangeslider.ts +1 -0
  62. package/components/Switch/Switch.svelte +2 -0
  63. package/components/Switch/Switch.tsx +0 -2
  64. package/components/Switch/switch.module.scss +1 -0
  65. package/components/Switch/switch.ts +3 -1
  66. package/components/Textarea/Textarea.svelte +2 -0
  67. package/components/Textarea/textarea.ts +7 -6
  68. package/components/ThemeSwitcher/themeswitcher.module.scss +1 -0
  69. package/components/ThemeSwitcher/themeswitcher.ts +1 -0
  70. package/icons/minus.svg +3 -0
  71. package/icons.d.ts +1 -0
  72. package/icons.js +1 -0
  73. package/index.d.ts +12 -5
  74. package/package.json +111 -109
  75. package/react.d.ts +9 -0
  76. package/react.js +6 -0
  77. package/scss/resets.scss +2 -0
  78. package/svelte.d.ts +9 -0
  79. package/svelte.js +6 -0
  80. package/utils/DOMUtils.ts +3 -3
  81. package/utils/modal.ts +2 -2
  82. package/utils/popover.ts +87 -46
package/package.json CHANGED
@@ -1,109 +1,111 @@
1
- {
2
- "name": "webcoreui",
3
- "type": "module",
4
- "version": "1.2.0",
5
- "scripts": {
6
- "prepare": "husky",
7
- "pre-commit": "lint-staged",
8
- "dev": "astro dev",
9
- "start": "astro preview",
10
- "build": "astro check && astro build",
11
- "build:package": "node scripts/build.js",
12
- "compile": "node scripts/sass.js",
13
- "test": "cd .. && vitest run && npm run test:sass",
14
- "test:dev": "vitest",
15
- "test:run": "vitest run",
16
- "test:sass": "vitest run src/tests/unit/scss.test.js --config astro.config.mjs",
17
- "test:e2e": "playwright test",
18
- "test:e2e:update": "playwright test --update-snapshots",
19
- "test:e2e:ui": "playwright test --ui",
20
- "create-component": "node scripts/createComponent.js",
21
- "lint": "eslint src/**/* --fix"
22
- },
23
- "devDependencies": {
24
- "@astrojs/check": "0.9.4",
25
- "@astrojs/node": "9.4.1",
26
- "@astrojs/react": "4.3.0",
27
- "@astrojs/svelte": "7.1.0",
28
- "@eslint/js": "9.23.0",
29
- "@playwright/test": "1.55.1",
30
- "@types/node": "24.6.2",
31
- "@typescript-eslint/parser": "8.39.1",
32
- "astro": "5.13.0",
33
- "astro-eslint-parser": "1.2.2",
34
- "eslint": "9.23.0",
35
- "eslint-plugin-astro": "1.3.1",
36
- "eslint-plugin-react": "7.37.4",
37
- "eslint-plugin-simple-import-sort": "12.1.1",
38
- "eslint-plugin-svelte": "3.3.3",
39
- "husky": "9.1.7",
40
- "jsdom": "26.0.0",
41
- "lint-staged": "15.5.0",
42
- "react": "19.0.0",
43
- "react-dom": "19.0.0",
44
- "sass": "1.90.0",
45
- "sass-true": "8.1.0",
46
- "svelte": "5.38.1",
47
- "svelte-eslint-parser": "1.1.0",
48
- "typescript": "5.9.2",
49
- "typescript-eslint": "8.39.1",
50
- "vite-tsconfig-paths": "5.1.4",
51
- "vitest": "3.0.4"
52
- },
53
- "exports": {
54
- ".": "./index.js",
55
- "./astro": "./astro.js",
56
- "./svelte": "./svelte.js",
57
- "./react": "./react.js",
58
- "./icons": "./icons.js",
59
- "./integration": "./integration.js",
60
- "./styles": "./scss/index.scss",
61
- "./config": "./scss/config.scss"
62
- },
63
- "files": [
64
- "components",
65
- "icons",
66
- "scss",
67
- "utils",
68
- "astro.d.ts",
69
- "astro.js",
70
- "icons.d.ts",
71
- "icons.js",
72
- "svelte.d.ts",
73
- "svelte.js",
74
- "react.d.ts",
75
- "react.js",
76
- "index.js",
77
- "index.d.ts",
78
- "integration.js",
79
- "integration.d.ts",
80
- "README.md",
81
- "LICENSE"
82
- ],
83
- "license": "MIT",
84
- "description": "UI component and template library for Astro, Svelte, and React apps styled with Sass.",
85
- "keywords": [
86
- "webcore",
87
- "component",
88
- "components",
89
- "ui components",
90
- "component library",
91
- "astro components",
92
- "svelte components",
93
- "react components",
94
- "frontend",
95
- "library",
96
- "sass"
97
- ],
98
- "homepage": "https://webcoreui.dev",
99
- "repository": {
100
- "type": "git",
101
- "url": "git+https://github.com/Frontendland/webcoreui.git"
102
- },
103
- "bugs": {
104
- "url": "https://github.com/Frontendland/webcoreui/issues"
105
- },
106
- "lint-staged": {
107
- "*.{js,ts,jsx,tsx,svelte,astro}": "eslint src/**/*"
108
- }
109
- }
1
+ {
2
+ "name": "webcoreui",
3
+ "type": "module",
4
+ "version": "1.4.0",
5
+ "scripts": {
6
+ "prepare": "husky",
7
+ "pre-commit": "lint-staged",
8
+ "dev": "astro dev",
9
+ "start": "astro preview",
10
+ "build": "astro check && astro build",
11
+ "build:package": "node scripts/build.js",
12
+ "compile": "node scripts/sass.js",
13
+ "test": "cd .. && vitest run && npm run test:sass",
14
+ "test:dev": "vitest",
15
+ "test:run": "vitest run",
16
+ "test:sass": "vitest run src/tests/unit/scss.test.js --config astro.config.mjs",
17
+ "test:e2e": "playwright test",
18
+ "test:e2e:update": "playwright test --update-snapshots",
19
+ "test:e2e:ui": "playwright test --ui",
20
+ "create-component": "node scripts/createComponent.js",
21
+ "lint": "eslint src/**/* --fix"
22
+ },
23
+ "devDependencies": {
24
+ "@astrojs/check": "0.9.6",
25
+ "@astrojs/node": "9.5.4",
26
+ "@astrojs/react": "4.4.2",
27
+ "@astrojs/svelte": "7.2.5",
28
+ "@eslint/js": "9.39.3",
29
+ "@playwright/test": "1.58.2",
30
+ "@types/node": "25.3.0",
31
+ "@typescript-eslint/parser": "8.56.1",
32
+ "astro": "5.17.3",
33
+ "astro-eslint-parser": "1.3.0",
34
+ "eslint": "9.39.3",
35
+ "eslint-plugin-astro": "1.6.0",
36
+ "eslint-plugin-react": "7.37.5",
37
+ "eslint-plugin-simple-import-sort": "12.1.1",
38
+ "eslint-plugin-svelte": "3.15.0",
39
+ "husky": "9.1.7",
40
+ "jsdom": "28.1.0",
41
+ "lint-staged": "16.2.7",
42
+ "react": "19.2.4",
43
+ "react-dom": "19.2.4",
44
+ "sass": "1.97.3",
45
+ "sass-true": "10.1.0",
46
+ "svelte": "5.53.3",
47
+ "svelte-eslint-parser": "1.5.1",
48
+ "typescript": "5.9.3",
49
+ "typescript-eslint": "8.56.1",
50
+ "vite-tsconfig-paths": "6.1.1",
51
+ "vitest": "4.0.18"
52
+ },
53
+ "exports": {
54
+ ".": "./index.js",
55
+ "./astro": "./astro.js",
56
+ "./svelte": "./svelte.js",
57
+ "./react": "./react.js",
58
+ "./icons": "./icons.js",
59
+ "./integration": "./integration.js",
60
+ "./styles": "./scss/index.scss",
61
+ "./config": "./scss/config.scss"
62
+ },
63
+ "files": [
64
+ "components",
65
+ "icons",
66
+ "scss",
67
+ "utils",
68
+ "astro.d.ts",
69
+ "astro.js",
70
+ "icons.d.ts",
71
+ "icons.js",
72
+ "svelte.d.ts",
73
+ "svelte.js",
74
+ "react.d.ts",
75
+ "react.js",
76
+ "index.js",
77
+ "index.d.ts",
78
+ "integration.js",
79
+ "integration.d.ts",
80
+ "README.md",
81
+ "LICENSE"
82
+ ],
83
+ "license": "MIT",
84
+ "description": "UI component and template library for Astro, Svelte, and React apps styled with Sass.",
85
+ "keywords": [
86
+ "webcore",
87
+ "components",
88
+ "ui components",
89
+ "ui library",
90
+ "component library",
91
+ "withastro",
92
+ "astro",
93
+ "astro ui",
94
+ "astro ui library",
95
+ "astro-component",
96
+ "astro components",
97
+ "svelte components",
98
+ "react components"
99
+ ],
100
+ "homepage": "https://webcoreui.dev",
101
+ "repository": {
102
+ "type": "git",
103
+ "url": "git+https://github.com/Frontendland/webcoreui.git"
104
+ },
105
+ "bugs": {
106
+ "url": "https://github.com/Frontendland/webcoreui/issues"
107
+ },
108
+ "lint-staged": {
109
+ "*.{js,ts,jsx,tsx,svelte,astro}": "eslint src/**/*"
110
+ }
111
+ }
package/react.d.ts CHANGED
@@ -15,12 +15,15 @@ import type { ReactCollapsibleProps as WReactCollapsibleProps } from './componen
15
15
  import type { ReactConditionalWrapperProps as WReactConditionalWrapperProps } from './components/ConditionalWrapper/conditionalwrapper'
16
16
  import type { ReactContextMenuProps as WReactContextMenuProps } from './components/ContextMenu/contextmenu'
17
17
  import type { ReactCopyProps as WReactCopyProps } from './components/Copy/copy'
18
+ import type { ReactCounterProps as WReactCounterProps } from './components/Counter/counter'
18
19
  import type { ReactDataTableProps as WReactDataTableProps } from './components/DataTable/datatable'
19
20
  import type { ReactFlexProps as WReactFlexProps } from './components/Flex/flex'
20
21
  import type { ReactFooterProps as WReactFooterProps } from './components/Footer/footer'
21
22
  import type { ReactGridProps as WReactGridProps } from './components/Grid/grid'
22
23
  import type { ReactGroupProps as WReactGroupProps } from './components/Group/group'
23
24
  import type { IconProps as WIconProps } from './components/Icon/icon'
25
+ import type { ImageProps as WImageProps } from './components/Image/image'
26
+ import type { ImageLoaderProps as WImageLoaderProps } from './components/ImageLoader/imageloader'
24
27
  import type { ReactInputProps as WReactInputProps } from './components/Input/input'
25
28
  import type { ReactKbdProps as WReactKbdProps } from './components/Kbd/kbd'
26
29
  import type { ReactListProps as WReactListProps } from './components/List/list'
@@ -76,12 +79,15 @@ declare module 'webcoreui/react' {
76
79
  export const ConditionalWrapper: FC<WReactConditionalWrapperProps>
77
80
  export const ContextMenu: FC<WReactContextMenuProps>
78
81
  export const Copy: FC<WReactCopyProps>
82
+ export const Counter: FC<WReactCounterProps>
79
83
  export const DataTable: FC<WReactDataTableProps>
80
84
  export const Flex: FC<WReactFlexProps>
81
85
  export const Footer: FC<WReactFooterProps>
82
86
  export const Grid: FC<WReactGridProps>
83
87
  export const Group: FC<WReactGroupProps>
84
88
  export const Icon: FC<WIconProps>
89
+ export const Image: FC<WImageProps>
90
+ export const ImageLoader: FC<WImageLoaderProps>
85
91
  export const Input: FC<WReactInputProps>
86
92
  export const Kbd: FC<WReactKbdProps>
87
93
  export const List: FC<WReactListProps>
@@ -130,12 +136,15 @@ declare module 'webcoreui/react' {
130
136
  export type ConditionalWrapperProps = WReactConditionalWrapperProps
131
137
  export type ContextMenuProps = WReactContextMenuProps
132
138
  export type CopyProps = WReactCopyProps
139
+ export type CounterProps = WReactCounterProps
133
140
  export type DataTableProps = WReactDataTableProps
134
141
  export type FlexProps = WReactFlexProps
135
142
  export type FooterProps = WReactFooterProps
136
143
  export type GridProps = WReactGridProps
137
144
  export type GroupProps = WReactGroupProps
138
145
  export type IconProps = WIconProps
146
+ export type ImageProps = WImageProps
147
+ export type ImageLoaderProps = WImageLoaderProps
139
148
  export type InputProps = WReactInputProps
140
149
  export type KbdProps = WReactKbdProps
141
150
  export type ListProps = WReactListProps
package/react.js CHANGED
@@ -14,12 +14,15 @@ import CollapsibleComponent from './components/Collapsible/Collapsible.tsx'
14
14
  import ConditionalWrapperComponent from './components/ConditionalWrapper/ConditionalWrapper.tsx'
15
15
  import ContextMenuComponent from './components/ContextMenu/ContextMenu.tsx'
16
16
  import CopyComponent from './components/Copy/Copy.tsx'
17
+ import CounterComponent from './components/Counter/Counter.tsx'
17
18
  import DataTableComponent from './components/DataTable/DataTable.tsx'
18
19
  import FlexComponent from './components/Flex/Flex.tsx'
19
20
  import FooterComponent from './components/Footer/Footer.tsx'
20
21
  import GridComponent from './components/Grid/Grid.tsx'
21
22
  import GroupComponent from './components/Group/Group.tsx'
22
23
  import IconComponent from './components/Icon/Icon.tsx'
24
+ import ImageComponent from './components/Image/Image.tsx'
25
+ import ImageLoaderComponent from './components/ImageLoader/ImageLoader.tsx'
23
26
  import InputComponent from './components/Input/Input.tsx'
24
27
  import KbdComponent from './components/Kbd/Kbd.tsx'
25
28
  import ListComponent from './components/List/List.tsx'
@@ -68,12 +71,15 @@ export const Collapsible = CollapsibleComponent
68
71
  export const ConditionalWrapper = ConditionalWrapperComponent
69
72
  export const ContextMenu = ContextMenuComponent
70
73
  export const Copy = CopyComponent
74
+ export const Counter = CounterComponent
71
75
  export const DataTable = DataTableComponent
72
76
  export const Flex = FlexComponent
73
77
  export const Footer = FooterComponent
74
78
  export const Grid = GridComponent
75
79
  export const Group = GroupComponent
76
80
  export const Icon = IconComponent
81
+ export const Image = ImageComponent
82
+ export const ImageLoader = ImageLoaderComponent
77
83
  export const Input = InputComponent
78
84
  export const Kbd = KbdComponent
79
85
  export const List = ListComponent
package/scss/resets.scss CHANGED
@@ -72,7 +72,9 @@
72
72
  }
73
73
 
74
74
  img {
75
+ @include visibility(block);
75
76
  @include border-radius();
77
+
76
78
  object-fit: cover;
77
79
  }
78
80
 
package/svelte.d.ts CHANGED
@@ -15,12 +15,15 @@ import type { SvelteCollapsibleProps as WSvelteCollapsibleProps } from './compon
15
15
  import type { SvelteConditionalWrapperProps as WSvelteConditionalWrapperProps } from './components/ConditionalWrapper/conditionalwrapper'
16
16
  import type { SvelteContextMenuProps as WSvelteContextMenuProps } from './components/ContextMenu/contextmenu'
17
17
  import type { SvelteCopyProps as WSvelteCopyProps } from './components/Copy/copy'
18
+ import type { SvelteCounterProps as WSvelteCounterProps } from './components/Counter/counter'
18
19
  import type { SvelteDataTableProps as WSvelteDataTableProps } from './components/DataTable/datatable'
19
20
  import type { SvelteFlexProps as WSvelteFlexProps } from './components/Flex/flex'
20
21
  import type { SvelteFooterProps as WSvelteFooterProps } from './components/Footer/footer'
21
22
  import type { SvelteGridProps as WSvelteGridProps } from './components/Grid/grid'
22
23
  import type { SvelteGroupProps as WSvelteGroupProps } from './components/Group/group'
23
24
  import type { IconProps as WIconProps } from './components/Icon/icon'
25
+ import type { ImageProps as WImageProps } from './components/Image/image'
26
+ import type { ImageLoaderProps as WImageLoaderProps } from './components/ImageLoader/imageloader'
24
27
  import type { SvelteInputProps as WSvelteInputProps } from './components/Input/input'
25
28
  import type { SvelteKbdProps as WSvelteKbdProps } from './components/Kbd/kbd'
26
29
  import type { SvelteListProps as WSvelteListProps } from './components/List/list'
@@ -76,12 +79,15 @@ declare module 'webcoreui/svelte' {
76
79
  export const ConditionalWrapper: Component<WSvelteConditionalWrapperProps>
77
80
  export const ContextMenu: Component<WSvelteContextMenuProps>
78
81
  export const Copy: Component<WSvelteCopyProps>
82
+ export const Counter: Component<WSvelteCounterProps>
79
83
  export const DataTable: Component<WSvelteDataTableProps>
80
84
  export const Flex: Component<WSvelteFlexProps>
81
85
  export const Footer: Component<WSvelteFooterProps>
82
86
  export const Grid: Component<WSvelteGridProps>
83
87
  export const Group: Component<WSvelteGroupProps>
84
88
  export const Icon: Component<WIconProps>
89
+ export const Image: Component<WImageProps>
90
+ export const ImageLoader: Component<WImageLoaderProps>
85
91
  export const Input: Component<WSvelteInputProps>
86
92
  export const Kbd: Component<WSvelteKbdProps>
87
93
  export const List: Component<WSvelteListProps>
@@ -130,12 +136,15 @@ declare module 'webcoreui/svelte' {
130
136
  export type ConditionalWrapperProps = WSvelteConditionalWrapperProps
131
137
  export type ContextMenuProps = WSvelteContextMenuProps
132
138
  export type CopyProps = WSvelteCopyProps
139
+ export type CounterProps = WSvelteCounterProps
133
140
  export type DataTableProps = WSvelteDataTableProps
134
141
  export type FlexProps = WSvelteFlexProps
135
142
  export type FooterProps = WSvelteFooterProps
136
143
  export type GridProps = WSvelteGridProps
137
144
  export type GroupProps = WSvelteGroupProps
138
145
  export type IconProps = WIconProps
146
+ export type ImageProps = WImageProps
147
+ export type ImageLoaderProps = WImageLoaderProps
139
148
  export type InputProps = WSvelteInputProps
140
149
  export type KbdProps = WSvelteKbdProps
141
150
  export type ListProps = WSvelteListProps
package/svelte.js CHANGED
@@ -14,12 +14,15 @@ import CollapsibleComponent from './components/Collapsible/Collapsible.svelte'
14
14
  import ConditionalWrapperComponent from './components/ConditionalWrapper/ConditionalWrapper.svelte'
15
15
  import ContextMenuComponent from './components/ContextMenu/ContextMenu.svelte'
16
16
  import CopyComponent from './components/Copy/Copy.svelte'
17
+ import CounterComponent from './components/Counter/Counter.svelte'
17
18
  import DataTableComponent from './components/DataTable/DataTable.svelte'
18
19
  import FlexComponent from './components/Flex/Flex.svelte'
19
20
  import FooterComponent from './components/Footer/Footer.svelte'
20
21
  import GridComponent from './components/Grid/Grid.svelte'
21
22
  import GroupComponent from './components/Group/Group.svelte'
22
23
  import IconComponent from './components/Icon/Icon.svelte'
24
+ import ImageComponent from './components/Image/Image.svelte'
25
+ import ImageLoaderComponent from './components/ImageLoader/ImageLoader.svelte'
23
26
  import InputComponent from './components/Input/Input.svelte'
24
27
  import KbdComponent from './components/Kbd/Kbd.svelte'
25
28
  import ListComponent from './components/List/List.svelte'
@@ -68,12 +71,15 @@ export const Collapsible = CollapsibleComponent
68
71
  export const ConditionalWrapper = ConditionalWrapperComponent
69
72
  export const ContextMenu = ContextMenuComponent
70
73
  export const Copy = CopyComponent
74
+ export const Counter = CounterComponent
71
75
  export const DataTable = DataTableComponent
72
76
  export const Flex = FlexComponent
73
77
  export const Footer = FooterComponent
74
78
  export const Grid = GridComponent
75
79
  export const Group = GroupComponent
76
80
  export const Icon = IconComponent
81
+ export const Image = ImageComponent
82
+ export const ImageLoader = ImageLoaderComponent
77
83
  export const Input = InputComponent
78
84
  export const Kbd = KbdComponent
79
85
  export const List = ListComponent
package/utils/DOMUtils.ts CHANGED
@@ -1,6 +1,6 @@
1
- export const get = (selector: string, all?: boolean) => all
2
- ? document?.querySelectorAll(selector)
3
- : document?.querySelector(selector)
1
+ export const get = <T extends Element = Element>(selector: string, all?: boolean): T | NodeListOf<T> | null => all
2
+ ? document?.querySelectorAll<T>(selector)
3
+ : document?.querySelector<T>(selector)
4
4
 
5
5
  export const on = (
6
6
  selector: string | HTMLElement | Document,
package/utils/modal.ts CHANGED
@@ -13,7 +13,7 @@ export type ModalCallback = {
13
13
  }
14
14
 
15
15
  export type Modal = {
16
- trigger: string
16
+ trigger?: string
17
17
  modal: string
18
18
  onOpen?: (args: ModalCallback) => unknown
19
19
  onClose?: (args: ModalCallback) => unknown
@@ -29,7 +29,7 @@ export const modal = (config: Modal | string): ModalInstance | undefined => {
29
29
 
30
30
  const modalSelector = typeof config === 'string' ? config : modal
31
31
 
32
- const triggerDOM = document.querySelector(trigger)
32
+ const triggerDOM = trigger ? document.querySelector(trigger) : null
33
33
  const modalDOM = document.querySelector(modalSelector)
34
34
 
35
35
  if (modalDOM instanceof HTMLElement) {
package/utils/popover.ts CHANGED
@@ -14,6 +14,12 @@ export type PopoverPosition = 'top'
14
14
  | 'bottom-start'
15
15
  | 'bottom-end'
16
16
 
17
+ export type PopoverInstance = {
18
+ close: () => void
19
+ destroy: () => void
20
+ remove: () => void
21
+ }
22
+
17
23
  export type PopoverCallback = {
18
24
  trigger: HTMLElement
19
25
  popover: HTMLElement
@@ -40,7 +46,7 @@ export const popover = ({
40
46
  closeOnEsc = true,
41
47
  onOpen,
42
48
  onClose
43
- }: Popover) => {
49
+ }: Popover): PopoverInstance | undefined => {
44
50
  const triggerDOM = document.querySelector(trigger) as HTMLElement
45
51
  const popoverDOM = document.querySelector(popover) as HTMLElement
46
52
 
@@ -51,7 +57,7 @@ export const popover = ({
51
57
  popoverDOM.dataset.position = position.split('-')[0]
52
58
  }
53
59
 
54
- const handleOpen = () => {
60
+ const getPosition = () => {
55
61
  const triggerPosition = triggerDOM.getBoundingClientRect()
56
62
  const popoverPosition = popoverDOM.getBoundingClientRect()
57
63
 
@@ -139,77 +145,105 @@ export const popover = ({
139
145
  }
140
146
  }
141
147
 
142
- const { top, left } = positions[position as keyof typeof positions] || positions.bottom
148
+ let finalPosition = position || 'bottom'
149
+ let { top, left } = positions[finalPosition]
150
+
151
+ const viewportTop = window.scrollY
152
+ const viewportBottom = window.scrollY + window.innerHeight
153
+ const viewportLeft = 0
154
+ const viewportRight = window.innerWidth
155
+
156
+ const overflowsTop = top < viewportTop
157
+ const overflowsBottom = top + popoverPosition.height > viewportBottom
158
+ const overflowsLeft = left < viewportLeft
159
+ const overflowsRight = left + popoverPosition.width > viewportRight
160
+
161
+ if (finalPosition.startsWith('bottom') && overflowsBottom) {
162
+ finalPosition = finalPosition.replace('bottom', 'top') as PopoverPosition
163
+ } else if (finalPosition.startsWith('top') && overflowsTop) {
164
+ finalPosition = finalPosition.replace('top', 'bottom') as PopoverPosition
165
+ } else if (finalPosition.startsWith('right') && overflowsRight) {
166
+ finalPosition = finalPosition.replace('right', 'left') as PopoverPosition
167
+ } else if (finalPosition.startsWith('left') && overflowsLeft) {
168
+ finalPosition = finalPosition.replace('left', 'right') as PopoverPosition
169
+ }
170
+
171
+ ({ top, left } = positions[finalPosition])
172
+
173
+ top = Math.max(viewportTop, Math.min(top, viewportBottom - popoverPosition.height))
174
+ left = Math.max(viewportLeft, Math.min(left, viewportRight - popoverPosition.width))
143
175
 
176
+ popoverDOM.dataset.position = finalPosition.split('-')[0]
177
+
178
+ return { top, left }
179
+ }
180
+
181
+ const handleOpen = () => {
182
+ const { top, left } = getPosition()
183
+
184
+ popoverDOM.dataset.noTransition = 'true'
144
185
  popoverDOM.style.top = `${top}px`
145
186
  popoverDOM.style.left = `${left}px`
146
187
 
147
- setTimeout(() => {
148
- popoverDOM.dataset.show = popoverDOM.dataset.show === 'true'
149
- ? ''
150
- : 'true'
151
- }, 0)
188
+ popoverDOM.getBoundingClientRect()
189
+ popoverDOM.removeAttribute('data-no-transition')
152
190
 
153
- setTimeout(() => {
154
- if (!popoverDOM.dataset.show) {
155
- popoverDOM.removeAttribute('data-show')
156
- }
157
- }, 300)
191
+ if (popoverDOM.dataset.show) {
192
+ popoverDOM.removeAttribute('data-show')
193
+ } else {
194
+ popoverDOM.dataset.show = 'true'
195
+ }
158
196
 
159
197
  onOpen?.({
160
198
  trigger: triggerDOM,
161
199
  popover: popoverDOM,
162
- position
200
+ position: popoverDOM.dataset.position as PopoverPosition
163
201
  })
164
202
  }
165
203
 
166
- const handleClose = (event: MouseEvent) => {
167
- const target = event.target as HTMLElement
168
- const hidePopover = !popoverDOM.contains(target)
169
- && !triggerDOM.contains(target)
170
- && popoverDOM.dataset.show
204
+ const closePopover = () => {
205
+ if (popoverDOM.dataset.show !== 'true') {
206
+ return
207
+ }
171
208
 
172
- if (hidePopover) {
173
- popoverDOM.dataset.show = ''
209
+ popoverDOM.removeAttribute('data-show')
210
+
211
+ const handleTransitionEnd = (e: TransitionEvent) => {
212
+ if (e.target !== popoverDOM) {
213
+ return
214
+ }
215
+
216
+ popoverDOM.removeEventListener('transitionend', handleTransitionEnd)
174
217
 
175
218
  onClose?.({
176
219
  trigger: triggerDOM,
177
220
  popover: popoverDOM,
178
- position
221
+ position: popoverDOM.dataset.position as PopoverPosition
179
222
  })
180
223
  }
181
224
 
182
- setTimeout(() => {
183
- if (!popoverDOM.dataset.show) {
184
- popoverDOM.removeAttribute('data-show')
185
- }
186
- }, 300)
225
+ popoverDOM.addEventListener('transitionend', handleTransitionEnd)
187
226
  }
188
227
 
189
- const handleCloseOnEsc = (event: KeyboardEvent) => {
190
- if (event.key === 'Escape' && popoverDOM.dataset.show) {
191
- popoverDOM.dataset.show = ''
228
+ const handleClose = (event: MouseEvent) => {
229
+ const target = event.target as HTMLElement
230
+ const hidePopover = !popoverDOM.contains(target)
231
+ && !triggerDOM.contains(target)
232
+ && popoverDOM.dataset.show
192
233
 
193
- onClose?.({
194
- trigger: triggerDOM,
195
- popover: popoverDOM,
196
- position
197
- })
234
+ if (hidePopover) {
235
+ closePopover()
236
+ }
237
+ }
198
238
 
199
- setTimeout(() => {
200
- popoverDOM.removeAttribute('data-show')
201
- }, 300)
239
+ const handleCloseOnEsc = (event: KeyboardEvent) => {
240
+ if (event.key === 'Escape' && popoverDOM.dataset.show) {
241
+ closePopover()
202
242
  }
203
243
  }
204
244
 
205
245
  const removeOnResize = debounce(() => {
206
- popoverDOM.dataset.show = ''
207
-
208
- setTimeout(() => {
209
- if (!popoverDOM.dataset.show) {
210
- popoverDOM.removeAttribute('data-show')
211
- }
212
- }, 300)
246
+ closePopover()
213
247
  })
214
248
 
215
249
  const observer = new ResizeObserver(() => {
@@ -230,7 +264,10 @@ export const popover = ({
230
264
  }
231
265
 
232
266
  return {
233
- remove() {
267
+ close() {
268
+ closePopover()
269
+ },
270
+ destroy() {
234
271
  triggerDOM.removeEventListener('click', handleOpen)
235
272
  observer.disconnect()
236
273
 
@@ -241,6 +278,10 @@ export const popover = ({
241
278
  if (closeOnEsc) {
242
279
  document.removeEventListener('keydown', handleCloseOnEsc)
243
280
  }
281
+ },
282
+ remove() {
283
+ popoverDOM.remove()
284
+ this.destroy()
244
285
  }
245
286
  }
246
287
  }