@mlola-ui/engine 1.0.10 → 1.0.12

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.
@@ -255,6 +255,10 @@
255
255
  "name": "ml-chart-heading",
256
256
  "note": ""
257
257
  },
258
+ {
259
+ "name": "ml-check-list",
260
+ "note": "A list of benefits, each after a check. Pricing tiers and feature rows share it."
261
+ },
258
262
  {
259
263
  "name": "ml-cluster",
260
264
  "note": ""
@@ -337,7 +341,7 @@
337
341
  },
338
342
  {
339
343
  "name": "ml-page-shell",
340
- "note": "A full page: header, main and footer stacked on the page background."
344
+ "note": "The navigation, main and footer are grid items; they may be narrower than their widest content (a table that scrolls), so the page never does."
341
345
  },
342
346
  {
343
347
  "name": "ml-person",
@@ -361,7 +365,7 @@
361
365
  },
362
366
  {
363
367
  "name": "ml-section",
364
- "note": ""
368
+ "note": "A section a link jumps to clears the sticky navigation bar."
365
369
  },
366
370
  {
367
371
  "name": "ml-section-description",
@@ -127,10 +127,12 @@ Compose pages from these before writing layout CSS: sections, stacks,
127
127
  clusters, grids, headings, forms, stats. They read the same tokens as every
128
128
  component, so a page built from them themes with the rest.
129
129
 
130
- `.ml-actions` `.ml-brand` `.ml-brand-mark` `.ml-brand-name` `.ml-chart` `.ml-chart-bar` `.ml-chart-bars` `.ml-chart-heading` `.ml-cluster` `.ml-definition-list` `.ml-display` `.ml-divider` `.ml-empty-state` `.ml-eyebrow` `.ml-filter-chip` `.ml-filter-group` `.ml-fine-print` `.ml-form` `.ml-form-message` `.ml-form-options` `.ml-grid` `.ml-heading` `.ml-icon-chip` `.ml-inline-form` `.ml-inline-form-field` `.ml-label` `.ml-lede` `.ml-link` `.ml-page-shell` `.ml-person` `.ml-person-copy` `.ml-positive` `.ml-price` `.ml-required-mark` `.ml-section` `.ml-section-description` `.ml-section-header` `.ml-section-header-centered` `.ml-section-muted` `.ml-section-shell` `.ml-stack` `.ml-stat` `.ml-stat-card` `.ml-stat-grid` `.ml-stat-list` `.ml-stat-meta` `.ml-stat-value` `.ml-text-primary` `.ml-value`
130
+ `.ml-actions` `.ml-brand` `.ml-brand-mark` `.ml-brand-name` `.ml-chart` `.ml-chart-bar` `.ml-chart-bars` `.ml-chart-heading` `.ml-check-list` `.ml-cluster` `.ml-definition-list` `.ml-display` `.ml-divider` `.ml-empty-state` `.ml-eyebrow` `.ml-filter-chip` `.ml-filter-group` `.ml-fine-print` `.ml-form` `.ml-form-message` `.ml-form-options` `.ml-grid` `.ml-heading` `.ml-icon-chip` `.ml-inline-form` `.ml-inline-form-field` `.ml-label` `.ml-lede` `.ml-link` `.ml-page-shell` `.ml-person` `.ml-person-copy` `.ml-positive` `.ml-price` `.ml-required-mark` `.ml-section` `.ml-section-description` `.ml-section-header` `.ml-section-header-centered` `.ml-section-muted` `.ml-section-shell` `.ml-stack` `.ml-stat` `.ml-stat-card` `.ml-stat-grid` `.ml-stat-list` `.ml-stat-meta` `.ml-stat-value` `.ml-text-primary` `.ml-value`
131
131
 
132
+ - `.ml-check-list` — A list of benefits, each after a check. Pricing tiers and feature rows share it.
132
133
  - `.ml-link` — A glyph inside a link flows with the text instead of breaking the line.
133
- - `.ml-page-shell` — A full page: header, main and footer stacked on the page background.
134
+ - `.ml-page-shell` — The navigation, main and footer are grid items; they may be narrower than their widest content (a table that scrolls), so the page never does.
135
+ - `.ml-section` — A section a link jumps to clears the sticky navigation bar.
134
136
 
135
137
  ## Elements and their attributes
136
138
 
@@ -166,6 +168,7 @@ correct. This table is read out of the stylesheet, so it is never stale.
166
168
  | `.ml-calendar-day` | `data-unreachable` | _presence only_ |
167
169
  | `.ml-card` | `data-interactive` | _presence only_ |
168
170
  | `.ml-card` | `data-variant` | `elevated`, `glass`, `specular` |
171
+ | `.ml-carousel` | `data-arrows` | _presence only_ |
169
172
  | `.ml-carousel` | `data-playing` | _presence only_ |
170
173
  | `.ml-carousel-arrow` | `data-side` | `next`, `previous` |
171
174
  | `.ml-carousel-dot` | `aria-current` | `true` |
@@ -1431,14 +1431,14 @@
1431
1431
  {
1432
1432
  "path": "empty-cart.svg",
1433
1433
  "role": "source",
1434
- "bytes": 4968,
1435
- "integrity": "sha256-D0zyZvimuFagUT0ChqyBNp2hsCjAZ4Pv7RW6cJ37gcE="
1434
+ "bytes": 4982,
1435
+ "integrity": "sha256-8m4Z0HWSI7KRjDc6MSHRrCI1HwbiyynBmoxgCyo2DDw="
1436
1436
  },
1437
1437
  {
1438
1438
  "path": "empty-cart.tsx",
1439
1439
  "role": "react",
1440
- "bytes": 5920,
1441
- "integrity": "sha256-fapGlGqTLVX54EYazXYKN+vxVbbYN9RP3t4qDLnN1/g="
1440
+ "bytes": 5934,
1441
+ "integrity": "sha256-CFip8M6D6RJdYVGIwQ6H3HwWek/dHTq9ON98SeHjS4Q="
1442
1442
  }
1443
1443
  ],
