@obosbbl/grunnmuren-react 1.6.1 → 1.7.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.
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- export declare type ButtonColor = 'standard' | 'white' | 'light-green';
2
+ export type ButtonColor = 'standard' | 'white' | 'light-green';
3
3
  export interface ButtonProps extends React.ComponentPropsWithoutRef<'button'> {
4
4
  children: React.ReactNode;
5
5
  className?: string;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- export declare type ChipColor = 'blue-light' | 'green-light' | 'red-light' | 'orange-light';
2
+ export type ChipColor = 'blue-light' | 'green-light' | 'red-light' | 'orange-light';
3
3
  export interface ChipProps {
4
4
  icon?: React.ReactNode;
5
5
  color?: ChipColor;
@@ -4,8 +4,8 @@ export declare const HeroContext: import("react").Context<{
4
4
  contentPosition: HeroContentPosition;
5
5
  hasImage: boolean;
6
6
  }>;
7
- export declare type HeroColor = 'green' | 'blue' | 'white';
8
- export declare type HeroContentPosition = 'below-center' | 'below-left' | 'top-left' | 'bottom-left' | 'top-right' | 'bottom-right' | 'center' | 'vertical-split';
7
+ export type HeroColor = 'green' | 'blue' | 'white';
8
+ export type HeroContentPosition = 'below-center' | 'below-left' | 'top-left' | 'bottom-left' | 'top-right' | 'bottom-right' | 'center' | 'vertical-split';
9
9
  export interface HeroProps {
10
10
  /** @default white */
11
11
  bgColor?: HeroColor;
@@ -0,0 +1,23 @@
1
+ /// <reference types="react" />
2
+ import type { RequireAtLeastOne } from 'type-fest';
3
+ interface BasePaginationProps extends Omit<React.ComponentPropsWithoutRef<'nav'>, 'onChange'> {
4
+ /** The current page number.
5
+ * @note Starts at 1
6
+ */
7
+ page: number;
8
+ /** The total number of pages. */
9
+ count: number;
10
+ /** Given a page number, should return a valid href string. */
11
+ getItemHref: (page: number) => string;
12
+ /** Given a page number, should return a valid href string. */
13
+ getItemAriaLabel: (page: number) => string;
14
+ /** Aria label for the next page button link */
15
+ nextPageAriaLabel: string;
16
+ /** Aria label for the previous page button link */
17
+ prevPageAriaLabel: string;
18
+ /** Handler that is called with the page number to navigate to. `event.preventDefault` is called for you. Fallbacks to default browser behavior if undefined. */
19
+ onChange?: (page: number) => void;
20
+ }
21
+ type PaginationProps = RequireAtLeastOne<BasePaginationProps, 'aria-label' | 'aria-labelledby'>;
22
+ export declare const Pagination: (props: PaginationProps) => JSX.Element;
23
+ export {};
@@ -0,0 +1 @@
1
+ export * from './Pagination';
@@ -1,13 +1,25 @@
1
1
  /// <reference types="react" />
2
- interface StepListProps extends React.ComponentPropsWithoutRef<'ol'> {
2
+ type Alignment = 'center' | 'top';
3
+ export interface StepListProps extends React.ComponentPropsWithoutRef<'ol'> {
4
+ /**
5
+ * Determines the vertical alignment of the bullets
6
+ * @default 'center'
7
+ */
8
+ align?: Alignment;
9
+ /**
10
+ * <StepList> items
11
+ */
12
+ children: React.ReactNode;
3
13
  }
4
14
  declare const StepList: {
5
15
  (props: StepListProps): JSX.Element;
6
16
  Item: (props: StepListItemProps) => JSX.Element;
7
17
  };
8
- interface StepListItemProps extends React.ComponentPropsWithoutRef<'li'> {
18
+ export interface StepListItemProps extends React.ComponentPropsWithoutRef<'li'> {
9
19
  /** Content for the StepListItem's bullet */
10
20
  bullet: React.ReactNode;
21
+ /** @private this is set by the parent StepList component */
22
+ align?: Alignment;
11
23
  }
12
24
  export declare const StepListItem: (props: StepListItemProps) => JSX.Element;
13
25
  export { StepList };
@@ -68,6 +68,32 @@ const ChevronDown = (props) => /* @__PURE__ */ jsx("svg", __spreadProps2(__sprea
68
68
  d: "M0 4.31662L4.31662 0L14.3752 10.0484L24.4337 0L28.7503 4.31662L17.2563 15.8106C16.4929 16.5722 15.4586 16.9999 14.3803 16.9999C13.3019 16.9999 12.2676 16.5722 11.5042 15.8106L0 4.31662Z"
69
69
  })
70
70
  }));
71
+ const ChevronLeft = (props) => /* @__PURE__ */ jsx("svg", __spreadProps2(__spreadValues2({
72
+ width: "1.25em",
73
+ height: "1.25em",
74
+ fill: "none",
75
+ viewBox: "0 0 17 29",
76
+ role: "img",
77
+ "aria-hidden": props["aria-label"] == null
78
+ }, props), {
79
+ children: /* @__PURE__ */ jsx("path", {
80
+ fill: "currentColor",
81
+ d: "M12.6771 0L17 4.31278L6.95043 14.3624L17 24.4119L12.6771 28.7247L1.19328 17.2409C0.814993 16.8631 0.514893 16.4143 0.310141 15.9204C0.105389 15.4265 0 14.897 0 14.3624C0 13.8277 0.105389 13.2982 0.310141 12.8043C0.514893 12.3104 0.814993 11.8616 1.19328 11.4838L12.6771 0Z"
82
+ })
83
+ }));
84
+ const ChevronRight = (props) => /* @__PURE__ */ jsx("svg", __spreadProps2(__spreadValues2({
85
+ width: "1.25em",
86
+ height: "1.25em",
87
+ fill: "none",
88
+ viewBox: "0 0 17 29",
89
+ role: "img",
90
+ "aria-hidden": props["aria-label"] == null
91
+ }, props), {
92
+ children: /* @__PURE__ */ jsx("path", {
93
+ fill: "currentColor",
94
+ d: "M4.32295 28.7247L0 24.4119L10.0496 14.3624L0 4.31278L4.32295 0L15.8067 11.4838C16.185 11.8616 16.4851 12.3104 16.6899 12.8043C16.8946 13.2982 17 13.8277 17 14.3624C17 14.897 16.8946 15.4265 16.6899 15.9204C16.4851 16.4143 16.185 16.8631 15.8067 17.2409L4.32295 28.7247Z"
95
+ })
96
+ }));
71
97
  const Close = (props) => /* @__PURE__ */ jsx("svg", __spreadProps2(__spreadValues2({
72
98
  width: "1.25em",
73
99
  height: "1.25em",
@@ -568,7 +594,7 @@ const CardContent = (props) => {
568
594
  "className"
569
595
  ]);
570
596
  return /* @__PURE__ */ jsx("div", __spreadValues({
571
- className: cx(className, "p-8 md:p-10")
597
+ className: cx(className, "p-8 md:px-10")
572
598
  }, rest));
573
599
  };
574
600
  const CardLinkOverlay = forwardRef((props, ref) => {
@@ -1138,6 +1164,150 @@ const NavbarExpandedMobileContent = (props) => {
1138
1164
  children: props.children
1139
1165
  });
1140
1166
  };
1167
+ const SIBLING_COUNT = 2;
1168
+ const PaginationContext = createContext({
1169
+ currentPage: 0,
1170
+ pageCount: 0
1171
+ });
1172
+ const Pagination = (props) => {
1173
+ const _a = props, {
1174
+ className,
1175
+ page: currentPage,
1176
+ count: pageCount,
1177
+ onChange,
1178
+ getItemHref,
1179
+ getItemAriaLabel,
1180
+ nextPageAriaLabel,
1181
+ prevPageAriaLabel
1182
+ } = _a, rest = __objRest(_a, [
1183
+ "className",
1184
+ "page",
1185
+ "count",
1186
+ "onChange",
1187
+ "getItemHref",
1188
+ "getItemAriaLabel",
1189
+ "nextPageAriaLabel",
1190
+ "prevPageAriaLabel"
1191
+ ]);
1192
+ const context = useMemo(() => ({
1193
+ currentPage: Math.max(1, Math.min(currentPage, pageCount)),
1194
+ pageCount: Math.max(1, pageCount)
1195
+ }), [currentPage, pageCount]);
1196
+ const handleClick = (page) => (event) => {
1197
+ if (onChange) {
1198
+ event.preventDefault();
1199
+ onChange(page);
1200
+ }
1201
+ };
1202
+ return /* @__PURE__ */ jsx(PaginationContext.Provider, {
1203
+ value: context,
1204
+ children: /* @__PURE__ */ jsxs("nav", __spreadProps(__spreadValues({
1205
+ className: cx("flex justify-center gap-2 sm:gap-4", className)
1206
+ }, rest), {
1207
+ children: [/* @__PURE__ */ jsx(PrevPage, {
1208
+ "aria-label": prevPageAriaLabel,
1209
+ href: getItemHref(currentPage - 1),
1210
+ onClick: handleClick(currentPage - 1)
1211
+ }), /* @__PURE__ */ jsx(PageItem, {
1212
+ page: 1,
1213
+ href: getItemHref(1),
1214
+ onClick: handleClick(1),
1215
+ "aria-label": getItemAriaLabel(1),
1216
+ selected: currentPage === 1
1217
+ }), pageCount > 2 + SIBLING_COUNT * 2 && currentPage > SIBLING_COUNT + 2 && /* @__PURE__ */ jsx(PaginationEllipsis, {}), /* @__PURE__ */ jsx(Pages, {
1218
+ children: (page) => /* @__PURE__ */ jsx(PageItem, {
1219
+ href: getItemHref(page),
1220
+ onClick: handleClick(page),
1221
+ "aria-label": getItemAriaLabel(page),
1222
+ page,
1223
+ selected: page === currentPage
1224
+ }, page)
1225
+ }), /* @__PURE__ */ jsx(NextPage, {
1226
+ "aria-label": nextPageAriaLabel,
1227
+ href: getItemHref(currentPage + 1),
1228
+ onClick: handleClick(currentPage + 1)
1229
+ })]
1230
+ }))
1231
+ });
1232
+ };
1233
+ const NextPage = forwardRef((props, ref) => {
1234
+ const {
1235
+ currentPage,
1236
+ pageCount
1237
+ } = useContext(PaginationContext);
1238
+ const hide = currentPage >= pageCount;
1239
+ return /* @__PURE__ */ jsx(PageLink, __spreadProps(__spreadValues({
1240
+ "aria-hidden": hide,
1241
+ className: hide ? "invisible" : void 0,
1242
+ ref,
1243
+ rel: "next"
1244
+ }, props), {
1245
+ children: /* @__PURE__ */ jsx(ChevronRight, {})
1246
+ }));
1247
+ });
1248
+ const PrevPage = forwardRef((props, ref) => {
1249
+ const {
1250
+ currentPage
1251
+ } = useContext(PaginationContext);
1252
+ const hide = currentPage <= 1;
1253
+ return /* @__PURE__ */ jsx(PageLink, __spreadProps(__spreadValues({
1254
+ "aria-hidden": hide,
1255
+ className: hide ? "invisible" : void 0,
1256
+ ref,
1257
+ rel: "prev"
1258
+ }, props), {
1259
+ children: /* @__PURE__ */ jsx(ChevronLeft, {})
1260
+ }));
1261
+ });
1262
+ const PageLink = forwardRef((props, ref) => {
1263
+ const _a = props, {
1264
+ className
1265
+ } = _a, rest = __objRest(_a, [
1266
+ "className"
1267
+ ]);
1268
+ return /* @__PURE__ */ jsx("a", __spreadValues({
1269
+ className: cx(className, "aria-[current]:border-green hover:bg-gray-concrete flex h-9 w-9 items-center justify-center rounded-lg border-2 border-transparent no-underline sm:h-10 sm:w-10"),
1270
+ ref
1271
+ }, rest));
1272
+ });
1273
+ const PaginationEllipsis = () => {
1274
+ return /* @__PURE__ */ jsx("span", {
1275
+ className: "flex h-9 w-9 cursor-default items-center justify-center border-2 border-transparent sm:h-10 sm:w-10",
1276
+ children: "..."
1277
+ });
1278
+ };
1279
+ const Pages = ({
1280
+ children
1281
+ }) => {
1282
+ const {
1283
+ currentPage,
1284
+ pageCount
1285
+ } = useContext(PaginationContext);
1286
+ const end = Math.min(Math.max(2 + SIBLING_COUNT * 2, currentPage + SIBLING_COUNT), pageCount);
1287
+ let start = Math.max(Math.min(currentPage - SIBLING_COUNT, end - SIBLING_COUNT * 2), 1);
1288
+ if (start - SIBLING_COUNT === 0) {
1289
+ start = start - 1;
1290
+ }
1291
+ const pages = Array.from({
1292
+ length: end - start
1293
+ }, (_, i) => start + i + 1);
1294
+ return pages.map((page) => children(page));
1295
+ };
1296
+ const PageItem = forwardRef((props, ref) => {
1297
+ const _a = props, {
1298
+ page,
1299
+ selected
1300
+ } = _a, rest = __objRest(_a, [
1301
+ "page",
1302
+ "selected"
1303
+ ]);
1304
+ return /* @__PURE__ */ jsx(PageLink, __spreadProps(__spreadValues({
1305
+ "aria-current": selected ? "page" : void 0,
1306
+ ref
1307
+ }, rest), {
1308
+ children: page
1309
+ }));
1310
+ });
1141
1311
  const RadioContext = createContext({
1142
1312
  defaultValue: void 0,
1143
1313
  isControlled: false,
@@ -1301,30 +1471,60 @@ const SnackbarContent = (props) => {
1301
1471
  }));
1302
1472
  };
1303
1473
  const StepList = (props) => {
1304
- return /* @__PURE__ */ jsx("ol", __spreadValues({}, props));
1474
+ const _a = props, {
1475
+ align = "center",
1476
+ children,
1477
+ className
1478
+ } = _a, rest = __objRest(_a, [
1479
+ "align",
1480
+ "children",
1481
+ "className"
1482
+ ]);
1483
+ return /* @__PURE__ */ jsx("ol", __spreadProps(__spreadValues({
1484
+ className: cx(className, "flex flex-col gap-8 md:gap-12")
1485
+ }, rest), {
1486
+ children: Children.map(children, (child) => {
1487
+ return cloneElement(child, {
1488
+ align
1489
+ });
1490
+ })
1491
+ }));
1305
1492
  };
1306
1493
  const StepListItem = (props) => {
1307
1494
  const _a = props, {
1308
1495
  className,
1309
1496
  children,
1310
- bullet
1497
+ bullet,
1498
+ align = "center"
1311
1499
  } = _a, rest = __objRest(_a, [
1312
1500
  "className",
1313
1501
  "children",
1314
- "bullet"
1502
+ "bullet",
1503
+ "align"
1315
1504
  ]);
1316
1505
  return /* @__PURE__ */ jsxs("li", __spreadProps(__spreadValues({
1317
- className: cx(className, "group relative flex items-center gap-4 pb-8 text-sm last:pb-0 md:gap-8 md:pb-12 md:text-base")
1506
+ className: cx(className, "group relative flex gap-4 text-sm md:gap-8 md:text-base", {
1507
+ "items-center": align === "center"
1508
+ })
1318
1509
  }, rest), {
1319
1510
  children: [/* @__PURE__ */ jsx(StepListBullet, {
1511
+ align,
1320
1512
  children: bullet
1321
1513
  }), children]
1322
1514
  }));
1323
1515
  };
1324
- const StepListBullet = (props) => {
1516
+ const StepListBullet = (_a) => {
1517
+ var _b = _a, {
1518
+ align
1519
+ } = _b, props = __objRest(_b, [
1520
+ "align"
1521
+ ]);
1325
1522
  return /* @__PURE__ */ jsx("span", __spreadValues({
1326
1523
  "aria-hidden": true,
1327
- className: "text-green after:bg-gray-light grid h-10 w-10 flex-none place-content-center justify-items-center rounded-full border-2 text-sm font-bold after:absolute after:left-5 after:top-10 after:bottom-0 after:w-0.5 group-last:after:hidden md:h-20 md:w-20 md:text-xl md:after:left-10 md:after:top-20"
1524
+ className: cx("text-green after:bg-gray-light before:bg-gray-light grid h-10 w-10 flex-none place-content-center justify-items-center rounded-full border-2 text-sm font-bold after:absolute after:bottom-0 after:w-0.5 after:translate-x-1/2 group-last:after:hidden md:h-20 md:w-20 md:text-xl ", {
1525
+ "before:absolute before:top-0 before:bottom-1/2 before:w-0.5 before:-translate-y-5 before:translate-x-1/2 after:top-1/2 after:translate-y-5 group-first:before:hidden before:md:-translate-y-10 after:md:translate-y-10": align === "center",
1526
+ "after:top-10 after:-bottom-8 after:md:-bottom-12 after:md:top-20": align === "top"
1527
+ })
1328
1528
  }, props));
1329
1529
  };
1330
1530
  StepList.Item = StepListItem;
@@ -1428,4 +1628,4 @@ const TextField = forwardRef((props, ref) => {
1428
1628
  })]
1429
1629
  });
1430
1630
  });
