@thinkpixellab-public/px-vue 5.0.3 → 5.2.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 (124) hide show
  1. package/README.md +10 -15
  2. package/bases/PxBaseScroll.vue +0 -1
  3. package/components/PxColorPanel.vue +2 -1
  4. package/components/PxSelectionBar.vue +0 -1
  5. package/components/PxValidator.vue +0 -1
  6. package/composables/loadGsap.js +10 -10
  7. package/package.json +60 -42
  8. package/plugins/common-client.js +0 -3
  9. package/plugins/common.js +0 -3
  10. package/utils/SharedHeightManager.js +2 -2
  11. package/utils/cardGridLayoutHelper.js +1 -1
  12. package/utils/scrollWatcher.js +6 -6
  13. package/utils/smootherCorners.js +33 -38
  14. package/.eslintrc.js +0 -14
  15. package/.prettierrc.json +0 -10
  16. package/.storybook/main.js +0 -26
  17. package/.storybook/manager-head.html +0 -0
  18. package/.storybook/manager.js +0 -6
  19. package/.storybook/preview-head.html +0 -3
  20. package/.storybook/preview.js +0 -26
  21. package/.storybook/preview.scss +0 -3
  22. package/.storybook/px-styles.config.scss +0 -26
  23. package/babel.config.js +0 -16
  24. package/chromatic.config.json +0 -5
  25. package/dev/data/fruits.js +0 -59
  26. package/dev/data/random.js +0 -13
  27. package/dev/demos/Demo-PxBaseDrag.vue +0 -94
  28. package/dev/demos/Demo-PxCardGrid.vue +0 -50
  29. package/dev/demos/Demo-PxContain.vue +0 -106
  30. package/dev/demos/Demo-PxFlip.vue +0 -104
  31. package/dev/demos/Demo-PxFloat.vue +0 -105
  32. package/dev/demos/Demo-PxMenu.vue +0 -94
  33. package/dev/demos/Demo-PxPivot.vue +0 -55
  34. package/dev/demos/Demo-PxSideDrawer.vue +0 -62
  35. package/dev/demos/Demo-PxSlideTransition.vue +0 -84
  36. package/dev/demos/Demo-PxSlides.vue +0 -142
  37. package/dev/demos/Demo-PxStylesPreview.vue +0 -41
  38. package/dev/demos/Demo-PxSwiper.vue +0 -36
  39. package/dev/demos/DemoPicker.vue +0 -77
  40. package/dev/dev.vue +0 -64
  41. package/dev/serve.js +0 -17
  42. package/stories/Intro.mdx +0 -1
  43. package/stories/PxAnimate.stories.js +0 -184
  44. package/stories/PxArrow.stories.js +0 -74
  45. package/stories/PxArrowScroller.stories.js +0 -38
  46. package/stories/PxAspect.stories.js +0 -66
  47. package/stories/PxAutoClamp.stories.js +0 -47
  48. package/stories/PxBackgroundFader.stories.js +0 -42
  49. package/stories/PxBalancedText.stories.js +0 -66
  50. package/stories/PxButton.stories.js +0 -83
  51. package/stories/PxCalendar.stories.js +0 -36
  52. package/stories/PxCard.stories.js +0 -31
  53. package/stories/PxCardGrid.stories.js +0 -60
  54. package/stories/PxClock.stories.js +0 -36
  55. package/stories/PxCodeSample.stories.js +0 -53
  56. package/stories/PxColorPalette.stories.js +0 -59
  57. package/stories/PxColorPanel.stories.js +0 -31
  58. package/stories/PxColorPicker.stories.js +0 -41
  59. package/stories/PxContain.stories.js +0 -80
  60. package/stories/PxCopyText.stories.js +0 -35
  61. package/stories/PxCorners.stories.js +0 -187
  62. package/stories/PxDatePicker.stories.js +0 -36
  63. package/stories/PxDropdown.stories.js +0 -56
  64. package/stories/PxExpander.stories.js +0 -33
  65. package/stories/PxFit.stories.js +0 -40
  66. package/stories/PxFlex.stories.js +0 -41
  67. package/stories/PxFlip.stories.js +0 -51
  68. package/stories/PxFloat.stories.js +0 -147
  69. package/stories/PxGsapScrubber.stories.js +0 -36
  70. package/stories/PxIcon.stories.js +0 -189
  71. package/stories/PxIconButton.stories.js +0 -87
  72. package/stories/PxImage.stories.js +0 -113
  73. package/stories/PxLabeledInput.stories.js +0 -44
  74. package/stories/PxMeasureContainer.stories.js +0 -50
  75. package/stories/PxMenu.stories.js +0 -99
  76. package/stories/PxPivot.stories.js +0 -42
  77. package/stories/PxPopupButton.stories.js +0 -69
  78. package/stories/PxProgressCircle.stories.js +0 -39
  79. package/stories/PxQrCode.stories.js +0 -36
  80. package/stories/PxRadioButton.stories.js +0 -35
  81. package/stories/PxResizer.stories.js +0 -40
  82. package/stories/PxScrubber.stories.js +0 -58
  83. package/stories/PxSideDrawer.stories.js +0 -36
  84. package/stories/PxSlides.stories.js +0 -65
  85. package/stories/PxSpinner.stories.js +0 -37
  86. package/stories/PxSticky.stories.js +0 -36
  87. package/stories/PxSvg.stories.js +0 -46
  88. package/stories/PxSvgRender.stories.js +0 -40
  89. package/stories/PxSyncHeight.stories.js +0 -48
  90. package/stories/PxTable.stories.js +0 -145
  91. package/stories/PxTextbox.stories.js +0 -59
  92. package/stories/PxToggle.stories.js +0 -77
  93. package/stories/PxToggleButton.stories.js +0 -109
  94. package/stories/PxToggleButtonList.stories.js +0 -102
  95. package/stories/PxToolPanel.stories.js +0 -351
  96. package/stories/PxTransition.stories.js +0 -74
  97. package/stories/PxTransitionExpand.stories.js +0 -36
  98. package/stories/PxTransitionItem.stories.js +0 -36
  99. package/stories/PxValidator.stories.js +0 -100
  100. package/stories/assets/alpha.svg +0 -6
  101. package/stories/assets/alphaNoSizing.svg +0 -6
  102. package/stories/assets/alphaSizeWidth.svg +0 -6
  103. package/stories/assets/px-01.jpg +0 -0
  104. package/stories/assets/px-02.jpg +0 -0
  105. package/stories/assets/px-03.jpg +0 -0
  106. package/stories/assets/px-04.jpg +0 -0
  107. package/stories/makestories.js +0 -65
  108. package/stories/svgIcon.stories.js +0 -67
  109. package/storybook/sb-sampledata.js +0 -664
  110. package/storybook/sb-styles.scss +0 -200
  111. package/storybook/sb-utils.js +0 -30
  112. package/test/MockComponent.vue +0 -12
  113. package/test/PxBaseColor.test.js +0 -54
  114. package/test/PxBaseItems.test.js +0 -95
  115. package/test/PxBaseItemsSelect.test.js +0 -470
  116. package/test/PxBaseUniqueId.test.js +0 -29
  117. package/test/PxBaseVariants.test.js +0 -166
  118. package/test/PxBaseVariantsOverride.test.js +0 -87
  119. package/test/animation.test.js +0 -120
  120. package/test/cssStr.test.js +0 -287
  121. package/test/utils.test.js +0 -60
  122. package/test/variants.test.js +0 -92
  123. package/vite.config.js +0 -37
  124. package/vue.config.js +0 -12
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Storybook
4
4
 