1444
1444
  "themeable": true,
@@ -1617,7 +1617,7 @@
1617
1617
  "id": "inventory",
1618
1618
  "kind": "2d",
1619
1619
  "title": "Inventory",
1620
- "summary": "Shelved parcels with labels, counted slots and an active stock marker.",
1620
+ "summary": "An open shelf of labeled parcels, one empty slot and a tag marking the stock that is ready.",
1621
1621
  "tags": [
1622
1622
  "inventory",
1623
1623
  "warehouse",
@@ -1627,14 +1627,14 @@
1627
1627
  {
1628
1628
  "path": "inventory.svg",
1629
1629
  "role": "source",
1630
- "bytes": 4558,
1631
- "integrity": "sha256-lpe+xybY6if62AE7jyrc531zeQuQiZWvB6bZ8LNSAuE="
1630
+ "bytes": 9461,
1631
+ "integrity": "sha256-PrHqQsxeEtVKhftidsFZpr2XMIWx2oMgKhsd0dGKXSQ="
1632
1632
  },
1633
1633
  {
1634
1634
  "path": "inventory.tsx",
1635
1635
  "role": "react",
1636
- "bytes": 5532,
1637
- "integrity": "sha256-si0HLYrwRJ07wZH2lNuvUhxhhNGFtihT8S21fClz4sY="
1636
+ "bytes": 10590,
1637
+ "integrity": "sha256-WH+stRnsQsNF8bWuVpZAoqkjthF3JNM/FEQ3aw2G6Lg="
1638
1638
  }
1639
1639
  ],
1640
1640
  "themeable": true,
@@ -1869,7 +1869,7 @@
1869
1869
  "id": "offline",
1870
1870
  "kind": "2d",
1871
1871
  "title": "Offline",
1872
- "summary": "A small wireless router and a disconnected cable. Connection paused, ready to reconnect.",
1872
+ "summary": "A wireless router that has lost its signal and a disconnected cable. Connection paused, ready to reconnect.",
1873
1873
  "tags": [
1874
1874
  "error",
1875
1875
  "network",
@@ -1879,14 +1879,14 @@
1879
1879
  {
1880
1880
  "path": "offline.svg",
1881
1881
  "role": "source",
1882
- "bytes": 4202,
1883
- "integrity": "sha256-2sWn+8fJD4xEyp/D+Po2wAIUJVufv9EGmu4cQYmFCRg="
1882
+ "bytes": 4560,
1883
+ "integrity": "sha256-q0ZZ4EKo8a+56sIAtcGyjni7yVhxyD6yMYwSlDaWqRQ="
1884
1884
  },
1885
1885
  {
1886
1886
  "path": "offline.tsx",
1887
1887
  "role": "react",
1888
- "bytes": 5132,
1889
- "integrity": "sha256-4fui9gRQW3U+pMsibh1vg8b3jmHvnpxQRXqmAiSNA04="
1888
+ "bytes": 5517,
1889
+ "integrity": "sha256-G1ys9dW4cJg6CjD3Gj1aJ2InQus4zYClR45jExmITSg="
1890
1890
  }
1891
1891
  ],
