@stevederico/skateboard-ui 4.3.0 → 4.5.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # CHANGELOG
2
2
 
3
+ 4.5.0
4
+
5
+ Toggle uses resolvedTheme
6
+ ThemeProvider owns dark
7
+ Drop dark-mode stripping
8
+ Slot render child fallback
9
+
10
+ 4.4.0
11
+
12
+ Document a11y releases
13
+ Fix peer-dep naming
14
+
3
15
  4.3.0
4
16
 
5
17
  Submenu aria-controls wiring
package/README.md CHANGED
@@ -6,6 +6,8 @@ React component library for rapid application development. Built with TypeScript
6
6
 
7
7
  **Self-contained components (v4.0).** Every component is now hand-written with no primitive framework underneath — the previously-vendored `@base-ui/react` bundle (~31k lines) is gone. Floating positioning, focus trapping, dismiss layers, and animations are small in-house hooks; modals use the native `<dialog>` element. The legacy `shadcn/ui/*` import paths still work — they re-export the new `ui/*` components — so existing apps need no changes.
8
8
 
9
+ **Accessibility-hardened (v4.1–4.3).** The self-contained tier was put through three rounds of a11y work: menu/select typeahead, correct keyboard focus management and tab-stops (menus, tabs, radios, popovers, navigation menu), ARIA wiring (`aria-controls`, labelled-by, indeterminate checkbox mixed state, named popover/slider dialogs), scroll-lock and exit-animation fixes, plus matching DOMException error names. Each release adds to a Playwright a11y regression suite that runs `workers: 1`.
10
+
9
11
  **TypeScript with full type declarations.** Source is TypeScript, compiled to plain JavaScript + `.d.ts` in `dist/` (`npm run build`). JavaScript apps consume the compiled JS exactly as before — import paths are unchanged — and TypeScript apps get real types for every export (`SkateboardConstants`, `User`, component props, `VariantProps`, typed icons).
10
12
 
11
13
  **Node.js 24+** is required in the app repo for build tooling and backend (see `engines` in `package.json`). The UI package itself runs in the browser.
@@ -1309,7 +1311,7 @@ All components support dark mode automatically and accept a `className` prop for
1309
1311
  ### Required peer dependencies
1310
1312
  - React 19.1+
1311
1313
  - react-dom 19.1+
1312
- - react-router-dom 7.0+
1314
+ - react-router 7.0+
1313
1315
 
1314
1316
  ### Hard dependencies
1315
1317
 
@@ -5,14 +5,14 @@ import { Sun, Moon } from '../icons/index.js';
5
5
  import { Button } from '../shadcn/ui/button.js';
6
6
  import { cn } from '../shadcn/lib/utils.js';
7
7
  export default function ThemeToggle({ className = "", iconSize = 16, variant = "settings", ...props }) {
8
- const { theme, setTheme } = useTheme();
8
+ const { resolvedTheme, setTheme } = useTheme();
9
9
  const [mounted, setMounted] = React.useState(false);
10
10
  React.useEffect(() => {
11
11
  setMounted(true);
12
12
  }, []);
13
13
  if (!mounted)
14
14
  return null;
15
- const isDarkMode = theme === 'dark';
15
+ const isDarkMode = resolvedTheme === 'dark';
16
16
  const toggleTheme = () => setTheme(isDarkMode ? 'light' : 'dark');
17
17
  return (_jsx(Button, { variant: variant === "landing" ? "outline" : "ghost", size: "icon", onClick: toggleTheme, className: cn(className), "aria-label": "Toggle dark mode", ...props, children: isDarkMode
18
18
  ? _jsx(Sun, { size: iconSize })
@@ -321,7 +321,8 @@ export declare function showUpgradeSheet(upgradeSheetRef: RefObject<{
321
321
  */
322
322
  export declare function timestampToString(input: number | Date, format?: string): string | number | Date;
323
323
  /**
324
- * Hook that sets the document title and removes dark mode on non-app pages.
324
+ * Hook that sets the document title on navigation.
325
+ * Dark mode is owned by ThemeProvider — never touch the class here.
325
326
  *
326
327
  * @param {Object} location - react-router location object
327
328
  */
@@ -657,17 +657,14 @@ export function timestampToString(input, format = "DOB") {
657
657
  }
658
658
  }
659
659
  /**
660
- * Hook that sets the document title and removes dark mode on non-app pages.
660
+ * Hook that sets the document title on navigation.
661
+ * Dark mode is owned by ThemeProvider — never touch the class here.
661
662
  *
662
663
  * @param {Object} location - react-router location object
663
664
  */
664
665
  export function useAppSetup(location) {
665
666
  useEffect(() => {
666
667
  document.title = getConstants().appName;
667
- if (!location.pathname.toLowerCase().includes('app')) {
668
- document.documentElement.classList.remove('dark');
669
- document.body.classList.remove('dark');
670
- }
671
668
  }, [location.pathname]);
672
669
  }
673
670
  // ===== API REQUEST UTILITIES =====
package/dist/ui/slot.d.ts CHANGED
@@ -19,6 +19,10 @@ declare function Slot({ children, className, style, ref, ...props }: SlotProps):
19
19
  * element to `render` to control the rendered element; here that maps onto the
20
20
  * `asChild` + Slot mechanism. Returns whether to use the Slot and what child to
21
21
  * render through it, so `render={<Button/>}` keeps working on the new components.
22
+ * Matching Base UI's render-prop semantics, the component's children become the
23
+ * render element's children when the element has none of its own — so
24
+ * `<Trigger render={<Button/>}>Columns</Trigger>` renders the label, while
25
+ * `render={<Button>Sign Out</Button>}` keeps the element's own children.
22
26
  */
23
27
  declare function resolveRender(asChild: boolean | undefined, render: React.ReactElement | undefined, children: React.ReactNode): {
24
28
  useSlot: boolean;
package/dist/ui/slot.js CHANGED
@@ -53,10 +53,28 @@ function Slot({ children, className, style, ref, ...props }) {
53
53
  * element to `render` to control the rendered element; here that maps onto the
54
54
  * `asChild` + Slot mechanism. Returns whether to use the Slot and what child to
55
55
  * render through it, so `render={<Button/>}` keeps working on the new components.
56
+ * Matching Base UI's render-prop semantics, the component's children become the
57
+ * render element's children when the element has none of its own — so
58
+ * `<Trigger render={<Button/>}>Columns</Trigger>` renders the label, while
59
+ * `render={<Button>Sign Out</Button>}` keeps the element's own children.
56
60
  */
57
61
  function resolveRender(asChild, render, children) {
58
- if (React.isValidElement(render))
62
+ if (React.isValidElement(render)) {
63
+ const renderProps = render.props;
64
+ const ownChildren = typeof renderProps === "object" &&
65
+ renderProps !== null &&
66
+ "children" in renderProps
67
+ ? renderProps.children
68
+ : undefined;
69
+ // != null, not truthiness: 0 and "" are renderable children to keep.
70
+ if (ownChildren == null && children != null) {
71
+ return {
72
+ useSlot: true,
73
+ slotChild: React.cloneElement(render, undefined, children),
74
+ };
75
+ }
59
76
  return { useSlot: true, slotChild: render };
77
+ }
60
78
  return { useSlot: !!asChild, slotChild: children };
61
79
  }
62
80
  export { Slot, mergeRefs, resolveRender };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stevederico/skateboard-ui",
3
3
  "private": false,
4
- "version": "4.3.0",
4
+ "version": "4.5.0",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {