@ship-it-ui/shipit 0.0.14 → 0.0.16

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/dist/index.js CHANGED
@@ -1191,10 +1191,10 @@ var PathOverlay = forwardRef18(function PathOverlay2({ points, color = "var(--co
1191
1191
  PathOverlay.displayName = "PathOverlay";
1192
1192
 
1193
1193
  // src/marketing/CTAStrip.tsx
1194
- import { cn as cn16 } from "@ship-it-ui/ui";
1194
+ import { Heading, cn as cn16 } from "@ship-it-ui/ui";
1195
1195
  import { forwardRef as forwardRef19 } from "react";
1196
1196
  import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
1197
- var CTAStrip = forwardRef19(function CTAStrip2({ title, description, actions, className, ...props }, ref) {
1197
+ var CTAStrip = forwardRef19(function CTAStrip2({ title, titleAs = "h2", description, actions, className, ...props }, ref) {
1198
1198
  return /* @__PURE__ */ jsxs18(
1199
1199
  "section",
1200
1200
  {
@@ -1206,7 +1206,7 @@ var CTAStrip = forwardRef19(function CTAStrip2({ title, description, actions, cl
1206
1206
  ),
1207
1207
  ...props,
1208
1208
  children: [
1209
- /* @__PURE__ */ jsx19("h2", { className: "m-0 mb-[10px] text-[28px] font-medium tracking-[-0.4px]", children: title }),
1209
+ /* @__PURE__ */ jsx19(Heading, { as: titleAs, className: "m-0 mb-[10px] text-[28px] font-medium tracking-[-0.4px]", children: title }),
1210
1210
  description && /* @__PURE__ */ jsx19("p", { className: "text-text-muted m-0 mb-5 text-[13px]", children: description }),
1211
1211
  actions && /* @__PURE__ */ jsx19("div", { className: "flex flex-wrap justify-center gap-2", children: actions })
1212
1212
  ]
@@ -1216,7 +1216,7 @@ var CTAStrip = forwardRef19(function CTAStrip2({ title, description, actions, cl
1216
1216
  CTAStrip.displayName = "CTAStrip";
1217
1217
 
1218
1218
  // src/marketing/FeatureGrid.tsx
1219
- import { cn as cn17 } from "@ship-it-ui/ui";
1219
+ import { Heading as Heading2, cn as cn17 } from "@ship-it-ui/ui";
1220
1220
  import { forwardRef as forwardRef20 } from "react";
1221
1221
  import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
1222
1222
  var colsClass = {
@@ -1224,7 +1224,7 @@ var colsClass = {
1224
1224
  3: "md:grid-cols-3",
1225
1225
  4: "md:grid-cols-2 lg:grid-cols-4"
1226
1226
  };
1227
- var FeatureGrid = forwardRef20(function FeatureGrid2({ features, columns = 3, className, ...props }, ref) {
1227
+ var FeatureGrid = forwardRef20(function FeatureGrid2({ features, columns = 3, featureTitleAs = "h3", className, ...props }, ref) {
1228
1228
  return /* @__PURE__ */ jsx20(
1229
1229
  "div",
1230
1230
  {
@@ -1233,7 +1233,7 @@ var FeatureGrid = forwardRef20(function FeatureGrid2({ features, columns = 3, cl
1233
1233
  ...props,
1234
1234
  children: features.map((f, i) => /* @__PURE__ */ jsxs19("div", { className: "rounded-base border-border bg-panel border p-5", children: [
1235
1235
  /* @__PURE__ */ jsx20("div", { "aria-hidden": true, className: "text-accent mb-3 text-[22px]", children: f.glyph }),
1236
- /* @__PURE__ */ jsx20("div", { className: "mb-[6px] text-[14px] font-medium", children: f.title }),
1236
+ /* @__PURE__ */ jsx20(Heading2, { as: featureTitleAs, className: "mb-[6px] text-[14px] font-medium", children: f.title }),
1237
1237
  /* @__PURE__ */ jsx20("div", { className: "text-text-muted text-[12px] leading-[1.55]", children: f.description })
1238
1238
  ] }, i))
1239
1239
  }
@@ -1245,21 +1245,16 @@ FeatureGrid.displayName = "FeatureGrid";
1245
1245
  import { cn as cn18 } from "@ship-it-ui/ui";
1246
1246
  import { forwardRef as forwardRef21 } from "react";
1247
1247
  import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
1248
- var Footer = forwardRef21(function Footer2({ brand, columns, copyright, closing, className, ...props }, ref) {
1248
+ var Footer = forwardRef21(function Footer2({ brand, columns, copyright, closing, address, className, ...props }, ref) {
1249
1249
  return /* @__PURE__ */ jsxs20("footer", { ref, className: cn18("px-7 py-7", className), ...props, children: [
1250
1250
  /* @__PURE__ */ jsxs20("div", { className: "mb-7 flex flex-wrap gap-8", children: [
1251
- brand && /* @__PURE__ */ jsx21("div", { children: brand }),
1251
+ brand && /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-2", children: [
1252
+ /* @__PURE__ */ jsx21("div", { children: brand }),
1253
+ address && /* @__PURE__ */ jsx21("address", { className: "text-text-dim text-[12px] not-italic", children: address })
1254
+ ] }),
1252
1255
  /* @__PURE__ */ jsx21("div", { className: "text-text-muted ml-auto flex flex-wrap gap-6 text-[12px]", children: columns.map((col, i) => /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-[6px]", children: [
1253
1256
  /* @__PURE__ */ jsx21("div", { className: "text-text-dim font-mono text-[10px] tracking-[1.2px] uppercase", children: col.heading }),
1254
- col.links.map((link, j) => /* @__PURE__ */ jsx21(
1255
- "a",
1256
- {
1257
- href: link.href,
1258
- className: "text-text-muted hover:text-text no-underline",
1259
- children: link.label
1260
- },
1261
- j
1262
- ))
1257
+ /* @__PURE__ */ jsx21("ul", { className: "m-0 flex list-none flex-col gap-[6px] p-0", children: col.links.map((link, j) => /* @__PURE__ */ jsx21("li", { children: /* @__PURE__ */ jsx21("a", { href: link.href, className: "text-text-muted hover:text-text no-underline", children: link.label }) }, j)) })
1263
1258
  ] }, i)) })
1264
1259
  ] }),
1265
1260
  /* @__PURE__ */ jsxs20("div", { className: "border-border text-text-dim flex border-t pt-4 font-mono text-[11px]", children: [
@@ -1271,10 +1266,10 @@ var Footer = forwardRef21(function Footer2({ brand, columns, copyright, closing,
1271
1266
  Footer.displayName = "Footer";
1272
1267
 
1273
1268
  // src/marketing/Hero.tsx
1274
- import { cn as cn19 } from "@ship-it-ui/ui";
1269
+ import { Heading as Heading3, cn as cn19 } from "@ship-it-ui/ui";
1275
1270
  import { forwardRef as forwardRef22 } from "react";
1276
1271
  import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
1277
- var Hero = forwardRef22(function Hero2({ eyebrow, title, description, actions, visual, className, ...props }, ref) {
1272
+ var Hero = forwardRef22(function Hero2({ eyebrow, title, titleAs = "h1", description, actions, visual, className, ...props }, ref) {
1278
1273
  const hasVisual = visual != null;
1279
1274
  return /* @__PURE__ */ jsxs21(
1280
1275
  "section",
@@ -1290,8 +1285,9 @@ var Hero = forwardRef22(function Hero2({ eyebrow, title, description, actions, v
1290
1285
  /* @__PURE__ */ jsxs21("div", { className: cn19("max-w-[680px]", !hasVisual && "mx-auto text-center"), children: [
1291
1286
  eyebrow,
1292
1287
  /* @__PURE__ */ jsx22(
1293
- "h1",
1288
+ Heading3,
1294
1289
  {
1290
+ as: titleAs,
1295
1291
  className: cn19(
1296
1292
  "mb-4 text-[44px] leading-[1.05] font-medium tracking-[-1.6px] md:text-[56px]",
1297
1293
  eyebrow && "mt-5"
@@ -1310,10 +1306,76 @@ var Hero = forwardRef22(function Hero2({ eyebrow, title, description, actions, v
1310
1306
  Hero.displayName = "Hero";
1311
1307
 
1312
1308
  // src/marketing/PricingCard.tsx
1313
- import { cn as cn20 } from "@ship-it-ui/ui";
1309
+ import { Heading as Heading4, JsonLd, cn as cn20, nodeToString } from "@ship-it-ui/ui";
1314
1310
  import { forwardRef as forwardRef23 } from "react";
1315
1311
  import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
1316
- var PricingCard = forwardRef23(function PricingCard2({ tier, price, priceUnit, description, features, action, featured, className, ...props }, ref) {
1312
+ function parsePrice(priceAmount, price) {
1313
+ if (typeof priceAmount === "number" && Number.isFinite(priceAmount)) {
1314
+ return priceAmount;
1315
+ }
1316
+ const text = nodeToString(price);
1317
+ if (!text) return null;
1318
+ const cleaned = text.replace(/[^\d.]/g, "");
1319
+ if (!cleaned) return null;
1320
+ const n = Number(cleaned);
1321
+ return Number.isFinite(n) ? n : null;
1322
+ }
1323
+ function buildOfferSchema(props) {
1324
+ if (!props.priceCurrency) return null;
1325
+ const name = props.tierName ?? nodeToString(props.tier);
1326
+ if (!name) return null;
1327
+ const numericPrice = parsePrice(props.priceAmount, props.price);
1328
+ if (numericPrice === null) return null;
1329
+ const schema = {
1330
+ "@context": "https://schema.org",
1331
+ "@type": "Offer",
1332
+ name,
1333
+ price: numericPrice,
1334
+ priceCurrency: props.priceCurrency
1335
+ };
1336
+ const description = props.descriptionText ?? nodeToString(props.description);
1337
+ if (description) {
1338
+ schema.description = description;
1339
+ }
1340
+ if (props.availability) {
1341
+ schema.availability = props.availability;
1342
+ }
1343
+ if (props.url) {
1344
+ schema.url = props.url;
1345
+ }
1346
+ return schema;
1347
+ }
1348
+ var PricingCard = forwardRef23(function PricingCard2({
1349
+ tier,
1350
+ price,
1351
+ priceUnit,
1352
+ description,
1353
+ features,
1354
+ action,
1355
+ featured,
1356
+ tierAs = "h3",
1357
+ priceCurrency,
1358
+ priceAmount,
1359
+ availability,
1360
+ url,
1361
+ tierName,
1362
+ descriptionText,
1363
+ noStructuredData,
1364
+ className,
1365
+ ...props
1366
+ }, ref) {
1367
+ const structuredData = !noStructuredData ? buildOfferSchema({
1368
+ tier,
1369
+ price,
1370
+ features,
1371
+ priceCurrency,
1372
+ priceAmount,
1373
+ availability,
1374
+ url,
1375
+ tierName,
1376
+ description,
1377
+ descriptionText
1378
+ }) : null;
1317
1379
  return /* @__PURE__ */ jsxs22(
1318
1380
  "div",
1319
1381
  {
@@ -1325,9 +1387,10 @@ var PricingCard = forwardRef23(function PricingCard2({ tier, price, priceUnit, d
1325
1387
  ),
1326
1388
  ...props,
1327
1389
  children: [
1390
+ structuredData && /* @__PURE__ */ jsx23(JsonLd, { data: structuredData }),
1328
1391
  /* @__PURE__ */ jsxs22("div", { children: [
1329
1392
  /* @__PURE__ */ jsxs22("div", { className: "mb-1 flex flex-wrap items-center gap-2", children: [
1330
- /* @__PURE__ */ jsx23("span", { className: "text-[14px] font-medium", children: tier }),
1393
+ /* @__PURE__ */ jsx23(Heading4, { as: tierAs, className: "text-[14px] font-medium", children: tier }),
1331
1394
  featured && /* @__PURE__ */ jsx23("span", { className: "bg-accent-dim text-accent rounded-full px-[6px] py-[1px] font-mono text-[10px]", children: "recommended" })
1332
1395
  ] }),
1333
1396
  description && /* @__PURE__ */ jsx23("div", { className: "text-text-muted text-[12px]", children: description })
@@ -1348,11 +1411,64 @@ var PricingCard = forwardRef23(function PricingCard2({ tier, price, priceUnit, d
1348
1411
  PricingCard.displayName = "PricingCard";
1349
1412
 
1350
1413
  // src/marketing/Testimonial.tsx
1351
- import { Avatar as Avatar2 } from "@ship-it-ui/ui";
1352
- import { cn as cn21 } from "@ship-it-ui/ui";
1414
+ import { Avatar as Avatar2, JsonLd as JsonLd2, cn as cn21, nodeToString as nodeToString2 } from "@ship-it-ui/ui";
1353
1415
  import { forwardRef as forwardRef24 } from "react";
1354
1416
  import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
1355
- var Testimonial = forwardRef24(function Testimonial2({ quote, author, role, avatar, className, ...props }, ref) {
1417
+ function buildTestimonialSchema(props) {
1418
+ const authorName = props.authorName ?? nodeToString2(props.author);
1419
+ const reviewBody = props.quoteText ?? nodeToString2(props.quote);
1420
+ if (!authorName || !reviewBody) return null;
1421
+ const schema = {
1422
+ "@context": "https://schema.org",
1423
+ "@type": "Review",
1424
+ author: { "@type": "Person", name: authorName },
1425
+ reviewBody
1426
+ };
1427
+ const jobTitle = props.authorJobTitle ?? nodeToString2(props.role);
1428
+ if (jobTitle) {
1429
+ schema.author.jobTitle = jobTitle;
1430
+ }
1431
+ if (typeof props.rating === "number") {
1432
+ schema.reviewRating = {
1433
+ "@type": "Rating",
1434
+ ratingValue: props.rating,
1435
+ bestRating: 5
1436
+ };
1437
+ }
1438
+ if (props.itemReviewedName) {
1439
+ schema.itemReviewed = { "@type": "Thing", name: props.itemReviewedName };
1440
+ if (props.url) {
1441
+ schema.itemReviewed.url = props.url;
1442
+ }
1443
+ }
1444
+ return schema;
1445
+ }
1446
+ var Testimonial = forwardRef24(function Testimonial2({
1447
+ quote,
1448
+ author,
1449
+ role,
1450
+ avatar,
1451
+ quoteText,
1452
+ authorName,
1453
+ authorJobTitle,
1454
+ rating,
1455
+ itemReviewedName,
1456
+ url,
1457
+ noStructuredData,
1458
+ className,
1459
+ ...props
1460
+ }, ref) {
1461
+ const structuredData = !noStructuredData ? buildTestimonialSchema({
1462
+ quote,
1463
+ author,
1464
+ role,
1465
+ quoteText,
1466
+ authorName,
1467
+ authorJobTitle,
1468
+ rating,
1469
+ itemReviewedName,
1470
+ url
1471
+ }) : null;
1356
1472
  return /* @__PURE__ */ jsxs23(
1357
1473
  "figure",
1358
1474
  {
@@ -1360,6 +1476,7 @@ var Testimonial = forwardRef24(function Testimonial2({ quote, author, role, avat
1360
1476
  className: cn21("mx-auto max-w-[620px] px-6 py-10 text-center", className),
1361
1477
  ...props,
1362
1478
  children: [
1479
+ structuredData && /* @__PURE__ */ jsx24(JsonLd2, { data: structuredData }),
1363
1480
  /* @__PURE__ */ jsx24("div", { "aria-hidden": true, className: "text-accent mb-4 text-[40px] leading-none", children: "\u201C" }),
1364
1481
  /* @__PURE__ */ jsx24("blockquote", { className: "m-0 text-[22px] leading-[1.45] font-medium tracking-[-0.3px]", children: quote }),
1365
1482
  /* @__PURE__ */ jsxs23("figcaption", { className: "mt-5 flex items-center justify-center gap-[10px]", children: [
@@ -1377,9 +1494,31 @@ Testimonial.displayName = "Testimonial";
1377
1494
 
1378
1495
  // src/data/ConnectorCard.tsx
1379
1496
  import { DynamicIconGlyph as DynamicIconGlyph5 } from "@ship-it-ui/icons";
1380
- import { cn as cn22, formatRelative, StatusDot } from "@ship-it-ui/ui";
1497
+ import {
1498
+ cn as cn22,
1499
+ formatRelative,
1500
+ JsonLd as JsonLd3,
1501
+ nodeToString as nodeToString3,
1502
+ StatusDot,
1503
+ toIsoString
1504
+ } from "@ship-it-ui/ui";
1381
1505
  import { forwardRef as forwardRef25 } from "react";
1382
1506
  import { Fragment as Fragment4, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
1507
+ function buildConnectorSchema(input) {
1508
+ const name = input.nameText ?? nodeToString3(input.name);
1509
+ if (!name) return null;
1510
+ const schema = {
1511
+ "@context": "https://schema.org",
1512
+ "@type": "SoftwareApplication",
1513
+ name
1514
+ };
1515
+ if (input.applicationCategory) schema.applicationCategory = input.applicationCategory;
1516
+ if (input.url) schema.url = input.url;
1517
+ if (input.softwareVersion) schema.softwareVersion = input.softwareVersion;
1518
+ const dateModified = toIsoString(input.lastSyncedAt);
1519
+ if (dateModified) schema.dateModified = dateModified;
1520
+ return schema;
1521
+ }
1383
1522
  var statusDot = {
1384
1523
  connected: "ok",
1385
1524
  syncing: "sync",
@@ -1402,11 +1541,24 @@ var ConnectorCard = forwardRef25(function ConnectorCard2({
1402
1541
  actions,
1403
1542
  onClick,
1404
1543
  accessibleName,
1544
+ nameText,
1545
+ applicationCategory,
1546
+ url,
1547
+ softwareVersion,
1548
+ noStructuredData,
1405
1549
  className,
1406
1550
  ...props
1407
1551
  }, ref) {
1408
1552
  const interactive = typeof onClick === "function";
1409
1553
  const time = lastSyncedAt ? formatRelative(lastSyncedAt, relativeNow ?? /* @__PURE__ */ new Date()) : "";
1554
+ const structuredData = !noStructuredData ? buildConnectorSchema({
1555
+ name,
1556
+ nameText,
1557
+ applicationCategory,
1558
+ url,
1559
+ softwareVersion,
1560
+ lastSyncedAt
1561
+ }) : null;
1410
1562
  const labelBlock = /* @__PURE__ */ jsxs24(Fragment4, { children: [
1411
1563
  /* @__PURE__ */ jsx25(
1412
1564
  "span",
@@ -1462,6 +1614,7 @@ var ConnectorCard = forwardRef25(function ConnectorCard2({
1462
1614
  ),
1463
1615
  ...props,
1464
1616
  children: [
1617
+ structuredData && /* @__PURE__ */ jsx25(JsonLd3, { data: structuredData }),
1465
1618
  labelRegion,
1466
1619
  actions && /* @__PURE__ */ jsx25("div", { className: "shrink-0 self-center pr-1", children: actions })
1467
1620
  ]
@@ -1503,7 +1656,7 @@ function entityTypeColumn(options = {}) {
1503
1656
  }
1504
1657
 
1505
1658
  // src/notifications/NotifRow.tsx
1506
- import { cn as cn23 } from "@ship-it-ui/ui";
1659
+ import { DateTime, cn as cn23 } from "@ship-it-ui/ui";
1507
1660
  import { forwardRef as forwardRef26 } from "react";
1508
1661
  import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
1509
1662
  var toneClass = {
@@ -1516,6 +1669,7 @@ var NotifRow = forwardRef26(function NotifRow2({
1516
1669
  title,
1517
1670
  body,
1518
1671
  time,
1672
+ dateTime,
1519
1673
  tone = "neutral",
1520
1674
  unread,
1521
1675
  isFirst,
@@ -1535,7 +1689,14 @@ var NotifRow = forwardRef26(function NotifRow2({
1535
1689
  /* @__PURE__ */ jsxs26("div", { className: "min-w-0 flex-1", children: [
1536
1690
  /* @__PURE__ */ jsxs26("div", { className: "flex items-baseline justify-between gap-2", children: [
1537
1691
  /* @__PURE__ */ jsx27("div", { className: "truncate text-[14px] font-medium tracking-tight", children: title }),
1538
- time != null && /* @__PURE__ */ jsx27("span", { className: "text-text-muted shrink-0 font-mono text-[11px] whitespace-nowrap", children: time })
1692
+ time != null && (dateTime !== void 0 ? /* @__PURE__ */ jsx27(
1693
+ DateTime,
1694
+ {
1695
+ iso: dateTime,
1696
+ className: "text-text-muted shrink-0 font-mono text-[11px] whitespace-nowrap",
1697
+ children: time
1698
+ }
1699
+ ) : /* @__PURE__ */ jsx27("span", { className: "text-text-muted shrink-0 font-mono text-[11px] whitespace-nowrap", children: time }))
1539
1700
  ] }),
1540
1701
  body && /* @__PURE__ */ jsx27("div", { className: "text-text-muted mt-[3px] text-[13px] leading-tight", children: body })
1541
1702
  ] })