1892
1892
  "themeable": true,
@@ -2897,14 +2897,14 @@
2897
2897
  {
2898
2898
  "path": "measuring-tape.glb",
2899
2899
  "role": "source",
2900
- "bytes": 592628,
2901
- "integrity": "sha256-gjp8OVIjpEbmo0zeegc7p9W+gkYGeNqwETxuBfE43Js="
2900
+ "bytes": 445392,
2901
+ "integrity": "sha256-VsiwX1rsnRBGeE28vd1LuoqIZSF5OVqvDjy9fgwbLNk="
2902
2902
  },
2903
2903
  {
2904
2904
  "path": "measuring-tape-poster.webp",
2905
2905
  "role": "poster",
2906
- "bytes": 16086,
2907
- "integrity": "sha256-Ygzmwy/ttH5//dWsBUTsR+4XGQlD/YpodjI6y9caXuo="
2906
+ "bytes": 18308,
2907
+ "integrity": "sha256-Nmmtp3upafknGSg3V57I1GEBf+yMRCBVBmIsSGXKlks="
2908
2908
  }
2909
2909
  ],
2910
2910
  "themeable": true,
@@ -3209,14 +3209,14 @@
3209
3209
  {
3210
3210
  "path": "task-lamp.glb",
3211
3211
  "role": "source",
3212
- "bytes": 283168,
3213
- "integrity": "sha256-hAolZPXrmhkMW0DjUx/aB4iXTEBm3YFDnoTzOqsMtMc="
3212
+ "bytes": 283120,
3213
+ "integrity": "sha256-mQVMpISa78gjVjYSbzsY9IOzZjTQVwl2n/YrCCdVOf0="
3214
3214
  },
3215
3215
  {
3216
3216
  "path": "task-lamp-poster.webp",
3217
3217
  "role": "poster",
3218
- "bytes": 16676,
3219
- "integrity": "sha256-KczARj6DGDO6U9YrYZ5LLTKCHK922mbXLvJtcmeMEfQ="
3218
+ "bytes": 17958,
3219
+ "integrity": "sha256-IQot+k4DZEqTkOknca5ZxH4dqPjpE4xyeJWxGANl6yM="
3220
3220
  }
3221
3221
  ],
3222
3222
  "themeable": true,
@@ -114,6 +114,7 @@
114
114
  ]
115
115
  },
116
116
  "ml-carousel": {
117
+ "data-arrows": [],
117
118
  "data-playing": []
118
119
  },
119
120
  "ml-carousel-arrow": {
@@ -145,8 +145,39 @@
145
145
  gap: var(--ml-space-2);
146
146
  }
147
147
 
148
+ /* A list of benefits, each after a check. Pricing tiers and feature rows share it. */
149
+ .ml-check-list {
150
+ margin: 0;
151
+ padding: 0;
152
+ list-style: none;
153
+ display: grid;
154
+ gap: var(--ml-space-2);
155
+ }
156
+
157
+ .ml-check-list li {
158
+ display: flex;
159
+ align-items: flex-start;
160
+ gap: var(--ml-space-2);
161
+ font-size: var(--ml-type-base);
162
+ color: var(--ml-text-muted);
163
+ }
164
+
165
+ .ml-check-list li > svg {
166
+ flex: none;
167
+ margin-top: 0.2em;
168
+ color: var(--ml-success-text);
169
+ }
170
+
148
171
  .ml-section {
149
172
  padding-block: clamp(3.5rem,8vw,6.5rem);
173
+ /* A section is a grid or flex item in a page shell; without this, a wide
174
+ table inside it widens the whole page instead of scrolling in place. */
175
+ min-width: 0;
176
+ }
177
+
178
+ /* A section a link jumps to clears the sticky navigation bar. */
179
+ .ml-section[id] {
180
+ scroll-margin-block-start: calc(var(--ml-control-md) + var(--ml-space-6));
150
181
  }
