@nordwerk/scroll-carousel 0.1.0 → 0.1.2

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/AGENTS.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Two parts: how to build a carousel with this package in a project, and how to work on the package
4
4
  itself. Human documentation is in README.md; live examples with code are at
5
- https://studio-nordwerk.github.io/scroll-carousel/.
5
+ https://www.nordwerk.studio/oss/scroll-carousel.
6
6
 
7
7
  ## Part 1: using the package
8
8
 
@@ -39,6 +39,12 @@ JavaScript, never move slides with transforms, never clone slides.
39
39
  9. Text: pass `labels` for dots and the live region in the page's language, and give the arrow
40
40
  buttons their own `aria-label`s ("Previous products", "Next products").
41
41
  10. Do not add `disabled` to the arrows yourself; the script manages `aria-disabled`.
42
+ 11. Tailwind CSS: `@import "@nordwerk/scroll-carousel/carousel.css" layer(components);`, layout as
43
+ arbitrary properties (`[--sc-per-view:2]`, `@3xl:[--sc-per-view:4]` on `.sc-track`), own
44
+ controls styled from the state attributes (`group-data-[sc-overflow]/row:grid`,
45
+ `aria-disabled:opacity-30`). Copyable example: the `#tailwind` section of the docs site.
46
+ 12. Next.js App Router: import `<Carousel>` from `@nordwerk/scroll-carousel/react` in a Server
47
+ Component as is; the entry carries `'use client'`.
42
48
 
43
49
  ### Recipes (CSS on the root or track, options in attach)
44
50
 
@@ -79,7 +85,15 @@ JavaScript, never move slides with transforms, never clone slides.
79
85
  - `src/astro/Carousel.astro`: shipped as source.
80
86
  - `src/carousel.css`: all layout and the default controls.
81
87
  - `site/`: the documentation site (`generate.mjs` writes `_site/`), including the wireframe
82
- patterns in `wireframes.mjs`. Content there is fictional.
88
+ patterns in `wireframes.mjs`. Content there is fictional. CI publishes it to GitHub Pages;
89
+ www.nordwerk.studio/oss/scroll-carousel serves the same files through a proxy that rewrites
90
+ `<base href>`, so every link in the site must stay relative to `<base>`. The proxy also puts the
91
+ studio site's own header and footer in place of `<!--nw:header-->` (first child of `.sheet`)
92
+ and `<!--nw:footer-->` (right after `.sheet`); keep both, keep `<html lang="en">` and `<body>`
93
+ free of other attributes, keep `data-hero` on the introduction, and never style the studio's
94
+ class names (band, pill, brand, brand-mark, links, link, cta, foot, grid, brand-col, tag, label,
95
+ base) or set `--wrap` in the site CSS. Locally and on GitHub Pages the site has no header or
96
+ footer.
83
97
  - `test/unit/`: node's test runner on the TypeScript sources.
84
98
  - `test/e2e/`: Playwright against `_site/` and the adapter fixtures from `scripts/fixtures.mjs`.
85
99
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 (2026-09-22)
4
+
5
+ - React entry marked `'use client'`: `<Carousel>` now works in Next.js App Router Server
6
+ Components (it failed to prerender before, as the hooks are not available on the server).
7
+ - Documentation: a copy-and-paste Tailwind CSS v4 example with a live preview compiled by
8
+ Tailwind, and notes for Tailwind and Next.js.
9
+
10
+ ## 0.1.1 (2026-09-21)
11
+
12
+ - Astro and `templateLabels`: `statusSingle` template for when only one slide is visible, so a
13
+ status like "Items {first} to {last}" does not read "Items 2 to 2".
14
+ - Documentation moved to https://www.nordwerk.studio/oss/scroll-carousel; the GitHub Pages
15
+ address forwards there.
16
+
3
17
  ## 0.1.0 (2026-09-21)
4
18
 
5
19
  First version.
package/README.md CHANGED
@@ -5,7 +5,7 @@ so the markup your server sends is already the final layout: no layout shift, no
5
5
  no device detection on the server. A small script adds arrows, dots, paging by group, an API and
6
6
  change events. Drag and autoplay are opt-in plugins. No runtime dependencies.
7
7
 