5
- Basic component preview and testing can be done with storybook. Run storybook with `npm run dev-px`.
5
+ Basic component preview and testing can be done with storybook. Run storybook with `pnpm storybook-px`.
6
6
 
7
7
  ## Migration Notes / Approach
8
8
 
@@ -73,8 +73,8 @@ watch: {
73
73
 
74
74
  ## Styles / Customization
75
75
 
76
- - **Component Fallbacks** Hardcoded values defined in the component style.
77
- - **Component Variants** Overrides defined within the component
76
+ - **Component Fallbacks** Hardcoded values defined in the component style.
77
+ - **Component Variants** Overrides defined within the component
78
78
 
79
79
  App Defaults App Scoped Defaults App Variants
80
80
 
@@ -162,29 +162,24 @@ See [Vite Configuration Reference](https://vitejs.dev/config/).
162
162
  ### Project Setup
163
163
 
164
164
  ```sh
165
- npm install
165
+ pnpm install
166
166
  ```
167
167
 
168
- #### Compile and Hot-Reload for Development
168
+ #### Component preview & development with [Storybook](https://storybook.js.org/)
169
169
 
170
170
  ```sh
171
- npm run dev
172
- ```
173
-
174
- #### Compile and Minify for Production
175
-
176
- ```sh
177
- npm run build
171
+ pnpm storybook
178
172
  ```
179
173
 
180
174
  #### Run Unit Tests with [Vitest](https://vitest.dev/)
181
175
 
182
176
  ```sh
183
- npm run test:unit
177
+ pnpm test
184
178
  ```
185
179
 
186
- #### Lint with [ESLint](https://eslint.org/)
180
+ #### Format with [oxfmt](https://oxc.rs/docs/guide/usage/formatter.html) and lint with [oxlint](https://oxc.rs/docs/guide/usage/linter.html)
187
181
 
188
182
  ```sh
189
- npm run lint
183
+ pnpm format
184
+ pnpm lint
190
185
  ```
@@ -3,7 +3,6 @@
3
3
  -->
4
4
 
5
5
  <script>
6
-
7
6
  export default {
8
7
  // components: { Component },
9
8
  // mixins: [ Mixin ],
@@ -169,7 +169,8 @@ export default {
169
169
  width: 100%;
170
170
  border-radius: var(--px-color-panel-radius);
171
171
 
172
- background-image: linear-gradient(rgba(0, 0, 0, 0), #000),
172
+ background-image:
173
+ linear-gradient(rgba(0, 0, 0, 0), #000),
173
174
  linear-gradient(90deg, #fff, var(--px-color-panel-hsl-hue));
174
175
  }
175
176
 
@@ -14,7 +14,6 @@
14
14
  import PxBaseResize from '../bases/PxBaseResize.vue';
15
15
  import { getClientRect } from '../utils/utils';
16
16
 
17
-
18
17
  export default {
19
18
  name: 'px-selection-bar',
20
19
  // components: { Component },
@@ -197,7 +197,6 @@ export default {
197
197
  }
198
198
 
199
199
  // Object
200
-
201
200
  // Expects an object like {required: true, regex: '...', myvalidator:(value) => {...} }
202
201
  // Use this format for more complex or customized validation rules.
203
202
  else if (t == 'object') {
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * Lazy loading utilities for GSAP and ScrollTrigger
5
- *
5
+ *
6
6
  * These functions provide race-condition-safe loading of GSAP libraries.
7
7
  * They ensure single initialization even with concurrent calls.
8
8
  */
@@ -12,13 +12,13 @@ let scrollTriggerPromise = null;
12
12
 
13
13
  /**
14
14
  * Loads the GSAP library lazily
15
- *
15
+ *
16
16
  * @returns {Promise} Promise that resolves to the GSAP instance
17
- *
17
+ *
18
18
  * @example
19
19
  * // Direct usage (not recommended - use useGsap composable instead)
20
20
  * import { loadGsap } from '@thinkpixellab-public/px-vue/composables/loadGsap';
21
- *
21
+ *
22
22
  * const gsap = await loadGsap();
23
23
  * gsap.to('.element', { x: 100 });
24
24
  */
@@ -31,15 +31,15 @@ export const loadGsap = async () => {
31
31
 
32
32
  /**
33
33
  * Loads GSAP with ScrollTrigger plugin registered
34
- *
34
+ *
35
35
  * @returns {Promise} Promise that resolves to { gsap, ScrollTrigger }
36
- *
36
+ *
37
37
  * @example
38
38
  * // Direct usage (not recommended - use useScrollAnimation composable instead)
39
39
  * import { loadScrollTrigger } from '@thinkpixellab-public/px-vue/composables/loadGsap';
40
- *
40
+ *
41
41
  * const { gsap, ScrollTrigger } = await loadScrollTrigger();
42
- *
42
+ *
43
43
  * gsap.to('.element', {
44
44
  * x: 100,
45
45
  * scrollTrigger: {
@@ -52,9 +52,9 @@ export const loadScrollTrigger = async () => {
52
52
  if (!scrollTriggerPromise) {
53
53
  scrollTriggerPromise = (async () => {
54
54
  const [gsap, { ScrollTrigger }, { CSSPlugin }] = await Promise.all([
55
- loadGsap(),
55
+ loadGsap(),
56
56
  import('gsap/ScrollTrigger'),
57
- import('gsap/CSSPlugin')
57
+ import('gsap/CSSPlugin'),
58
58
  ]);
59
59
  gsap.registerPlugin(ScrollTrigger, CSSPlugin);
60
60
  return { gsap, ScrollTrigger };
package/package.json CHANGED
@@ -1,12 +1,29 @@
1
1
  {
2
2
  "name": "@thinkpixellab-public/px-vue",
3
- "version": "5.0.3",
3
+ "version": "5.2.0",
4
4
  "description": "General purpose Vue components and helpers that can be used across projects.",
5
5
  "author": {
6
6
  "name": "Pixel Lab"
7
7
  },
8
8
  "license": "MIT",
9
9
  "type": "module",
10
+ "engines": {
11
+ "node": ">=24 <25"
12
+ },
13
+ "packageManager": "pnpm@11.5.2",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "files": [
18
+ "assets",
19
+ "bases",
20
+ "components",
21
+ "composables",
22
+ "plugins",
23
+ "styles",
24
+ "utils",
25
+ "nuxt-module.js"
26
+ ],
10
27
  "repository": {
11
28
  "type": "git",
12
29
  "url": "git+https://github.com/thinkpixellab/px-vue.git"
@@ -16,62 +33,63 @@
16
33
  "storybook": "storybook dev -p 6006",
17
34
  "build-storybook": "storybook build",
18
35
  "test": "vitest",
19
- "serve": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve dev/serve.js",
20
- "chromatic": "npx chromatic --project-token=chpt_30d6cbeac803e5a"
36
+ "test:run": "vitest run",
37
+ "chromatic": "npx chromatic --project-token=chpt_30d6cbeac803e5a",
38
+ "format": "oxfmt --write .",
39
+ "format:check": "oxfmt --check .",
40
+ "lint": "oxlint",
41
+ "lint:fix": "oxlint --fix",
42
+ "prepare": "git config core.hooksPath .githooks || true"
21
43
  },
22
44
  "dependencies": {
23
- "@floating-ui/dom": "^1.6.13",
45
+ "@floating-ui/dom": "^1.7.6",
24
46
  "@popperjs/core": "^2.11.8",
25
- "@thinkpixellab-public/px-styles": "^4.1.5",
47
+ "@thinkpixellab-public/px-styles": "^4.2.1",
26
48
  "@thinkpixellab-public/px-vue-tester": "^2.0.0",
27
- "@thinkpixellab-public/vue-resize-directive": "^1.2.2",
28
49
  "body-scroll-lock": "^3.1.5",
29
- "chrono-node": "^2.7.8",
50
+ "chrono-node": "^2.9.1",
30
51
  "dateformat": "^5.0.3",
31
52
  "figma-squircle": "^1.1.0",
32
- "gsap": "^3.13.0",
53
+ "gsap": "^3.15.0",
33
54
  "highlight.js": "^11.11.1",
34
- "lenis": "^1.1.17",
55
+ "lenis": "^1.3.23",
35
56
  "mitt": "^3.0.1",
36
57
  "qr-code-styling": "^1.9.2",
37
- "sortablejs": "^1.15.6",
58
+ "sortablejs": "^1.15.7",
38
59
  "throttle-debounce": "^5.0.2",
39
60
  "tiny-date-picker": "^3.2.8",
40
61
  "tinycolor2": "^1.6.0",
41
- "vue-inline-svg": "^3.1.4"
62
+ "vue-inline-svg": "^4.0.1"
42
63
  },
43
64
  "devDependencies": {
44
- "@babel/core": "^7.26.10",
45
- "@chromatic-com/storybook": "^3.2.6",
46
- "@nuxt/kit": "^4.2.2",
47
- "@rushstack/eslint-patch": "^1.11.0",
48
- "@storybook/addon-essentials": "^8.6.7",
49
- "@storybook/addon-interactions": "^8.6.7",
50
- "@storybook/addon-links": "^8.6.7",
51
- "@storybook/addon-mdx-gfm": "^8.6.7",
52
- "@storybook/blocks": "^8.6.7",
53
- "@storybook/manager-api": "^8.6.7",
54
- "@storybook/test": "^8.6.7",
55
- "@storybook/theming": "^8.6.7",
56
- "@storybook/vue3": "^8.6.7",
57
- "@storybook/vue3-vite": "^8.6.7",
58
- "@vitejs/plugin-vue": "^5.2.3",
59
- "@vue/eslint-config-prettier": "^10.2.0",
60
- "@vue/test-utils": "^2.4.6",
61
- "babel-eslint": "^10.1.0",
62
- "chromatic": "^11.27.0",
63
- "eslint": "^9.22.0",
64
- "eslint-plugin-storybook": "^0.11.6",
65
- "eslint-plugin-vue": "^9.32.0",
66
- "jsdom": "^26.0.0",
67
- "prettier": "^3.5.3",
68
- "sass": "^1.83.4",
69
- "storybook": "^8.6.7",
70
- "storybook-addon-pseudo-states": "^4.0.3",
71
- "storybook-dark-mode": "^4.0.2",
72
- "vite": "^6.2.2",
73
- "vitest": "^3.0.9",
74
- "vue-loader": "^17.4.2"
65
+ "@chromatic-com/storybook": "^5.2.1",
66
+ "@nuxt/kit": "^4.4.7",
67
+ "@storybook/addon-docs": "^10.4.2",
68
+ "@storybook/addon-links": "^10.4.2",
69
+ "@storybook/vue3": "^10.4.2",
70
+ "@storybook/vue3-vite": "^10.4.2",
71
+ "@vitejs/plugin-vue": "^6.0.7",
72
+ "@vue/test-utils": "^2.4.11",
73
+ "@vueless/storybook-dark-mode": "^10.0.8",
74
+ "chromatic": "^17.2.0",
75
+ "jsdom": "^29.1.1",
76
+ "oxfmt": "^0.53.0",
77
+ "oxlint": "^1.68.0",
78
+ "sass": "^1.100.0",
79
+ "storybook": "^10.4.2",
80
+ "storybook-addon-pseudo-states": "^10.4.2",
81
+ "vite": "^8.0.16",
82
+ "vitest": "^4.1.8",
83
+ "vue": "^3.5.35"
84
+ },
85
+ "peerDependencies": {
86
+ "@nuxt/kit": "^3.0.0 || ^4.0.0",
87
+ "vue": "^3.2.25"
88
+ },
89
+ "peerDependenciesMeta": {
90
+ "@nuxt/kit": {
91
+ "optional": true
92
+ }
75
93
  },
76
94
  "bugs": {
77
95
  "url": "https://github.com/thinkpixellab/px-vue/issues"
@@ -1,5 +1,4 @@
1
1
  import mitt from 'mitt';
2
- import resize from '@thinkpixellab-public/vue-resize-directive';
3
2
 
4
3
  export default {
5
4
  install: app => {
@@ -18,7 +17,5 @@ export default {
18
17
  app.config.globalProperties.$globalOff = function (eventName, fn) {
19
18
  $eventBus.off(eventName, fn);
20
19
  };
21
-
22
- app.directive('resize', resize);
23
20
  },
24
21
  };
package/plugins/common.js CHANGED
@@ -56,9 +56,6 @@ export default {
56
56
  // $eventBus is only client-side but we want to avoid warnings about missing $eventBus
57
57
  // for inject called during setup on server-side.
58
58
  app.provide('$eventBus', null);
59
-
60
- // v-resize is only client-side but we want to avoid warnings about missing directive
61
- app.directive('resize', {});
62
59
  }
63
60
  },
64
61
  };
@@ -88,11 +88,11 @@ class HeightGroup {
88
88
  console.log(`ignore: ${ignore}`);
89
89
  console.log(
90
90
  'valid heights:',
91
- heights.filter(height => height <= ignore)
91
+ heights.filter(height => height <= ignore),
92
92
  );
93
93
  console.log(
94
94
  'invalid heights:',
95
- heights.filter(height => height > ignore)
95
+ heights.filter(height => height > ignore),
96
96
  );
97
97
  }
98
98
  }, this.ops.debounce);
@@ -526,7 +526,7 @@ const reverseTemplate = template => {
526
526
  const mergeH = (a, b) => {
527
527
  if (!a || !a.length || !b || b.length || a.length !== b.length) {
528
528
  console.warn(
529
- 'Cannot horizontally merge empty templates or templates of different lengths.'
529
+ 'Cannot horizontally merge empty templates or templates of different lengths.',
530
530
  );
531
531
  return [];
532
532
  }
@@ -109,19 +109,19 @@ class ScrollWatcherElement {
109
109
  // If element is smaller than viewport...
110
110
  // overlapping begins when the bottom of the element meets the bottom of the viewport
111
111
  this.calc.progressBegin = Math.round(
112
- this.calc.elementRect.bottom - this.calc.viewport.bottom
112
+ this.calc.elementRect.bottom - this.calc.viewport.bottom,
113
113
  );
114
114
  this.calc.progressDuration = Math.round(
115
- this.calc.viewport.height - this.calc.elementRect.height
115
+ this.calc.viewport.height - this.calc.elementRect.height,
116
116
  );
117
117
  } else {
118
118
  // If element is larger than viewport...
119
119
  // begin when the top of the element is at the top of the viewport
120
120
  this.calc.progressBegin = Math.round(
121
- this.calc.elementRect.top - this.calc.viewport.top
121
+ this.calc.elementRect.top - this.calc.viewport.top,
122
122
  );
123
123
  this.calc.progressDuration = Math.round(
124
- this.calc.elementRect.height - this.calc.viewport.height
124
+ this.calc.elementRect.height - this.calc.viewport.height,
125
125
  );
126
126
  }
127
127
  } else {
@@ -129,10 +129,10 @@ class ScrollWatcherElement {
129
129
  // Occurs as any part of the element is within any part of the viewport
130
130
 
131
131
  this.calc.progressBegin = Math.round(
132
- this.calc.elementRect.top - this.calc.viewport.bottom
132
+ this.calc.elementRect.top - this.calc.viewport.bottom,
133
133
  );
134
134
  this.calc.progressDuration = Math.round(
135
- this.calc.viewport.height + this.calc.elementRect.height
135
+ this.calc.viewport.height + this.calc.elementRect.height,
136
136
  );
137
137
  }
138
138
 
@@ -175,16 +175,14 @@ export function getSmoothCornersPath(options = {}) {
175
175
 
176
176
  // calculate corner radii with percentage support and clamping
177
177
  const radii = calculateCornerRadii(radius, adjustedWidth, adjustedHeight, minRadius, maxRadius);
178
-
178
+
179
179
  // check if all radii are 0 - no need for clipping/masking
180
180
  if (radii.every(r => r === 0)) {
181
181
  return null;
182
182
  }
183
-
183
+
184
184
  // adjust radii for inner path when borderWidth is present
185
- const adjustedRadii = borderWidth > 0
186
- ? radii.map(r => Math.max(0, r - borderWidth))
187
- : radii;
185
+ const adjustedRadii = borderWidth > 0 ? radii.map(r => Math.max(0, r - borderWidth)) : radii;
188
186
 
189
187
  const path = generateSquirclePath(
190
188
  adjustedWidth,
@@ -214,13 +212,13 @@ export function getSmoothCornersPath(options = {}) {
214
212
  */
215
213
  export function getBorderMaskStyles(options = {}) {
216
214
  const { width, height, borderWidth = 0 } = options;
217
-
215
+
218
216
  if (width <= 0 || height <= 0 || borderWidth <= 0) return null;
219
-
217
+
220
218
  // Create the inner path (smaller for content area)
221
219
  const innerPath = getSmoothCornersPath({
222
- width: width - (borderWidth * 2),
223
- height: height - (borderWidth * 2),
220
+ width: width - borderWidth * 2,
221
+ height: height - borderWidth * 2,
224
222
  radius: options.radius,
225
223
  smoothing: options.smoothing,
226
224
  borderWidth: 0,
@@ -228,13 +226,13 @@ export function getBorderMaskStyles(options = {}) {
228
226
  maxRadius: options.maxRadius,
229
227
  preserveSmoothing: options.preserveSmoothing,
230
228
  });
231
-
229
+
232
230
  if (!innerPath) return null;
233
-
231
+
234
232
  // Position the inner mask to create border space
235
233
  const maskPosition = `${borderWidth}px ${borderWidth}px`;
236
- const maskSize = `${width - (borderWidth * 2)}px ${height - (borderWidth * 2)}px`;
237
-
234
+ const maskSize = `${width - borderWidth * 2}px ${height - borderWidth * 2}px`;
235
+
238
236
  return {
239
237
  WebkitMask: `radial-gradient(white, white), ${innerPath}`,
240
238
  mask: `radial-gradient(white, white), ${innerPath}`,
@@ -245,7 +243,7 @@ export function getBorderMaskStyles(options = {}) {
245
243
  WebkitMaskSize: `100% 100%, ${maskSize}`,
246
244
  maskSize: `100% 100%, ${maskSize}`,
247
245
  WebkitMaskRepeat: 'no-repeat, no-repeat',
248
- maskRepeat: 'no-repeat, no-repeat'
246
+ maskRepeat: 'no-repeat, no-repeat',
249
247
  };
250
248
  }
251
249
 
@@ -257,54 +255,54 @@ export function getBorderMaskStyles(options = {}) {
257
255
  */
258
256
  export function getBorderMaskClipPath(options = {}) {
259
257
  const { width, height, borderWidth = 0, renderMode = 'clip-path' } = options;
260
-
258
+
261
259
  if (width <= 0 || height <= 0 || borderWidth <= 0) return null;
262
-
260
+
263
261
  // Check if the border is too large for the element
264
262
  if (borderWidth * 2 >= width || borderWidth * 2 >= height) return null;
265
-
263
+
266
264
  // Create outer rectangle path (clockwise)
267
265
  const rectPath = `M 0 0 H ${width} V ${height} H 0 Z`;
268
-
266
+
269
267
  // Generate the inner smooth path directly at the correct size and position
270
- const innerWidth = width - (borderWidth * 2);
271
- const innerHeight = height - (borderWidth * 2);
272
-
268
+ const innerWidth = width - borderWidth * 2;
269
+ const innerHeight = height - borderWidth * 2;
270
+
273
271
  // Calculate radii for the outer dimensions first
274
272
  const outerRadii = calculateCornerRadii(
275
273
  options.radius,
276
274
  width,
277
275
  height,
278
276
  options.minRadius || 0,
279
- options.maxRadius || Infinity
277
+ options.maxRadius || Infinity,
280
278
  );
281
-
279
+
282
280
  // check if all radii are 0 - no need for border masking
283
281
  if (outerRadii.every(r => r === 0)) {
284
282
  return null;
285
283
  }
286
-
284
+
287
285
  // Adjust radii for the inner path by subtracting border width
288
286
  // This ensures consistent border thickness around corners
289
287
  const innerRadii = outerRadii.map(r => Math.max(0, r - borderWidth));
290
-
288
+
291
289
  // Generate the inner path with adjusted radii
292
290
  const innerSmoothPath = generateSquirclePath(
293
291
  innerWidth,
294
292
  innerHeight,
295
293
  innerRadii,
296
294
  options.smoothing || 0.8,
297
- options.preserveSmoothing !== false
295
+ options.preserveSmoothing !== false,
298
296
  );
299
-
297
+
300
298
  if (!innerSmoothPath) return null;
301
-
299
+
302
300
  // Apply offset to position the inner path
303
301
  const offsetInnerPath = applyPathOffset(innerSmoothPath, borderWidth, borderWidth);
304
-
302
+
305
303
  // Combine the paths
306
304
  const combinedPath = `${rectPath} ${offsetInnerPath}`;
307
-
305
+
308
306
  // Return format based on render mode
309
307
  if (renderMode === 'mask') {
310
308
  return createSvgBorderMaskDataUrl(combinedPath, width, height);
@@ -313,7 +311,6 @@ export function getBorderMaskClipPath(options = {}) {
313
311
  }
314
312
  }
315
313
 
316
-
317
314
  /**
318
315
  * Create SVG mask data URL from path string
319
316
  * @param {string} pathString - SVG path string
@@ -331,14 +328,14 @@ export function createSvgMaskDataUrl(pathString, width, height) {
331
328
  </defs>
332
329
  <rect width="100%" height="100%" fill="white" mask="url(#smooth-mask)"/>
333
330
  </svg>`;
334
-
331
+
335
332
  return `url('data:image/svg+xml;utf8,${encodeURIComponent(svgContent)}')`;
336
333
  }
337
334
 
338
335
  /**
339
336
  * Create SVG border mask data URL using compound path approach
340
337
  * @param {string} compoundPathString - Compound path string (outer rect + inner hole)
341
- * @param {number} width - Mask width
338
+ * @param {number} width - Mask width
342
339
  * @param {number} height - Mask height
343
340
  * @returns {string} Data URL for SVG border mask
344
341
  */
@@ -351,7 +348,7 @@ export function createSvgBorderMaskDataUrl(compoundPathString, width, height) {
351
348
  </defs>
352
349
  <rect width="100%" height="100%" fill="white" mask="url(#border-mask)"/>
353
350
  </svg>`;
354
-
351
+
355
352
  return `url('data:image/svg+xml;utf8,${encodeURIComponent(svgContent)}')`;
356
353
  }
357
354
 
@@ -376,11 +373,9 @@ export function generateSmoothCornersConfig(options = {}) {
376
373
  const adjustedHeight = Math.max(0, height - borderWidth * 2);
377
374
 
378
375
  const radii = calculateCornerRadii(radius, adjustedWidth, adjustedHeight, minRadius, maxRadius);
379
-
376
+
380
377
  // adjust radii for inner path when borderWidth is present
381
- const adjustedRadii = borderWidth > 0
382
- ? radii.map(r => Math.max(0, r - borderWidth))
383
- : radii;
378
+ const adjustedRadii = borderWidth > 0 ? radii.map(r => Math.max(0, r - borderWidth)) : radii;
384
379
 
385
380
  return {
386
381
  width: adjustedWidth,
package/.eslintrc.js DELETED
@@ -1,14 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- env: {
4
- node: true,
5
- },
6
- extends: ['plugin:vue/essential', 'eslint:recommended', '@vue/prettier'],
7
- parserOptions: {
8
- parser: 'babel-eslint',
9
- },
10
- rules: {
11
- 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
12
- 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
13
- },
14
- };
package/.prettierrc.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "semi": true,
3
- "arrowParens": "avoid",
4
- "singleQuote": true,
5
- "tabWidth": 4,
6
- "printWidth": 100,
7
- "bracketSpacing": true,
8
- "htmlWhitespaceSensitivity": "ignore",
9
- "endOfLine": "auto"
10
- }
@@ -1,26 +0,0 @@
1
- /** @type { import('@storybook/vue3-vite').StorybookConfig } */
2
- const config = {
3
- stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],
4
- addons: [
5
- '@storybook/addon-links',
6
- '@storybook/addon-essentials',
7
- '@storybook/addon-interactions',
8
- '@chromatic-com/storybook',
9
- 'storybook-addon-pseudo-states',
10
- 'storybook-dark-mode',
11
- ],
12
-
13
- framework: {
14
- name: '@storybook/vue3-vite',
15
- options: {},
16
- },
17
-
18
- docs: {
19
- defaultName: 'Documentation'
20
- },
21
-
22
- features: {
23
- interactionsDebugger: true,
24
- },
25
- };
26
- export default config;
File without changes
@@ -1,6 +0,0 @@
1
- import { addons } from '@storybook/manager-api';
2
- import { themes } from '@storybook/theming';
3
-
4
- addons.setConfig({
5
- theme: themes.dark,
6
- });
@@ -1,3 +0,0 @@
1
- <script>
2
- window.global = window;
3
- </script>
@@ -1,26 +0,0 @@
1
- import { setup } from '@storybook/vue3';
2
- import common from '../plugins/common.js';
3
- import './preview.scss';
4
-
5
- // px-vue common plugins
6
- setup(app => {
7
- app.use(common);
8
- });
9
-
10
- const preview = {
11
- parameters: {
12
- controls: {
13
- matchers: {
14
- color: /(background|color)$/i,
15
- date: /Date$/,
16
- string: /(itemsKey|itemsDisabled)$/i,
17
- },
18
- },
19
- order: ['Intro', 'Components'],
20
- storySort: (a, b) => a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),
21
- docs: { },
22
- },
23
- tags: ['autodocs']
24
- };
25
-
26
- export default preview;
@@ -1,3 +0,0 @@
1
- @use '../styles/px.scss' as *;
2
- @use '@thinkpixellab-public/px-styles/src/modules/controls' as *;
3
- @use '../storybook/sb-styles.scss' as *;