151
182
 
152
183
  .ml-section-shell {
@@ -551,6 +582,12 @@
551
582
  color: var(--ml-text);
552
583
  }
553
584
 
585
+ /* The navigation, main and footer are grid items; they may be narrower than
586
+ their widest content (a table that scrolls), so the page never does. */
587
+ .ml-page-shell > * {
588
+ min-width: 0;
589
+ }
590
+
554
591
  /* components/accordion */
555
592
  .ml-accordion {
556
593
  width: 100%;
@@ -1409,15 +1446,41 @@
1409
1446
 
1410
1447
  .ml-breadcrumb-item {
1411
1448
  display: inline-flex;
1449
+ min-width: 0;
1412
1450
  align-items: center;
1413
1451
  gap: var(--ml-space-1-5);
1414
1452
  }
1415
1453
 
1454
+ /* Links, in-app buttons and the current page share one shape; a long title shortens instead of breaking the bar. */
1455
+ .ml-breadcrumb-link,
1456
+ .ml-breadcrumb-page {
1457
+ display: inline-flex;
1458
+ align-items: center;
1459
+ gap: var(--ml-space-1);
1460
+ min-width: 0;
1461
+ overflow: hidden;
1462
+ text-overflow: ellipsis;
1463
+ white-space: nowrap;
1464
+ }
1465
+
1416
1466
  .ml-breadcrumb-link {
1417
1467
  color: var(--ml-text-muted);
1418
1468
  text-decoration: none;
1419
1469
  }
1420
1470
 
1471
+ button.ml-breadcrumb-link {
1472
+ padding: 0;
1473
+ border: 0;
1474
+ border-radius: var(--ml-radius-xs);
1475
+ background: none;
1476
+ font: inherit;
1477
+ cursor: pointer;
1478
+ }
1479
+
1480
+ .ml-breadcrumb-icon {
1481
+ flex: none;
1482
+ }
1483
+
1421
1484
  .ml-breadcrumb-link:hover {
1422
1485
  color: var(--ml-text);
1423
1486
  }
@@ -1933,7 +1996,24 @@
1933
1996
  height: 100%;
1934
1997
  }
1935
1998
 
1936
- /* Arrows float over the edges and come forward when the reader is near. */
1999
+ /* With a pointer that hovers, the arrows sit in a gutter beside the slides,
2000
+ never over them. On touch the reader swipes, the arrows stay hidden until
2001
+ focused, and the slides keep the full width. */
2002
+ @media (hover: hover) and (pointer: fine) {
2003
+ .ml-carousel[data-arrows] .ml-carousel-viewport {
2004
+ padding-inline: calc(var(--ml-control-md) + var(--ml-space-3));
2005
+ }
2006
+
2007
+ .ml-carousel[data-arrows] .ml-carousel-arrow[data-side="previous"] {
2008
+ left: 0;
2009
+ }
2010
+
2011
+ .ml-carousel[data-arrows] .ml-carousel-arrow[data-side="next"] {
2012
+ right: 0;
2013
+ }
2014
+ }
2015
+
2016
+ /* The arrows come forward when the reader is near. */
1937
2017
  .ml-carousel-arrow {
1938
2018
  position: absolute;
1939
2019
  top: 50%;
@@ -2072,6 +2152,7 @@
2072
2152
  grid-template-columns: auto 1fr;
2073
2153
  gap: var(--ml-space-1-5) var(--ml-space-3);
2074
2154
  align-items: start;
2155
+ align-content: start;
2075
2156
  }
2076
2157
 
2077
2158
  .ml-checkbox-control {
@@ -3061,6 +3142,7 @@
3061
3142
  .ml-dropzone-root {
3062
3143
  display: grid;
3063
3144
  gap: var(--ml-space-2);
3145
+ align-content: start;
3064
3146
  }
3065
3147
 
3066
3148
  .ml-dropzone {
@@ -3299,6 +3381,8 @@
3299
3381
  grid-template-columns: minmax(0, 1fr);
3300
3382
  gap: var(--ml-space-1-5);
3301
3383
  width: 100%;
3384
+ /* In a form row taller than itself, a field keeps its own height instead of stretching its label and control apart. */
3385
+ align-content: start;
3302
3386
  }
3303
3387
 
3304
3388
  .ml-input,
@@ -3449,6 +3533,13 @@
3449
3533
  pointer-events: none;
3450
3534
  }
