@stevederico/skateboard-ui 2.14.0 → 2.16.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.
@@ -0,0 +1,16 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(for file in App.jsx AppSidebar.jsx Context.jsx Layout.jsx TabBar.jsx TextView.jsx SettingsView.jsx SignInView.jsx LandingView.jsx UpgradeSheet.jsx PaymentView.jsx SignUpView.jsx)",
5
+ "Bash(do)",
6
+ "Bash(if [ -f \"$file\" ])",
7
+ "Bash(then)",
8
+ "Bash(node --check:*)",
9
+ "Bash(echo:*)",
10
+ "Bash(fi)",
11
+ "Bash(done)",
12
+ "Bash(git commit:*)",
13
+ "Bash(git push:*)"
14
+ ]
15
+ }
16
+ }
Binary file
Binary file
Binary file
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # CHANGELOG
2
2
 
3
+ 2.15.0
4
+
5
+ Add authOverlay 401 retry logic
6
+ Add SHOW_AUTH_OVERLAY dispatch
7
+
3
8
  2.14.0
4
9
 
5
10
  Switch icons to Lucide React
@@ -1,5 +1,4 @@
1
- import React, { useState, useEffect } from "react";
2
- import { cn } from "../shadcn/lib/utils.js";
1
+ import * as LucideIcons from "lucide-react";
3
2
 
4
3
  /**
5
4
  * Convert a kebab-case, snake_case, or space-separated string to PascalCase.
@@ -27,42 +26,6 @@ function toKebabCase(str) {
27
26
  .toLowerCase();
28
27
  }
29
28
 
30
- /** Cache of resolved icon components keyed by name */
31
- const iconCache = new Map();
32
-
33
- /** Cache of in-flight import promises keyed by module name */
34
- const importCache = new Map();
35
-
36
- /**
37
- * Load a single Lucide icon by its kebab-case file name (e.g. "arrow-right").
38
- * Each icon is imported individually (~1KB) instead of loading the entire
39
- * icon library. Results are cached for instant subsequent lookups.
40
- *
41
- * @param {string} kebabName - kebab-case icon file name
42
- * @param {string} cacheKey - PascalCase name used as cache key
43
- * @returns {Promise<React.ComponentType|null>} Icon component or null
44
- */
45
- function loadIcon(kebabName, cacheKey) {
46
- if (iconCache.has(cacheKey)) return Promise.resolve(iconCache.get(cacheKey));
47
- if (importCache.has(cacheKey)) return importCache.get(cacheKey);
48
-
49
- const promise = import(`/node_modules/lucide-react/dist/esm/icons/${kebabName}.js`)
50
- .then((mod) => {
51
- const Icon = mod.default || null;
52
- iconCache.set(cacheKey, Icon);
53
- importCache.delete(cacheKey);
54
- return Icon;
55
- })
56
- .catch(() => {
57
- iconCache.set(cacheKey, null);
58
- importCache.delete(cacheKey);
59
- return null;
60
- });
61
-
62
- importCache.set(cacheKey, promise);
63
- return promise;
64
- }
65
-
66
29
  /**
67
30
  * Resolve an icon name in any format to a PascalCase name and kebab-case file path.
68
31
  * e.g. "layout-dashboard" → { pascal: "LayoutDashboard", kebab: "layout-dashboard" }
@@ -84,23 +47,22 @@ function toIconName(name) {
84
47
  }
85
48
 
86
49
  /**
87
- * Check if a name string has been resolved to a valid icon.
88
- * Returns false for unloaded or invalid icons.
50
+ * Check if a name string can be resolved to a valid Lucide icon.
89
51
  *
90
52
  * @param {string} name - Icon name to check
91
- * @returns {boolean} True if icon is cached and valid
53
+ * @returns {boolean} True if icon exists in the Lucide library
92
54
  */
93
55
  export function canResolveIcon(name) {
94
56
  const { pascal } = toIconName(name);
95
- return iconCache.has(pascal) && iconCache.get(pascal) !== null;
57
+ return pascal in LucideIcons && typeof LucideIcons[pascal] === "function";
96
58
  }
97
59
 
98
60
  /**
99
- * Render a Lucide icon by name string with per-icon lazy loading.
61
+ * Render a Lucide icon by name string using a static import of all icons.
100
62
  *
101
- * Each icon is imported individually from lucide-react (~1KB per icon)
102
- * instead of loading the entire library. Resolved icons are cached in memory
103
- * for instant rendering on subsequent uses.
63
+ * All icons are bundled at build time from lucide-react, ensuring they work
64
+ * in both Vite dev mode and production builds. Icons are looked up synchronously
65
+ * by PascalCase name from the LucideIcons namespace.
104
66
  *
105
67
  * Accepts kebab-case ("layout-dashboard"), PascalCase ("LayoutDashboard"),
106
68
  * or legacy prefixed ("IconLayoutDashboard") names.
@@ -111,7 +73,7 @@ export function canResolveIcon(name) {
111
73
  * @param {string} [props.color='currentColor'] - Icon stroke color
112
74
  * @param {number} [props.strokeWidth=2] - Stroke width
113
75
  * @param {string} [props.className] - Additional CSS classes
114
- * @returns {JSX.Element|null} Rendered icon or null if loading/not found
76
+ * @returns {JSX.Element|null} Rendered icon or null if not found
115
77
  *
116
78
  * @example
117
79
  * import DynamicIcon from '@stevederico/skateboard-ui/DynamicIcon';
@@ -128,18 +90,10 @@ const DynamicIcon = ({
128
90
  className,
129
91
  ...props
130
92
  }) => {
131
- const { pascal, kebab } = toIconName(name);
132
-
133
- const [Icon, setIcon] = useState(() => iconCache.get(pascal) || null);
134
-
135
- useEffect(() => {
136
- if (Icon) return;
137
- loadIcon(kebab, pascal).then((resolved) => {
138
- if (resolved) setIcon(() => resolved);
139
- });
140
- }, [pascal, kebab, Icon]);
93
+ const { pascal } = toIconName(name);
94
+ const Icon = LucideIcons[pascal];
141
95
 
142
- if (!Icon) return null;
96
+ if (!Icon || typeof Icon !== "function") return null;
143
97
 
144
98
  return (
145
99
  <Icon
package/core/Utilities.js CHANGED
@@ -723,11 +723,31 @@ export async function apiRequest(endpoint, options = {}) {
723
723
  if (timeoutId) clearTimeout(timeoutId);
724
724
  }
725
725
 
726
- // Handle 401 (redirect to signout, unless authOverlay mode)
726
+ // Handle 401 (redirect to signout, or show auth overlay and retry)
727
727
  if (response.status === 401) {
728
728
  if (getConstants().authOverlay !== true) {
729
729
  window.location.href = '/signout';
730
+ throw new Error('Unauthorized');
730
731
  }
732
+
733
+ // In authOverlay mode: show sign-in overlay, retry request after auth
734
+ const dispatch = getDispatch();
735
+ if (dispatch) {
736
+ return new Promise((resolve, reject) => {
737
+ dispatch({
738
+ type: 'SHOW_AUTH_OVERLAY',
739
+ payload: async () => {
740
+ try {
741
+ const result = await apiRequest(endpoint, options);
742
+ resolve(result);
743
+ } catch (err) {
744
+ reject(err);
745
+ }
746
+ }
747
+ });
748
+ });
749
+ }
750
+
731
751
  throw new Error('Unauthorized');
732
752
  }
733
753
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stevederico/skateboard-ui",
3
3
  "private": false,
4
- "version": "2.14.0",
4
+ "version": "2.16.0",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  "./Sidebar": {