8
- **Live examples:** https://studio-nordwerk.github.io/scroll-carousel/ (every configuration, with
8
+ **Live examples:** https://www.nordwerk.studio/oss/scroll-carousel (every configuration, with
9
9
  its code, plus common storefront patterns as wireframes next to the library options they replace).
10
10
 
11
11
  | Part | gzip, minified |
@@ -102,6 +102,35 @@ import Carousel from '@nordwerk/scroll-carousel/astro';
102
102
  Slides go in the default slot, one element each. Drag and autoplay are loaded only on pages that
103
103
  use them. Labels take templates: `labels={{ page: 'Slide {n} of {count}' }}`.
104
104
 
105
+ ### Tailwind CSS
106
+
107
+ Import the stylesheet into the components layer, so utilities on your markup can override it, and
108
+ set the layout with arbitrary properties and container-query variants:
109
+
110
+ ```css
111
+ @import "tailwindcss";
112
+ @import "@nordwerk/scroll-carousel/carousel.css" layer(components);
113
+ ```
114
+
115
+ ```html
116
+ <div class="sc group/row relative [--sc-gap:1rem]">
117
+ <ul data-sc-track tabindex="0" aria-label="New arrivals"
118
+ class="sc-track [--sc-group:page] [--sc-per-view:1.3] @md:[--sc-per-view:2] @3xl:[--sc-per-view:4]">
119
+ <li>…</li>
120
+ </ul>
121
+ <button data-sc-next aria-label="Next products"
122
+ class="absolute end-3 top-1/3 hidden group-data-[sc-overflow]/row:grid aria-disabled:opacity-30">›</button>
123
+ </div>
124
+ ```
125
+
126
+ The complete example to copy, with a live preview compiled by Tailwind, is on the
127
+ [documentation site](https://www.nordwerk.studio/oss/scroll-carousel#tailwind).
128
+
129
+ ### Next.js
130
+
131
+ The React entry is marked `'use client'`, so `<Carousel>` can be used directly in Server
132
+ Components of the App Router; it renders on the server and attaches in the browser.
133
+
105
134
  ## Markup
106
135
 
107
136
  | Element | Required | Purpose |
package/dist/markup.d.ts CHANGED
@@ -36,10 +36,15 @@ export declare function responsiveCss(id: string, props: LayoutProps): string;
36
36
  * Start alignment only. It expects the root as its previous sibling.
37
37
  */
38
38
  export declare const PRE_POSITION: string;
39
- /** Label templates such as 'Slide {n} of {count}' turned into label functions. */
39
+ /**
40
+ * Label templates such as 'Slide {n} of {count}' turned into label functions. `statusSingle`
41
+ * is used when only one slide is visible, e.g. 'Item {first} of {count}' next to a `status` of
42
+ * 'Items {first} to {last} of {count}'.
43
+ */
40
44
  export declare function templateLabels(templates?: {
41
45
  page?: string;
42
46
  status?: string;
47
+ statusSingle?: string;
43
48
  }): {
44
49
  page?: ((n: number, count: number) => string) | undefined;
45
50
  status?: ((first: number, last: number, count: number) => string) | undefined;
package/dist/markup.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  baseVars,
5
5
  responsiveCss,
6
6
  templateLabels
7
- } from "./shared/chunk-I4ZMRKZV.js";
7
+ } from "./shared/chunk-QHWWA243.js";
8
8
  export {
9
9
  PRE_POSITION,
10
10
  baseStyle,
package/dist/preact.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  createAdapter
3
- } from "./shared/chunk-5Q4YPVNK.js";
3
+ } from "./shared/chunk-I3QEUR7L.js";
4
4
  import "./shared/chunk-HPGJKTV5.js";
5
5
  import "./shared/chunk-3THCBXDW.js";
6
- import "./shared/chunk-I4ZMRKZV.js";
6
+ import "./shared/chunk-QHWWA243.js";
7
7
 
8
8
  // src/preact.ts
9
9
  import { Fragment, createElement, toChildArray } from "preact";
package/dist/react.js CHANGED
@@ -1,9 +1,10 @@
1
+ 'use client';
1
2
  import {
2
3
  createAdapter
3
- } from "./shared/chunk-5Q4YPVNK.js";
4
+ } from "./shared/chunk-I3QEUR7L.js";
4
5
  import "./shared/chunk-HPGJKTV5.js";