3451
3535
 
3536
+ /* A text affix ("https://", a domain, a unit) reads at the size of what is typed beside it. */
3537
+ .ml-input-leading,
3538
+ .ml-input-trailing {
3539
+ font-size: var(--ml-type-base);
3540
+ line-height: var(--ml-leading-snug);
3541
+ }
3542
+
3452
3543
  /* components/kbd */
3453
3544
  .ml-kbd {
3454
3545
  display: inline-grid;
@@ -3637,9 +3728,12 @@
3637
3728
  border-inline-start: var(--ml-border-width) solid var(--ml-border-subtle);
3638
3729
  }
3639
3730
 
3731
+ /* Square at any height: where touch sizing makes the field taller, the steps
3732
+ grow with it instead of stretching into tall slivers. */
3640
3733
  .ml-number-input-step {
3641
3734
  display: inline-grid;
3642
- width: var(--ml-control-md);
3735
+ min-width: var(--ml-control-md);
3736
+ aspect-ratio: 1;
3643
3737
  place-items: center;
3644
3738
  padding: 0;
3645
3739
  border: 0;
@@ -3937,6 +4031,7 @@
3937
4031
  display: grid;
3938
4032
  gap: var(--ml-space-2);
3939
4033
  width: 100%;
4034
+ align-content: start;
3940
4035
  }
3941
4036
 
3942
4037
  .ml-progress-root[data-tone="info"] {
@@ -4284,6 +4379,7 @@
4284
4379
  display: grid;
4285
4380
  gap: var(--ml-space-3);
4286
4381
  width: 100%;
4382
+ align-content: start;
4287
4383
  }
4288
4384
 
4289
4385
  .ml-radio-group[data-orientation="horizontal"] .ml-radio-group-items {
@@ -4305,6 +4401,7 @@
4305
4401
  .ml-radio-group-items {
4306
4402
  display: grid;
4307
4403
  gap: var(--ml-space-2-5);
4404
+ align-content: start;
4308
4405
  }
4309
4406
 
4310
4407
  /* components/rating */
@@ -4486,6 +4583,8 @@
4486
4583
  position: relative;
4487
4584
  display: grid;
4488
4585
  grid-template-columns: minmax(0, 1fr);
4586
+ /* In a form row taller than itself, the trigger keeps a field's height instead of stretching. */
4587
+ align-content: start;
4489
4588
  gap: var(--ml-space-1-5);
4490
4589
  width: 100%;
4491
4590
  min-width: 0;
@@ -4510,6 +4609,10 @@
4510
4609
  border: var(--ml-border-width) solid var(--ml-border);
4511
4610
  border-radius: var(--ml-radius-md);
4512
4611
  box-shadow: var(--ml-shadow-xs);
4612
+ /* The same type as a text field, so a select and an input sit level in a row. */
4613
+ font-family: var(--ml-font-sans);
4614
+ font-size: var(--ml-type-base);
4615
+ line-height: var(--ml-leading-snug);
4513
4616
  cursor: pointer;
4514
4617
  text-align: start;
4515
4618
  transition: border-color var(--ml-duration-fast),box-shadow var(--ml-duration-fast);
@@ -4991,6 +5094,7 @@
4991
5094
  display: grid;
4992
5095
  gap: var(--ml-space-2-5);
4993
5096
  width: 100%;
5097
+ align-content: start;
4994
5098
  }
4995
5099
 
4996
5100
  .ml-slider-header {
@@ -5339,6 +5443,9 @@ button.ml-stepper-target:focus-visible {
5339
5443
 
5340
5444
  /* components/table */
5341
5445
  .ml-table-container {
5446
+ /* The containing block for anything positioned inside, such as visually
5447
+ hidden cell text, so it scrolls with the table instead of widening the page. */
5448
+ position: relative;
5342
5449
  width: 100%;
5343
5450
  overflow-x: auto;
5344
5451
  border: var(--ml-border-width) solid var(--ml-border-subtle);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mlola-ui/engine",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Framework-free CSS, spring easings, and the machine-readable contract for Mlola UI",
5
5
  "type": "module",
6
6
  "sideEffects": [