1431
- export { Accordion, AccordionContent, AccordionHeader, AccordionItem, Alert, Banner, BannerImage, Button, ButtonColorContext, Campaign, Card, CardContent, CardImage, CardLinkOverlay, CardList, Checkbox, Chip, Footer, Form, FormError, FormErrorMessage, FormHeading, FormHelperText, FormLabel, FormSuccess, Hero, HeroActions, HeroContent, HeroContext, HeroImage, Input, Link, Navbar, NavbarCollapsible, NavbarContent, NavbarExpandedMobileContent, NavbarItem, NavbarItems, Radio, RadioGroup, Select, Snackbar, SnackbarButton, SnackbarContent, StepList, StepListItem, TextArea, TextField, useBlockBackgroundColor, useFallbackId, useFormControlValidity, usePrefersReducedMotion, useScreenMaxWidthMd };
1631
+ export { Accordion, AccordionContent, AccordionHeader, AccordionItem, Alert, Banner, BannerImage, Button, ButtonColorContext, Campaign, Card, CardContent, CardImage, CardLinkOverlay, CardList, Checkbox, Chip, Footer, Form, FormError, FormErrorMessage, FormHeading, FormHelperText, FormLabel, FormSuccess, Hero, HeroActions, HeroContent, HeroContext, HeroImage, Input, Link, Navbar, NavbarCollapsible, NavbarContent, NavbarExpandedMobileContent, NavbarItem, NavbarItems, Pagination, Radio, RadioGroup, Select, Snackbar, SnackbarButton, SnackbarContent, StepList, StepListItem, TextArea, TextField, useBlockBackgroundColor, useFallbackId, useFormControlValidity, usePrefersReducedMotion, useScreenMaxWidthMd };
@@ -1,2 +1,2 @@
1
- export declare type BlockBackgroundColor = 'yellow' | 'gray' | 'blue' | 'green';
1
+ export type BlockBackgroundColor = 'yellow' | 'gray' | 'blue' | 'green';
2
2
  export declare function useBlockBackgroundColor(blockBgColor: BlockBackgroundColor | undefined): string | undefined;