5
6
  import "./shared/chunk-3THCBXDW.js";
6
- import "./shared/chunk-I4ZMRKZV.js";
7
+ import "./shared/chunk-QHWWA243.js";
7
8
 
8
9
  // src/react.ts
9
10
  import { Children, Fragment, createElement, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
@@ -5,7 +5,7 @@ import {
5
5
  PRE_POSITION,
6
6
  baseVars,
7
7
  responsiveCss
8
- } from "./chunk-I4ZMRKZV.js";
8
+ } from "./chunk-QHWWA243.js";
9
9
 
10
10
  // src/adapter.ts
11
11
  var chevron = (h, path) => h("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false" }, h("path", { d: path }));
@@ -43,10 +43,11 @@ function responsiveCss(id, props) {
43
43
  var PRE_POSITION = "(function(r){var t=r.querySelector('[data-sc-track]'),s=t&&t.querySelector('[data-sc-initial]'),f=t&&t.firstElementChild;if(!s||s==f)return;var a=s.getBoundingClientRect(),b=f.getBoundingClientRect();t.scrollLeft=getComputedStyle(t).direction=='rtl'?a.right-b.right:a.left-b.left})(document.currentScript.previousElementSibling)";
44
44
  function templateLabels(templates = {}) {
45
45
  const fill = (template, values) => template.replace(/\{(\w+)\}/g, (match, name) => name in values ? String(values[name]) : match);
46
+ const status = templates.status || templates.statusSingle;
46
47
  return {
47
48
  ...templates.page && { page: (n, count) => fill(templates.page, { n, count }) },
48
- ...templates.status && {
49
- status: (first, last, count) => fill(templates.status, { first, last, count })
49
+ ...status && {
50
+ status: (first, last, count) => fill(first == last && templates.statusSingle ? templates.statusSingle : status, { first, last, count })
50
51
  }
51
52
  };
52
53
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nordwerk/scroll-carousel",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A dependency-free carousel on native scrolling: CSS scroll snap first, arrows, dots, paging and an API as progressive enhancement.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/studio-nordwerk/scroll-carousel.git"
10
10
  },
11
- "homepage": "https://studio-nordwerk.github.io/scroll-carousel/",
11
+ "homepage": "https://www.nordwerk.studio/oss/scroll-carousel",
12
12
  "keywords": [
13
13
  "carousel",
14
14
  "slider",
@@ -87,7 +87,9 @@
87
87
  },
88
88
  "devDependencies": {
89
89
  "@axe-core/playwright": "4.13.0",
90
+ "@fontsource-variable/geist": "^5.3.0",
90
91
  "@playwright/test": "1.61.1",
92
+ "@tailwindcss/cli": "4.3.3",
91
93
  "@types/node": "^24.0.0",
92
94
  "@types/react": "^19.3.0",
93
95
  "@types/react-dom": "^19.3.0",
@@ -97,6 +99,7 @@
97
99
  "preact-render-to-string": "6.7.0",
98
100
  "react": "^19.3.0",
99
101
  "react-dom": "^19.3.0",
102
+ "tailwindcss": "4.3.3",
100
103
  "typescript": "^7.0.2"
101
104
  },
102
105
  "engines": {
@@ -21,8 +21,11 @@ interface Props extends LayoutProps {
21
21
  drag?: boolean;
22
22
  /** Milliseconds per page; renders the play button. */
23
23
  autoplay?: number;
24
- /** Label templates: page 'Slide {n} of {count}', status 'Items {first} to {last} of {count}', prev, next. */
25
- labels?: { page?: string; status?: string; prev?: string; next?: string; play?: string; pause?: string };
24
+ /**
25
+ * Label templates: page 'Slide {n} of {count}', status 'Items {first} to {last} of {count}',
26
+ * statusSingle 'Item {first} of {count}' for one visible slide, prev, next, play, pause.
27
+ */
28
+ labels?: { page?: string; status?: string; statusSingle?: string; prev?: string; next?: string; play?: string; pause?: string };
26
29
  }
27
30
 
28
31
  const props = Astro.props;