@@ -1,5 +1,5 @@
1
1
  import { RefObject } from 'react';
2
- declare type Validity = 'indeterminate' | 'invalid' | 'valid';
2
+ type Validity = 'indeterminate' | 'invalid' | 'valid';
3
3
  /**
4
4
  * Browser validation as it should be. "Invalid" only triggers after the user has blurred an input, or attempted
5
5
  * to submit the form.
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from './Hero';
12
12
  export * from './Input';
13
13
  export * from './Link';
14
14
  export * from './Navbar';
15
+ export * from './Pagination';
15
16
  export * from './Radio';
16
17
  export * from './Select';
17
18
  export * from './Snackbar';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obosbbl/grunnmuren-react",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "OBOS Grunnmuren design system React components",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,35 +17,36 @@
17
17
  ],
18
18
  "types": "./dist/index.d.ts",
19
19
  "devDependencies": {
20
- "@babel/core": "7.19.6",
21
- "@obosbbl/grunnmuren-tailwind": "0.8.1",
22
- "@storybook/addon-controls": "6.5.13",
23
- "@storybook/addon-docs": "6.5.13",
20
+ "@babel/core": "7.20.2",
21
+ "@storybook/addon-controls": "6.5.14",
22
+ "@storybook/addon-docs": "6.5.14",
24
23
  "@storybook/addon-postcss": "2.0.0",
25
- "@storybook/builder-webpack5": "6.5.13",
26
- "@storybook/manager-webpack5": "6.5.13",
27
- "@storybook/react": "6.5.13",
24
+ "@storybook/builder-webpack5": "6.5.14",
25
+ "@storybook/manager-webpack5": "6.5.14",
26
+ "@storybook/react": "6.5.14",
28
27
  "@types/react": "18.0.25",
29
- "@types/react-dom": "18.0.8",
28
+ "@types/react-dom": "18.0.9",
30
29
  "@vitejs/plugin-react": "1.3.2",
31
- "postcss": "8.4.18",
30
+ "postcss": "8.4.19",
32
31
  "react": "18.2.0",
33
32
  "react-dom": "18.2.0",
34
33
  "require-from-string": "2.0.2",
35
34
  "rimraf": "3.0.2",
36
- "tailwindcss": "3.2.1",
35
+ "tailwindcss": "3.2.4",
36
+ "type-fest": "3.3.0",
37
37
  "vite": "2.9.15",
38
- "webpack": "5.74.0"
38
+ "webpack": "5.75.0",
39
+ "@obosbbl/grunnmuren-tailwind": "0.8.3"
39
40
  },
40
41
  "dependencies": {
41
- "@obosbbl/grunnmuren-icons": "^0.5.1",
42
42
  "@seznam/compose-react-refs": "1.0.6",
43
43
  "clsx": "1.2.1",
44
44
  "react-collapsed": "3.5.0",
45
- "react-use": "17.4.0"
45
+ "react-use": "17.4.0",
46
+ "@obosbbl/grunnmuren-icons": "^0.5.1"
46
47
  },
47
48
  "peerDependencies": {
48
- "@obosbbl/grunnmuren-tailwind": "^0.8.1",
49
+ "@obosbbl/grunnmuren-tailwind": "^0.8.3",
49
50
  "react": "^18"
50
51
  },
51
52
  "peerDependenciesMeta": {