@0001-labs/design-system-1 0.3.0-alpha.28 → 0.3.1
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/DS1/0-face/button-label.ts +28 -0
- package/DS1/0-face/calendar.ts +6 -4
- package/DS1/0-face/carousel.ts +70 -0
- package/DS1/0-face/constraint-panel.ts +443 -0
- package/DS1/0-face/constraint-site.ts +201 -0
- package/DS1/0-face/constraints.ts +308 -0
- package/DS1/0-face/copy-text.ts +1 -1
- package/DS1/0-face/cut-fade.ts +312 -0
- package/DS1/0-face/define.ts +30 -2
- package/DS1/0-face/face-correction.ts +96 -0
- package/DS1/0-face/failures.ts +32 -0
- package/DS1/0-face/fault-lines.ts +159 -0
- package/DS1/0-face/feedback-overlays.ts +5 -3
- package/DS1/0-face/feedback.ts +3 -0
- package/DS1/0-face/focus-vision.swift +31 -0
- package/DS1/0-face/focus.ts +181 -0
- package/DS1/0-face/google-face-metrics.json +102 -0
- package/DS1/0-face/grid.ts +61 -4
- package/DS1/0-face/i18n.ts +36 -18
- package/DS1/0-face/layout-inspector.ts +124 -98
- package/DS1/0-face/preference-options.ts +4 -0
- package/DS1/0-face/scaling.ts +21 -3
- package/DS1/0-face/shape.ts +43 -0
- package/DS1/0-face/text-contrast.ts +164 -0
- package/DS1/0-face/theme-bootstrap.js +43 -0
- package/DS1/0-face/toast-queue.ts +7 -1
- package/DS1/0-face/translations/da.json +10 -1
- package/DS1/0-face/translations/de.json +10 -1
- package/DS1/0-face/translations/en.json +10 -1
- package/DS1/0-face/translations/es.json +10 -1
- package/DS1/0-face/translations/fi.json +10 -1
- package/DS1/0-face/translations/fr.json +10 -1
- package/DS1/0-face/translations/is.json +10 -1
- package/DS1/0-face/translations/it.json +10 -1
- package/DS1/0-face/translations/ja.json +10 -1
- package/DS1/0-face/translations/ko.json +10 -1
- package/DS1/0-face/translations/nb.json +10 -1
- package/DS1/0-face/translations/pt-BR.json +10 -1
- package/DS1/0-face/translations/pt.json +10 -1
- package/DS1/0-face/translations/sv.json +10 -1
- package/DS1/0-face/translations/zh.json +10 -1
- package/DS1/0-face/word-wrap.ts +113 -0
- package/DS1/1-root/card.css +47 -20
- package/DS1/1-root/carousel.css +7 -0
- package/DS1/1-root/cjk.css +1 -1
- package/DS1/1-root/component-tokens.css +3 -2
- package/DS1/1-root/context.css +44 -6
- package/DS1/1-root/controls.css +99 -8
- package/DS1/1-root/document.css +9 -1
- package/DS1/1-root/empty.css +46 -5
- package/DS1/1-root/figures.css +50 -3
- package/DS1/1-root/fonts.css +1 -1
- package/DS1/1-root/footer.css +147 -16
- package/DS1/1-root/foundation.ts +60 -0
- package/DS1/1-root/guide.css +35 -0
- package/DS1/1-root/header.css +30 -9
- package/DS1/1-root/material.css +67 -0
- package/DS1/1-root/notice.css +10 -2
- package/DS1/1-root/one.css +15 -7
- package/DS1/1-root/progress.css +9 -1
- package/DS1/1-root/row.css +68 -2
- package/DS1/1-root/table.css +47 -4
- package/DS1/1-root/text.css +26 -0
- package/DS1/2-core/button-split.ts +10 -5
- package/DS1/2-core/chart/chart.css +71 -2
- package/DS1/2-core/chart/grid-chart.ts +2 -1
- package/DS1/2-core/ds-activity.ts +32 -0
- package/DS1/2-core/ds-app-chrome.ts +1 -0
- package/DS1/2-core/ds-avatar.ts +75 -7
- package/DS1/2-core/ds-badge.ts +8 -1
- package/DS1/2-core/ds-button.ts +7 -1
- package/DS1/2-core/ds-chart.ts +184 -49
- package/DS1/2-core/ds-cycle.ts +27 -186
- package/DS1/2-core/ds-device-bezel.ts +1 -0
- package/DS1/2-core/ds-empty.ts +6 -4
- package/DS1/2-core/ds-input.ts +23 -3
- package/DS1/2-core/ds-message.ts +22 -0
- package/DS1/2-core/ds-number.ts +349 -0
- package/DS1/2-core/ds-progress.ts +3 -0
- package/DS1/2-core/ds-radio.ts +3 -0
- package/DS1/2-core/ds-stat.ts +3 -0
- package/DS1/2-core/ds-switch.ts +5 -1
- package/DS1/2-core/ds-tag.ts +9 -2
- package/DS1/2-core/ds-text.ts +7 -0
- package/DS1/2-core/ds-token.ts +3 -0
- package/DS1/2-core/ds-tooltip.ts +17 -2
- package/DS1/2-core/ds-window.ts +1 -0
- package/DS1/2-core/generated/ds-icon-map.ts +47 -5
- package/DS1/2-core/generated/icons-extra.ts +24 -3
- package/DS1/2-core/generated/icons-immediate.ts +3 -3
- package/DS1/2-core/number-expression.ts +64 -0
- package/DS1/2-core/styles/ds-activity.css +16 -0
- package/DS1/2-core/styles/ds-badge.css +4 -1
- package/DS1/2-core/styles/ds-button-host.css +47 -13
- package/DS1/2-core/styles/ds-button-split.css +8 -0
- package/DS1/2-core/styles/ds-button.css +94 -20
- package/DS1/2-core/styles/ds-card.css +6 -0
- package/DS1/2-core/styles/ds-checkbox.css +20 -8
- package/DS1/2-core/styles/ds-image.css +2 -1
- package/DS1/2-core/styles/ds-input.css +37 -4
- package/DS1/2-core/styles/ds-number.css +127 -0
- package/DS1/2-core/styles/ds-radio.css +4 -1
- package/DS1/2-core/styles/ds-switch.css +34 -4
- package/DS1/2-core/styles/ds-tag.css +34 -6
- package/DS1/2-core/styles/ds-text.css +13 -4
- package/DS1/2-core/styles/ds-token.css +4 -1
- package/DS1/2-core/styles/ds-tooltip.css +13 -7
- package/DS1/3-unit/calendar-base.ts +5 -2
- package/DS1/3-unit/context-trigger.ts +29 -2
- package/DS1/3-unit/ds-calendar.ts +711 -37
- package/DS1/3-unit/ds-carousel.ts +13 -1
- package/DS1/3-unit/ds-context.ts +40 -2
- package/DS1/3-unit/ds-form.ts +47 -11
- package/DS1/3-unit/ds-list.ts +31 -3
- package/DS1/3-unit/ds-matrix.ts +3 -0
- package/DS1/3-unit/ds-menu.ts +9 -5
- package/DS1/3-unit/ds-row.ts +17 -2
- package/DS1/3-unit/ds-select.ts +1 -1
- package/DS1/3-unit/ds-sidebar.ts +18 -3
- package/DS1/3-unit/ds-table-of-contents.ts +166 -0
- package/DS1/3-unit/ds-table.ts +2 -1
- package/DS1/3-unit/ds-tabs.ts +40 -2
- package/DS1/3-unit/styles/ds-calendar.css +356 -42
- package/DS1/3-unit/styles/ds-context.css +38 -0
- package/DS1/3-unit/styles/ds-list.css +26 -1
- package/DS1/3-unit/styles/ds-matrix.css +4 -1
- package/DS1/3-unit/styles/ds-row.css +39 -0
- package/DS1/3-unit/styles/ds-select.css +22 -12
- package/DS1/3-unit/styles/ds-sidebar.css +16 -2
- package/DS1/3-unit/styles/ds-table-of-contents.css +40 -0
- package/DS1/3-unit/styles/ds-tabs.css +95 -0
- package/DS1/4-page/ds-container.ts +2 -1
- package/DS1/4-page/ds-document.ts +3 -0
- package/DS1/4-page/ds-footer.ts +93 -18
- package/DS1/4-page/ds-header.ts +5 -1
- package/DS1/4-page/ds-overlay.ts +8 -3
- package/DS1/4-page/ds-page.ts +22 -1
- package/DS1/4-page/email.ts +7 -4
- package/DS1/4-page/styles/ds-container.css +0 -1
- package/DS1/4-page/styles/ds-overlay.css +7 -0
- package/DS1/4-page/styles/ds-page.css +10 -0
- package/DS1/5-visual-kit/app-chrome.ts +129 -0
- package/DS1/5-visual-kit/bezels.ts +394 -0
- package/DS1/5-visual-kit/browser-icons.LICENSE +53 -0
- package/DS1/5-visual-kit/browser-icons.ts +47 -0
- package/DS1/5-visual-kit/browser-styles.ts +53 -0
- package/DS1/5-visual-kit/device-bezel.ts +55 -0
- package/DS1/5-visual-kit/instagram-frame.ts +15 -0
- package/DS1/5-visual-kit/instagram.ts +41 -0
- package/DS1/5-visual-kit/mobile-chrome.ts +25 -0
- package/DS1/5-visual-kit/native-icon-paths.ts +145 -0
- package/DS1/5-visual-kit/window.ts +22 -0
- package/DS1/components.ts +1 -0
- package/DS1/index.ts +14 -1
- package/DS1/react/choice.ts +4 -2
- package/DS1/react/context.ts +11 -6
- package/DS1/react/empty.ts +2 -2
- package/DS1/react/footer.ts +5 -5
- package/DS1/react/header.ts +1 -1
- package/DS1/react/message.ts +4 -2
- package/DS1/react/number.ts +53 -0
- package/DS1/react/sidebar.ts +4 -2
- package/DS1/react/table-of-contents.ts +28 -0
- package/DS1/x-flag/LICENSE.md +26 -0
- package/DS1/x-flag/ac.svg +1 -0
- package/DS1/x-flag/ad.svg +1 -0
- package/DS1/x-flag/ae.svg +1 -0
- package/DS1/x-flag/af.svg +1 -0
- package/DS1/x-flag/ag.svg +1 -0
- package/DS1/x-flag/ai.svg +1 -0
- package/DS1/x-flag/al.svg +1 -0
- package/DS1/x-flag/am.svg +1 -0
- package/DS1/x-flag/ao.svg +1 -0
- package/DS1/x-flag/aq.svg +1 -0
- package/DS1/x-flag/ar.svg +1 -0
- package/DS1/x-flag/as.svg +1 -0
- package/DS1/x-flag/at.svg +1 -0
- package/DS1/x-flag/au.svg +1 -0
- package/DS1/x-flag/aw.svg +1 -0
- package/DS1/x-flag/ax.svg +1 -0
- package/DS1/x-flag/az.svg +1 -0
- package/DS1/x-flag/ba.svg +1 -0
- package/DS1/x-flag/bb.svg +1 -0
- package/DS1/x-flag/bd.svg +1 -0
- package/DS1/x-flag/be.svg +1 -0
- package/DS1/x-flag/bf.svg +1 -0
- package/DS1/x-flag/bg.svg +1 -0
- package/DS1/x-flag/bh.svg +1 -0
- package/DS1/x-flag/bi.svg +1 -0
- package/DS1/x-flag/bj.svg +1 -0
- package/DS1/x-flag/bl.svg +1 -0
- package/DS1/x-flag/bm.svg +1 -0
- package/DS1/x-flag/bn.svg +1 -0
- package/DS1/x-flag/bo.svg +1 -0
- package/DS1/x-flag/bq-bo.svg +1 -0
- package/DS1/x-flag/bq-sa.svg +1 -0
- package/DS1/x-flag/bq-se.svg +1 -0
- package/DS1/x-flag/bq.svg +1 -0
- package/DS1/x-flag/br.svg +1 -0
- package/DS1/x-flag/bs.svg +1 -0
- package/DS1/x-flag/bt.svg +1 -0
- package/DS1/x-flag/bv.svg +1 -0
- package/DS1/x-flag/bw.svg +1 -0
- package/DS1/x-flag/by.svg +1 -0
- package/DS1/x-flag/bz.svg +1 -0
- package/DS1/x-flag/ca.svg +1 -0
- package/DS1/x-flag/cc.svg +1 -0
- package/DS1/x-flag/cd.svg +1 -0
- package/DS1/x-flag/cf.svg +1 -0
- package/DS1/x-flag/cg.svg +1 -0
- package/DS1/x-flag/ch.svg +1 -0
- package/DS1/x-flag/ci.svg +1 -0
- package/DS1/x-flag/ck.svg +1 -0
- package/DS1/x-flag/cl.svg +1 -0
- package/DS1/x-flag/cm.svg +1 -0
- package/DS1/x-flag/cn.svg +1 -0
- package/DS1/x-flag/co.svg +1 -0
- package/DS1/x-flag/cr.svg +1 -0
- package/DS1/x-flag/cu.svg +1 -0
- package/DS1/x-flag/cv.svg +1 -0
- package/DS1/x-flag/cw.svg +1 -0
- package/DS1/x-flag/cx.svg +1 -0
- package/DS1/x-flag/cy.svg +1 -0
- package/DS1/x-flag/cz.svg +1 -0
- package/DS1/x-flag/de.svg +1 -0
- package/DS1/x-flag/dj.svg +1 -0
- package/DS1/x-flag/dk.svg +1 -0
- package/DS1/x-flag/dm.svg +1 -0
- package/DS1/x-flag/do.svg +1 -0
- package/DS1/x-flag/dz.svg +1 -0
- package/DS1/x-flag/ec.svg +1 -0
- package/DS1/x-flag/ee.svg +1 -0
- package/DS1/x-flag/eg.svg +1 -0
- package/DS1/x-flag/eh.svg +1 -0
- package/DS1/x-flag/er.svg +1 -0
- package/DS1/x-flag/es-ct.svg +1 -0
- package/DS1/x-flag/es.svg +1 -0
- package/DS1/x-flag/et.svg +1 -0
- package/DS1/x-flag/eu.svg +1 -0
- package/DS1/x-flag/fi.svg +1 -0
- package/DS1/x-flag/fj.svg +1 -0
- package/DS1/x-flag/fk.svg +1 -0
- package/DS1/x-flag/fm.svg +1 -0
- package/DS1/x-flag/fo.svg +1 -0
- package/DS1/x-flag/fr.svg +1 -0
- package/DS1/x-flag/ga.svg +1 -0
- package/DS1/x-flag/gb-eng.svg +1 -0
- package/DS1/x-flag/gb-nir.svg +1 -0
- package/DS1/x-flag/gb-sct.svg +1 -0
- package/DS1/x-flag/gb-wls.svg +1 -0
- package/DS1/x-flag/gb.svg +1 -0
- package/DS1/x-flag/gd.svg +1 -0
- package/DS1/x-flag/ge.svg +1 -0
- package/DS1/x-flag/gf.svg +1 -0
- package/DS1/x-flag/gg.svg +1 -0
- package/DS1/x-flag/gh.svg +1 -0
- package/DS1/x-flag/gi.svg +1 -0
- package/DS1/x-flag/gl.svg +1 -0
- package/DS1/x-flag/gm.svg +1 -0
- package/DS1/x-flag/gn.svg +1 -0
- package/DS1/x-flag/gp.svg +1 -0
- package/DS1/x-flag/gq.svg +1 -0
- package/DS1/x-flag/gr.svg +1 -0
- package/DS1/x-flag/gs.svg +1 -0
- package/DS1/x-flag/gt.svg +1 -0
- package/DS1/x-flag/gu.svg +1 -0
- package/DS1/x-flag/gw.svg +1 -0
- package/DS1/x-flag/gy.svg +1 -0
- package/DS1/x-flag/hk.svg +1 -0
- package/DS1/x-flag/hm.svg +1 -0
- package/DS1/x-flag/hn.svg +1 -0
- package/DS1/x-flag/hr.svg +1 -0
- package/DS1/x-flag/ht.svg +1 -0
- package/DS1/x-flag/hu.svg +1 -0
- package/DS1/x-flag/ic.svg +1 -0
- package/DS1/x-flag/id.svg +1 -0
- package/DS1/x-flag/ie.svg +1 -0
- package/DS1/x-flag/il.svg +1 -0
- package/DS1/x-flag/im.svg +1 -0
- package/DS1/x-flag/in.svg +1 -0
- package/DS1/x-flag/io.svg +1 -0
- package/DS1/x-flag/iq.svg +1 -0
- package/DS1/x-flag/ir.svg +1 -0
- package/DS1/x-flag/is.svg +1 -0
- package/DS1/x-flag/it.svg +1 -0
- package/DS1/x-flag/je.svg +1 -0
- package/DS1/x-flag/jm.svg +1 -0
- package/DS1/x-flag/jo.svg +1 -0
- package/DS1/x-flag/jp.svg +1 -0
- package/DS1/x-flag/ke.svg +1 -0
- package/DS1/x-flag/kg.svg +1 -0
- package/DS1/x-flag/kh.svg +1 -0
- package/DS1/x-flag/ki.svg +1 -0
- package/DS1/x-flag/km.svg +1 -0
- package/DS1/x-flag/kn.svg +1 -0
- package/DS1/x-flag/kp.svg +1 -0
- package/DS1/x-flag/kr.svg +1 -0
- package/DS1/x-flag/kw.svg +1 -0
- package/DS1/x-flag/ky.svg +1 -0
- package/DS1/x-flag/kz.svg +1 -0
- package/DS1/x-flag/la.svg +1 -0
- package/DS1/x-flag/lb.svg +1 -0
- package/DS1/x-flag/lc.svg +1 -0
- package/DS1/x-flag/li.svg +1 -0
- package/DS1/x-flag/lk.svg +1 -0
- package/DS1/x-flag/lr.svg +1 -0
- package/DS1/x-flag/ls.svg +1 -0
- package/DS1/x-flag/lt.svg +1 -0
- package/DS1/x-flag/lu.svg +1 -0
- package/DS1/x-flag/lv.svg +1 -0
- package/DS1/x-flag/ly.svg +1 -0
- package/DS1/x-flag/ma.svg +1 -0
- package/DS1/x-flag/mc.svg +1 -0
- package/DS1/x-flag/md.svg +1 -0
- package/DS1/x-flag/me.svg +1 -0
- package/DS1/x-flag/mf.svg +1 -0
- package/DS1/x-flag/mg.svg +1 -0
- package/DS1/x-flag/mh.svg +1 -0
- package/DS1/x-flag/mk.svg +1 -0
- package/DS1/x-flag/ml.svg +1 -0
- package/DS1/x-flag/mm.svg +1 -0
- package/DS1/x-flag/mn.svg +1 -0
- package/DS1/x-flag/mo.svg +1 -0
- package/DS1/x-flag/mp.svg +1 -0
- package/DS1/x-flag/mq.svg +1 -0
- package/DS1/x-flag/mr.svg +1 -0
- package/DS1/x-flag/ms.svg +1 -0
- package/DS1/x-flag/mt.svg +1 -0
- package/DS1/x-flag/mu.svg +1 -0
- package/DS1/x-flag/mv.svg +1 -0
- package/DS1/x-flag/mw.svg +1 -0
- package/DS1/x-flag/mx.svg +1 -0
- package/DS1/x-flag/my.svg +1 -0
- package/DS1/x-flag/mz.svg +1 -0
- package/DS1/x-flag/na.svg +1 -0
- package/DS1/x-flag/nc.svg +1 -0
- package/DS1/x-flag/ne.svg +1 -0
- package/DS1/x-flag/nf.svg +1 -0
- package/DS1/x-flag/ng.svg +1 -0
- package/DS1/x-flag/ni.svg +1 -0
- package/DS1/x-flag/nl.svg +1 -0
- package/DS1/x-flag/no.svg +1 -0
- package/DS1/x-flag/np.svg +1 -0
- package/DS1/x-flag/nr.svg +1 -0
- package/DS1/x-flag/nu.svg +1 -0
- package/DS1/x-flag/nz.svg +1 -0
- package/DS1/x-flag/om.svg +1 -0
- package/DS1/x-flag/pa.svg +1 -0
- package/DS1/x-flag/pe.svg +1 -0
- package/DS1/x-flag/pf.svg +1 -0
- package/DS1/x-flag/pg.svg +1 -0
- package/DS1/x-flag/ph.svg +1 -0
- package/DS1/x-flag/pk.svg +1 -0
- package/DS1/x-flag/pl.svg +1 -0
- package/DS1/x-flag/pm.svg +1 -0
- package/DS1/x-flag/pn.svg +1 -0
- package/DS1/x-flag/pr.svg +1 -0
- package/DS1/x-flag/ps.svg +1 -0
- package/DS1/x-flag/pt.svg +1 -0
- package/DS1/x-flag/pw.svg +1 -0
- package/DS1/x-flag/py.svg +1 -0
- package/DS1/x-flag/qa.svg +1 -0
- package/DS1/x-flag/re.svg +1 -0
- package/DS1/x-flag/ro.svg +1 -0
- package/DS1/x-flag/rs.svg +1 -0
- package/DS1/x-flag/ru.svg +1 -0
- package/DS1/x-flag/rw.svg +1 -0
- package/DS1/x-flag/sa.svg +1 -0
- package/DS1/x-flag/sb.svg +1 -0
- package/DS1/x-flag/sc.svg +1 -0
- package/DS1/x-flag/sd.svg +1 -0
- package/DS1/x-flag/se.svg +1 -0
- package/DS1/x-flag/sg.svg +1 -0
- package/DS1/x-flag/sh.svg +1 -0
- package/DS1/x-flag/si.svg +1 -0
- package/DS1/x-flag/sj.svg +1 -0
- package/DS1/x-flag/sk.svg +1 -0
- package/DS1/x-flag/sl.svg +1 -0
- package/DS1/x-flag/sm.svg +1 -0
- package/DS1/x-flag/sn.svg +1 -0
- package/DS1/x-flag/so.svg +1 -0
- package/DS1/x-flag/sr.svg +1 -0
- package/DS1/x-flag/ss.svg +1 -0
- package/DS1/x-flag/st.svg +1 -0
- package/DS1/x-flag/sv.svg +1 -0
- package/DS1/x-flag/sx.svg +1 -0
- package/DS1/x-flag/sy.svg +1 -0
- package/DS1/x-flag/sz.svg +1 -0
- package/DS1/x-flag/ta.svg +1 -0
- package/DS1/x-flag/tc.svg +1 -0
- package/DS1/x-flag/td.svg +1 -0
- package/DS1/x-flag/tf.svg +1 -0
- package/DS1/x-flag/tg.svg +1 -0
- package/DS1/x-flag/th.svg +1 -0
- package/DS1/x-flag/tj.svg +1 -0
- package/DS1/x-flag/tk.svg +1 -0
- package/DS1/x-flag/tl.svg +1 -0
- package/DS1/x-flag/tm.svg +1 -0
- package/DS1/x-flag/tn.svg +1 -0
- package/DS1/x-flag/to.svg +1 -0
- package/DS1/x-flag/tr.svg +1 -0
- package/DS1/x-flag/tt.svg +1 -0
- package/DS1/x-flag/tv.svg +1 -0
- package/DS1/x-flag/tw.svg +1 -0
- package/DS1/x-flag/tz.svg +1 -0
- package/DS1/x-flag/ua.svg +1 -0
- package/DS1/x-flag/ug.svg +1 -0
- package/DS1/x-flag/um.svg +1 -0
- package/DS1/x-flag/us.svg +1 -0
- package/DS1/x-flag/uy.svg +1 -0
- package/DS1/x-flag/uz.svg +1 -0
- package/DS1/x-flag/va.svg +1 -0
- package/DS1/x-flag/vc.svg +1 -0
- package/DS1/x-flag/ve.svg +1 -0
- package/DS1/x-flag/vg.svg +1 -0
- package/DS1/x-flag/vi.svg +1 -0
- package/DS1/x-flag/vn.svg +1 -0
- package/DS1/x-flag/vu.svg +1 -0
- package/DS1/x-flag/wf.svg +1 -0
- package/DS1/x-flag/ws.svg +1 -0
- package/DS1/x-flag/xk.svg +1 -0
- package/DS1/x-flag/ye.svg +1 -0
- package/DS1/x-flag/yt.svg +1 -0
- package/DS1/x-flag/za.svg +1 -0
- package/DS1/x-flag/zm.svg +1 -0
- package/DS1/x-flag/zw.svg +1 -0
- package/DS1/x-icon/android.svg +9 -0
- package/DS1/x-icon/arrange-check.svg +1 -1
- package/DS1/x-icon/arrange-page.svg +1 -1
- package/DS1/x-icon/chrome.svg +7 -0
- package/DS1/x-icon/edge-brand.svg +6 -0
- package/DS1/x-icon/firefox.svg +4 -0
- package/DS1/x-icon/health.svg +3 -0
- package/DS1/x-icon/left.svg +2 -3
- package/DS1/x-icon/linux.svg +1 -0
- package/DS1/x-icon/material.svg +1 -0
- package/DS1/x-icon/milestone-planned.svg +3 -0
- package/DS1/x-icon/milestone.svg +3 -0
- package/DS1/x-icon/more.svg +1 -5
- package/DS1/x-icon/network.svg +3 -0
- package/DS1/x-icon/opera.svg +4 -0
- package/DS1/x-icon/prediction.svg +3 -0
- package/DS1/x-icon/priority-high.svg +3 -0
- package/DS1/x-icon/priority-low.svg +3 -0
- package/DS1/x-icon/priority-medium.svg +3 -0
- package/DS1/x-icon/project.svg +3 -0
- package/DS1/x-icon/redo.svg +2 -2
- package/DS1/x-icon/repeat-small.svg +3 -0
- package/DS1/x-icon/safari.svg +4 -0
- package/DS1/x-icon/scaling.svg +3 -0
- package/DS1/x-icon/tabs.svg +4 -0
- package/DS1/x-icon/windows.svg +5 -0
- package/README.md +3 -3
- package/dist/0-face/button-label.d.ts +5 -0
- package/dist/0-face/button-label.d.ts.map +1 -0
- package/dist/0-face/button-label.js +31 -0
- package/dist/0-face/calendar.d.ts +1 -1
- package/dist/0-face/calendar.d.ts.map +1 -1
- package/dist/0-face/calendar.js +6 -3
- package/dist/0-face/carousel.d.ts +9 -0
- package/dist/0-face/carousel.d.ts.map +1 -1
- package/dist/0-face/carousel.js +80 -0
- package/dist/0-face/constraint-panel.d.ts +43 -0
- package/dist/0-face/constraint-panel.d.ts.map +1 -0
- package/dist/0-face/constraint-panel.js +451 -0
- package/dist/0-face/constraint-site.d.ts +73 -0
- package/dist/0-face/constraint-site.d.ts.map +1 -0
- package/dist/0-face/constraint-site.js +186 -0
- package/dist/0-face/constraints.d.ts +47 -0
- package/dist/0-face/constraints.d.ts.map +1 -0
- package/dist/0-face/constraints.js +274 -0
- package/dist/0-face/copy-text.js +1 -1
- package/dist/0-face/cut-fade.d.ts +112 -0
- package/dist/0-face/cut-fade.d.ts.map +1 -0
- package/dist/0-face/cut-fade.js +274 -0
- package/dist/0-face/define.d.ts.map +1 -1
- package/dist/0-face/define.js +24 -3
- package/dist/0-face/face-correction.d.ts +51 -0
- package/dist/0-face/face-correction.d.ts.map +1 -0
- package/dist/0-face/face-correction.js +80 -0
- package/dist/0-face/failures.d.ts +16 -0
- package/dist/0-face/failures.d.ts.map +1 -0
- package/dist/0-face/failures.js +21 -0
- package/dist/0-face/fault-lines.d.ts +20 -0
- package/dist/0-face/fault-lines.d.ts.map +1 -0
- package/dist/0-face/fault-lines.js +172 -0
- package/dist/0-face/feedback-overlays.d.ts.map +1 -1
- package/dist/0-face/feedback-overlays.js +5 -3
- package/dist/0-face/feedback.d.ts +2 -0
- package/dist/0-face/feedback.d.ts.map +1 -1
- package/dist/0-face/feedback.js +1 -0
- package/dist/0-face/focus.d.ts +71 -0
- package/dist/0-face/focus.d.ts.map +1 -0
- package/dist/0-face/focus.js +196 -0
- package/dist/0-face/grid.d.ts +11 -1
- package/dist/0-face/grid.d.ts.map +1 -1
- package/dist/0-face/grid.js +90 -4
- package/dist/0-face/i18n.d.ts.map +1 -1
- package/dist/0-face/i18n.js +38 -16
- package/dist/0-face/layout-inspector.d.ts +5 -1
- package/dist/0-face/layout-inspector.d.ts.map +1 -1
- package/dist/0-face/layout-inspector.js +130 -104
- package/dist/0-face/preference-options.d.ts +4 -0
- package/dist/0-face/preference-options.d.ts.map +1 -1
- package/dist/0-face/scaling.d.ts +8 -1
- package/dist/0-face/scaling.d.ts.map +1 -1
- package/dist/0-face/scaling.js +19 -2
- package/dist/0-face/shape.d.ts +35 -0
- package/dist/0-face/shape.d.ts.map +1 -0
- package/dist/0-face/shape.js +23 -0
- package/dist/0-face/text-contrast.d.ts +22 -0
- package/dist/0-face/text-contrast.d.ts.map +1 -0
- package/dist/0-face/text-contrast.js +178 -0
- package/dist/0-face/theme-bootstrap.js +56 -0
- package/dist/0-face/toast-queue.d.ts +4 -0
- package/dist/0-face/toast-queue.d.ts.map +1 -1
- package/dist/0-face/toast-queue.js +4 -1
- package/dist/0-face/translations/da.json +10 -1
- package/dist/0-face/translations/de.json +10 -1
- package/dist/0-face/translations/en.json +10 -1
- package/dist/0-face/translations/es.json +10 -1
- package/dist/0-face/translations/fi.json +10 -1
- package/dist/0-face/translations/fr.json +10 -1
- package/dist/0-face/translations/is.json +10 -1
- package/dist/0-face/translations/it.json +10 -1
- package/dist/0-face/translations/ja.json +10 -1
- package/dist/0-face/translations/ko.json +10 -1
- package/dist/0-face/translations/nb.json +10 -1
- package/dist/0-face/translations/pt-BR.json +10 -1
- package/dist/0-face/translations/pt.json +10 -1
- package/dist/0-face/translations/sv.json +10 -1
- package/dist/0-face/translations/zh.json +10 -1
- package/dist/0-face/word-wrap.d.ts +6 -0
- package/dist/0-face/word-wrap.d.ts.map +1 -0
- package/dist/0-face/word-wrap.js +119 -0
- package/dist/1-root/foundation.d.ts +12 -0
- package/dist/1-root/foundation.d.ts.map +1 -0
- package/dist/1-root/foundation.js +59 -0
- package/dist/2-core/button-split.d.ts +1 -0
- package/dist/2-core/button-split.d.ts.map +1 -1
- package/dist/2-core/button-split.js +9 -4
- package/dist/2-core/chart/grid-chart.d.ts +2 -0
- package/dist/2-core/chart/grid-chart.d.ts.map +1 -1
- package/dist/2-core/chart/grid-chart.js +2 -1
- package/dist/2-core/ds-activity.d.ts +25 -0
- package/dist/2-core/ds-activity.d.ts.map +1 -0
- package/dist/2-core/ds-activity.js +28 -0
- package/dist/2-core/ds-app-chrome.d.ts +2 -0
- package/dist/2-core/ds-app-chrome.d.ts.map +1 -0
- package/dist/2-core/ds-app-chrome.js +1 -0
- package/dist/2-core/ds-avatar.d.ts +12 -0
- package/dist/2-core/ds-avatar.d.ts.map +1 -1
- package/dist/2-core/ds-avatar.js +86 -7
- package/dist/2-core/ds-badge.d.ts +7 -1
- package/dist/2-core/ds-badge.d.ts.map +1 -1
- package/dist/2-core/ds-badge.js +8 -1
- package/dist/2-core/ds-button.d.ts +12 -0
- package/dist/2-core/ds-button.d.ts.map +1 -1
- package/dist/2-core/ds-button.js +4 -0
- package/dist/2-core/ds-chart.d.ts +28 -3
- package/dist/2-core/ds-chart.d.ts.map +1 -1
- package/dist/2-core/ds-chart.js +110 -130
- package/dist/2-core/ds-cycle.d.ts +2 -2
- package/dist/2-core/ds-cycle.d.ts.map +1 -1
- package/dist/2-core/ds-cycle.js +36 -171
- package/dist/2-core/ds-device-bezel.d.ts +2 -0
- package/dist/2-core/ds-device-bezel.d.ts.map +1 -0
- package/dist/2-core/ds-device-bezel.js +1 -0
- package/dist/2-core/ds-empty.d.ts +2 -2
- package/dist/2-core/ds-empty.d.ts.map +1 -1
- package/dist/2-core/ds-empty.js +6 -4
- package/dist/2-core/ds-input.d.ts +7 -0
- package/dist/2-core/ds-input.d.ts.map +1 -1
- package/dist/2-core/ds-input.js +23 -3
- package/dist/2-core/ds-message.d.ts +11 -0
- package/dist/2-core/ds-message.d.ts.map +1 -1
- package/dist/2-core/ds-message.js +18 -0
- package/dist/2-core/ds-number.d.ts +86 -0
- package/dist/2-core/ds-number.d.ts.map +1 -0
- package/dist/2-core/ds-number.js +326 -0
- package/dist/2-core/ds-progress.d.ts +3 -0
- package/dist/2-core/ds-progress.d.ts.map +1 -1
- package/dist/2-core/ds-progress.js +3 -0
- package/dist/2-core/ds-radio.d.ts +3 -0
- package/dist/2-core/ds-radio.d.ts.map +1 -1
- package/dist/2-core/ds-radio.js +10 -1
- package/dist/2-core/ds-stat.d.ts +3 -0
- package/dist/2-core/ds-stat.d.ts.map +1 -1
- package/dist/2-core/ds-stat.js +3 -0
- package/dist/2-core/ds-switch.d.ts +14 -1
- package/dist/2-core/ds-switch.d.ts.map +1 -1
- package/dist/2-core/ds-switch.js +3 -1
- package/dist/2-core/ds-tag.d.ts +8 -1
- package/dist/2-core/ds-tag.d.ts.map +1 -1
- package/dist/2-core/ds-tag.js +12 -2
- package/dist/2-core/ds-text.d.ts +7 -0
- package/dist/2-core/ds-text.d.ts.map +1 -1
- package/dist/2-core/ds-text.js +7 -0
- package/dist/2-core/ds-token.d.ts +3 -0
- package/dist/2-core/ds-token.d.ts.map +1 -1
- package/dist/2-core/ds-token.js +3 -0
- package/dist/2-core/ds-tooltip.d.ts.map +1 -1
- package/dist/2-core/ds-tooltip.js +23 -2
- package/dist/2-core/ds-window.d.ts +2 -0
- package/dist/2-core/ds-window.d.ts.map +1 -0
- package/dist/2-core/ds-window.js +1 -0
- package/dist/2-core/generated/ds-icon-map.d.ts +27 -6
- package/dist/2-core/generated/ds-icon-map.d.ts.map +1 -1
- package/dist/2-core/generated/ds-icon-map.js +47 -5
- package/dist/2-core/generated/icons-extra.d.ts.map +1 -1
- package/dist/2-core/generated/icons-extra.js +24 -3
- package/dist/2-core/generated/icons-immediate.d.ts +1 -1
- package/dist/2-core/generated/icons-immediate.d.ts.map +1 -1
- package/dist/2-core/generated/icons-immediate.js +3 -3
- package/dist/2-core/number-expression.d.ts +12 -0
- package/dist/2-core/number-expression.d.ts.map +1 -0
- package/dist/2-core/number-expression.js +82 -0
- package/dist/3-unit/calendar-base.d.ts +5 -0
- package/dist/3-unit/calendar-base.d.ts.map +1 -1
- package/dist/3-unit/calendar-base.js +3 -2
- package/dist/3-unit/context-trigger.d.ts.map +1 -1
- package/dist/3-unit/context-trigger.js +32 -2
- package/dist/3-unit/ds-calendar.d.ts +197 -4
- package/dist/3-unit/ds-calendar.d.ts.map +1 -1
- package/dist/3-unit/ds-calendar.js +687 -45
- package/dist/3-unit/ds-carousel.d.ts +3 -0
- package/dist/3-unit/ds-carousel.d.ts.map +1 -1
- package/dist/3-unit/ds-carousel.js +13 -1
- package/dist/3-unit/ds-context.d.ts +18 -1
- package/dist/3-unit/ds-context.d.ts.map +1 -1
- package/dist/3-unit/ds-context.js +37 -1
- package/dist/3-unit/ds-form.d.ts +9 -0
- package/dist/3-unit/ds-form.d.ts.map +1 -1
- package/dist/3-unit/ds-form.js +52 -11
- package/dist/3-unit/ds-list.d.ts +20 -1
- package/dist/3-unit/ds-list.d.ts.map +1 -1
- package/dist/3-unit/ds-list.js +31 -3
- package/dist/3-unit/ds-matrix.d.ts +3 -0
- package/dist/3-unit/ds-matrix.d.ts.map +1 -1
- package/dist/3-unit/ds-matrix.js +3 -0
- package/dist/3-unit/ds-menu.d.ts.map +1 -1
- package/dist/3-unit/ds-menu.js +17 -1
- package/dist/3-unit/ds-row.d.ts +13 -0
- package/dist/3-unit/ds-row.d.ts.map +1 -1
- package/dist/3-unit/ds-row.js +15 -2
- package/dist/3-unit/ds-select.js +1 -1
- package/dist/3-unit/ds-sidebar.d.ts +17 -0
- package/dist/3-unit/ds-sidebar.d.ts.map +1 -1
- package/dist/3-unit/ds-sidebar.js +14 -3
- package/dist/3-unit/ds-table-of-contents.d.ts +68 -0
- package/dist/3-unit/ds-table-of-contents.d.ts.map +1 -0
- package/dist/3-unit/ds-table-of-contents.js +190 -0
- package/dist/3-unit/ds-table.d.ts.map +1 -1
- package/dist/3-unit/ds-table.js +2 -1
- package/dist/3-unit/ds-tabs.d.ts +32 -1
- package/dist/3-unit/ds-tabs.d.ts.map +1 -1
- package/dist/3-unit/ds-tabs.js +39 -1
- package/dist/4-page/ds-container.d.ts.map +1 -1
- package/dist/4-page/ds-container.js +2 -1
- package/dist/4-page/ds-document.d.ts +3 -0
- package/dist/4-page/ds-document.d.ts.map +1 -1
- package/dist/4-page/ds-document.js +3 -0
- package/dist/4-page/ds-footer.d.ts +47 -7
- package/dist/4-page/ds-footer.d.ts.map +1 -1
- package/dist/4-page/ds-footer.js +58 -14
- package/dist/4-page/ds-header.d.ts +6 -0
- package/dist/4-page/ds-header.d.ts.map +1 -1
- package/dist/4-page/ds-header.js +4 -1
- package/dist/4-page/ds-overlay.d.ts +2 -2
- package/dist/4-page/ds-overlay.d.ts.map +1 -1
- package/dist/4-page/ds-overlay.js +8 -3
- package/dist/4-page/ds-page.d.ts +12 -0
- package/dist/4-page/ds-page.d.ts.map +1 -1
- package/dist/4-page/ds-page.js +19 -1
- package/dist/4-page/email.d.ts +2 -0
- package/dist/4-page/email.d.ts.map +1 -1
- package/dist/4-page/email.js +5 -4
- package/dist/5-visual-kit/app-chrome.d.ts +98 -0
- package/dist/5-visual-kit/app-chrome.d.ts.map +1 -0
- package/dist/5-visual-kit/app-chrome.js +119 -0
- package/dist/5-visual-kit/bezels.d.ts +30 -0
- package/dist/5-visual-kit/bezels.d.ts.map +1 -0
- package/dist/5-visual-kit/bezels.js +388 -0
- package/dist/5-visual-kit/browser-icons.d.ts +5 -0
- package/dist/5-visual-kit/browser-icons.d.ts.map +1 -0
- package/dist/5-visual-kit/browser-icons.js +51 -0
- package/dist/5-visual-kit/browser-styles.d.ts +3 -0
- package/dist/5-visual-kit/browser-styles.d.ts.map +1 -0
- package/dist/5-visual-kit/browser-styles.js +52 -0
- package/dist/5-visual-kit/device-bezel.d.ts +84 -0
- package/dist/5-visual-kit/device-bezel.d.ts.map +1 -0
- package/dist/5-visual-kit/device-bezel.js +56 -0
- package/dist/5-visual-kit/instagram-frame.d.ts +8 -0
- package/dist/5-visual-kit/instagram-frame.d.ts.map +1 -0
- package/dist/5-visual-kit/instagram-frame.js +13 -0
- package/dist/5-visual-kit/instagram.d.ts +18 -0
- package/dist/5-visual-kit/instagram.d.ts.map +1 -0
- package/dist/5-visual-kit/instagram.js +39 -0
- package/dist/5-visual-kit/mobile-chrome.d.ts +4 -0
- package/dist/5-visual-kit/mobile-chrome.d.ts.map +1 -0
- package/dist/5-visual-kit/mobile-chrome.js +24 -0
- package/dist/5-visual-kit/native-icon-paths.d.ts +146 -0
- package/dist/5-visual-kit/native-icon-paths.d.ts.map +1 -0
- package/dist/5-visual-kit/native-icon-paths.js +145 -0
- package/dist/5-visual-kit/window.d.ts +51 -0
- package/dist/5-visual-kit/window.d.ts.map +1 -0
- package/dist/5-visual-kit/window.js +20 -0
- package/dist/browser-icons-BFbS1tIx.js +56 -0
- package/dist/browser-icons-BFbS1tIx.js.map +1 -0
- package/dist/browser-icons-CT8qU77Z.js +48 -0
- package/dist/browser-icons-CT8qU77Z.js.map +1 -0
- package/dist/components.d.ts +1 -0
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +1 -0
- package/dist/design-system-1.bundle.js +5874 -2097
- package/dist/design-system-1.bundle.js.map +1 -1
- package/dist/design-system-1.bundle.min.js +7332 -4682
- package/dist/design-system-1.bundle.min.js.map +1 -1
- package/dist/design-system-1.css +1 -1
- package/dist/feedback.js +197 -167
- package/dist/feedback.js.map +1 -1
- package/dist/{icons-extra-CRxxWFjX.js → icons-extra-BMPvmQPI.js} +25 -4
- package/dist/icons-extra-BMPvmQPI.js.map +1 -0
- package/dist/{icons-extra-H5pqCM_R.js → icons-extra-BfYOw-cR.js} +83 -5
- package/dist/icons-extra-BfYOw-cR.js.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/instagram-CKofs55A.js +50 -0
- package/dist/instagram-CKofs55A.js.map +1 -0
- package/dist/instagram-CcYf5oiM.js +48 -0
- package/dist/instagram-CcYf5oiM.js.map +1 -0
- package/dist/lit-Ce_uWYM4.js +612 -0
- package/dist/lit-Ce_uWYM4.js.map +1 -0
- package/dist/lit-DGUVm1Ce.js +557 -0
- package/dist/lit-DGUVm1Ce.js.map +1 -0
- package/dist/native-icon-paths-CB9evXBM.js +93 -0
- package/dist/native-icon-paths-CB9evXBM.js.map +1 -0
- package/dist/native-icon-paths-zay-3g_n.js +150 -0
- package/dist/native-icon-paths-zay-3g_n.js.map +1 -0
- package/dist/react/avatar.d.ts +1 -1
- package/dist/react/choice.d.ts +4 -0
- package/dist/react/choice.d.ts.map +1 -1
- package/dist/react/choice.js +2 -2
- package/dist/react/context.d.ts +19 -4
- package/dist/react/context.d.ts.map +1 -1
- package/dist/react/context.js +4 -4
- package/dist/react/empty.d.ts +2 -2
- package/dist/react/empty.d.ts.map +1 -1
- package/dist/react/empty.js +1 -1
- package/dist/react/footer.d.ts +5 -5
- package/dist/react/footer.d.ts.map +1 -1
- package/dist/react/footer.js +2 -2
- package/dist/react/header.d.ts +2 -2
- package/dist/react/header.d.ts.map +1 -1
- package/dist/react/message.d.ts +4 -0
- package/dist/react/message.d.ts.map +1 -1
- package/dist/react/message.js +2 -2
- package/dist/react/number.d.ts +53 -0
- package/dist/react/number.d.ts.map +1 -0
- package/dist/react/number.js +25 -0
- package/dist/react/page.d.ts +1 -1
- package/dist/react/sidebar.d.ts +4 -0
- package/dist/react/sidebar.d.ts.map +1 -1
- package/dist/react/sidebar.js +2 -2
- package/dist/react/table-of-contents.d.ts +19 -0
- package/dist/react/table-of-contents.d.ts.map +1 -0
- package/dist/react/table-of-contents.js +28 -0
- package/dist/{shared-words-CdMDVtXx.js → shared-words-C5cjxMjZ.js} +151 -16
- package/dist/shared-words-C5cjxMjZ.js.map +1 -0
- package/dist/{shared-words-BtRee8xR.js → shared-words-Cdm7xd-_.js} +163 -28
- package/dist/shared-words-Cdm7xd-_.js.map +1 -0
- package/package.json +25 -12
- package/DS1/3-unit/ds-calendar-large.ts +0 -353
- package/DS1/3-unit/styles/ds-calendar-large.css +0 -178
- package/dist/3-unit/ds-calendar-large.d.ts +0 -142
- package/dist/3-unit/ds-calendar-large.d.ts.map +0 -1
- package/dist/3-unit/ds-calendar-large.js +0 -308
- package/dist/icons-extra-CRxxWFjX.js.map +0 -1
- package/dist/icons-extra-H5pqCM_R.js.map +0 -1
- package/dist/shared-words-BtRee8xR.js.map +0 -1
- package/dist/shared-words-CdMDVtXx.js.map +0 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
const tolerance = 1;
|
|
2
|
+
const near = (a, b) => Math.abs(a - b) <= tolerance;
|
|
3
|
+
const style = (el) => el.ownerDocument.defaultView.getComputedStyle(el);
|
|
4
|
+
const visible = (el) => {
|
|
5
|
+
const box = el.getBoundingClientRect();
|
|
6
|
+
return box.width > 0 && box.height > 0 && style(el).visibility !== 'hidden' && style(el).display !== 'none';
|
|
7
|
+
};
|
|
8
|
+
/** Walk each open shadow tree once; slotted children already occur in the light tree. */
|
|
9
|
+
function elements(root) {
|
|
10
|
+
return Array.from(root.querySelectorAll('*')).flatMap(el => [el, ...(el.shadowRoot ? elements(el.shadowRoot) : [])]);
|
|
11
|
+
}
|
|
12
|
+
/** Related grids opt in by name; unlabelled card grids are candidates for human review. */
|
|
13
|
+
export function faultLineGrids(root) {
|
|
14
|
+
return elements(root).flatMap(element => {
|
|
15
|
+
const family = element.getAttribute('data-ds-fault-lines');
|
|
16
|
+
if (family === 'off' || !visible(element))
|
|
17
|
+
return [];
|
|
18
|
+
const children = Array.from(element.children).filter(visible);
|
|
19
|
+
if (!children.length)
|
|
20
|
+
return [];
|
|
21
|
+
if (family === null && (!/grid/.test(style(element).display) || children.length < 2 ||
|
|
22
|
+
!children.every(child => child.matches('ds-card, .ds-card, ds-button, button'))))
|
|
23
|
+
return [];
|
|
24
|
+
const axis = element.getAttribute('data-ds-fault-axis') === 'y' ? 'y' : 'x';
|
|
25
|
+
const boxes = children.map(child => child.getBoundingClientRect());
|
|
26
|
+
const crossStart = (box) => axis === 'x' ? box.top : box.left;
|
|
27
|
+
const crossEnd = (box) => axis === 'x' ? box.bottom : box.right;
|
|
28
|
+
const start = (box) => axis === 'x' ? box.left : box.top;
|
|
29
|
+
const end = (box) => axis === 'x' ? box.right : box.bottom;
|
|
30
|
+
const bands = [];
|
|
31
|
+
for (const box of boxes.sort((a, b) => crossStart(a) - crossStart(b))) {
|
|
32
|
+
const band = bands.find(row => near(crossStart(row[0]), crossStart(box)));
|
|
33
|
+
if (band)
|
|
34
|
+
band.push(box);
|
|
35
|
+
else
|
|
36
|
+
bands.push([box]);
|
|
37
|
+
}
|
|
38
|
+
// The fullest band defines the tracks; an incomplete final row is valid.
|
|
39
|
+
const band = [...bands].sort((a, b) => b.length - a.length)[0].sort((a, b) => start(a) - start(b));
|
|
40
|
+
const lines = band.flatMap(box => [start(box), end(box)]);
|
|
41
|
+
const gaps = band.slice(1).map((box, index) => start(box) - end(band[index]));
|
|
42
|
+
const crossGaps = bands.slice(1).map((row, index) => Math.min(...row.map(crossStart)) - Math.max(...bands[index].map(crossEnd)));
|
|
43
|
+
const internalDrift = bands.some(row => row.length === band.length && row.slice().sort((a, b) => start(a) - start(b)).some((box, index) => !near(start(box), lines[index * 2]) || !near(end(box), lines[index * 2 + 1]))) || crossGaps.some(gap => !near(gap, crossGaps[0]));
|
|
44
|
+
return [{ element, family, axis, lines, gaps, crossGap: crossGaps[0], internalDrift, start: lines[0], end: lines[lines.length - 1] }];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function referenceFor(grids, i) {
|
|
48
|
+
const current = grids[i];
|
|
49
|
+
return grids.slice(0, i).find(other => {
|
|
50
|
+
if (other.axis !== current.axis || other.lines.length !== current.lines.length)
|
|
51
|
+
return false;
|
|
52
|
+
if (current.family !== null || other.family !== null)
|
|
53
|
+
return current.family !== null && current.family === other.family;
|
|
54
|
+
return near(current.start, other.start) && near(current.end, other.end);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Fault lines compare rendered tracks across separate sections, in the current viewport. */
|
|
58
|
+
export function inspectFaultLines(root) {
|
|
59
|
+
const grids = faultLineGrids(root);
|
|
60
|
+
const findings = [];
|
|
61
|
+
for (let i = 0; i < grids.length; i++) {
|
|
62
|
+
const current = grids[i];
|
|
63
|
+
if (current.internalDrift)
|
|
64
|
+
findings.push({ element: current.element, ...(current.family === null ? { review: true } : {}), message: `Fault lines at ${current.element.ownerDocument.documentElement.clientWidth}px: tracks or repeated gaps drift inside ${current.family || 'this card grid'}. Align its complete rows and repeated spacing.` });
|
|
65
|
+
const reference = referenceFor(grids, i);
|
|
66
|
+
if (!reference)
|
|
67
|
+
continue;
|
|
68
|
+
const drift = current.lines.map((line, index) => Math.abs(line - reference.lines[index]));
|
|
69
|
+
const gapDrift = current.gaps.some((gap, index) => !near(gap, reference.gaps[index]));
|
|
70
|
+
const rowDrift = current.crossGap !== undefined && reference.crossGap !== undefined && !near(current.crossGap, reference.crossGap);
|
|
71
|
+
if (!drift.some(value => value > tolerance) && !gapDrift && !rowDrift)
|
|
72
|
+
continue;
|
|
73
|
+
const width = current.element.ownerDocument.documentElement.clientWidth;
|
|
74
|
+
const review = current.family === null;
|
|
75
|
+
findings.push({ element: current.element, ...(review ? { review: true } : {}), message: `Fault lines at ${width}px: ${current.family || 'these card grids'} ${review ? 'may be related but have' : 'have'} misaligned ${current.axis === 'x' ? 'column' : 'row'} edges or unequal gaps (edge drift ${Math.round(Math.max(...drift))}px; gaps ${current.gaps.map(Math.round).join('/')}px versus ${reference.gaps.map(Math.round).join('/')}px${rowDrift ? `; cross-axis gap ${Math.round(current.crossGap)}px versus ${Math.round(reference.crossGap)}px` : ''}). ${review ? 'Name the related groups with data-ds-fault-lines to enforce alignment, or mark an intentional exception off.' : 'Use the same tracks and gap for this family at this viewport.'}` });
|
|
76
|
+
}
|
|
77
|
+
return findings;
|
|
78
|
+
}
|
|
79
|
+
/** The same rendered geometry as the checker, painted without affecting layout or hit testing. */
|
|
80
|
+
export function paintFaultLines(root, layer) {
|
|
81
|
+
const doc = layer.ownerDocument;
|
|
82
|
+
const width = doc.documentElement.clientWidth;
|
|
83
|
+
const height = doc.defaultView.innerHeight;
|
|
84
|
+
layer.setAttribute('viewBox', `0 0 ${width} ${height}`);
|
|
85
|
+
layer.setAttribute('width', String(width));
|
|
86
|
+
layer.setAttribute('height', String(height));
|
|
87
|
+
layer.setAttribute('aria-hidden', 'true');
|
|
88
|
+
layer.style.cssText = 'position:fixed;inset:0;pointer-events:none;overflow:hidden;z-index:2147483644';
|
|
89
|
+
layer.replaceChildren();
|
|
90
|
+
const grids = faultLineGrids(root);
|
|
91
|
+
const failed = new Set(inspectFaultLines(root).map(finding => finding.element));
|
|
92
|
+
const drawn = new Set();
|
|
93
|
+
const referenceInk = '#087ba8';
|
|
94
|
+
const faultInk = '#de0331';
|
|
95
|
+
function mark(tag, attributes, title) {
|
|
96
|
+
const node = doc.createElementNS('http://www.w3.org/2000/svg', tag);
|
|
97
|
+
for (const [key, value] of Object.entries(attributes))
|
|
98
|
+
node.setAttribute(key, String(value));
|
|
99
|
+
if (title) {
|
|
100
|
+
const tip = doc.createElementNS(node.namespaceURI, 'title');
|
|
101
|
+
tip.textContent = title;
|
|
102
|
+
node.appendChild(tip);
|
|
103
|
+
}
|
|
104
|
+
layer.appendChild(node);
|
|
105
|
+
return node;
|
|
106
|
+
}
|
|
107
|
+
for (let index = 0; index < grids.length; index++) {
|
|
108
|
+
const grid = grids[index];
|
|
109
|
+
const reference = referenceFor(grids, index) ?? grid;
|
|
110
|
+
for (const edge of reference.lines) {
|
|
111
|
+
const key = `${grid.axis}:${edge}`;
|
|
112
|
+
if (drawn.has(key))
|
|
113
|
+
continue;
|
|
114
|
+
drawn.add(key);
|
|
115
|
+
mark('line', { 'data-fault-reference': '', x1: grid.axis === 'x' ? edge : 0, y1: grid.axis === 'y' ? edge : 0,
|
|
116
|
+
x2: grid.axis === 'x' ? edge : width, y2: grid.axis === 'y' ? edge : height,
|
|
117
|
+
stroke: referenceInk, 'stroke-width': 1, 'stroke-dasharray': '4 4' }, 'Reference edge');
|
|
118
|
+
}
|
|
119
|
+
const broken = failed.has(grid.element);
|
|
120
|
+
if (!broken)
|
|
121
|
+
continue;
|
|
122
|
+
// Draw each actual child so drift inside a later row is visible too.
|
|
123
|
+
for (const child of Array.from(grid.element.children).filter(visible)) {
|
|
124
|
+
const box = child.getBoundingClientRect();
|
|
125
|
+
const edges = grid.axis === 'x' ? [box.left, box.right] : [box.top, box.bottom];
|
|
126
|
+
for (const edge of edges) {
|
|
127
|
+
if (reference.lines.some(expected => near(edge, expected)))
|
|
128
|
+
continue;
|
|
129
|
+
mark('line', { 'data-fault-actual': '', x1: grid.axis === 'x' ? edge : box.left, y1: grid.axis === 'y' ? edge : box.top,
|
|
130
|
+
x2: grid.axis === 'x' ? edge : box.right, y2: grid.axis === 'y' ? edge : box.bottom,
|
|
131
|
+
stroke: faultInk, 'stroke-width': 2 }, 'Actual edge differs from the dashed reference');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Row spacing can drift even when every column edge still aligns.
|
|
135
|
+
const rows = [];
|
|
136
|
+
for (const child of Array.from(grid.element.children).filter(visible)) {
|
|
137
|
+
const box = child.getBoundingClientRect();
|
|
138
|
+
const start = grid.axis === 'x' ? box.top : box.left;
|
|
139
|
+
const row = rows.find(row => near(grid.axis === 'x' ? row[0].top : row[0].left, start));
|
|
140
|
+
if (row)
|
|
141
|
+
row.push(box);
|
|
142
|
+
else
|
|
143
|
+
rows.push([box]);
|
|
144
|
+
}
|
|
145
|
+
rows.sort((a, b) => grid.axis === 'x' ? a[0].top - b[0].top : a[0].left - b[0].left);
|
|
146
|
+
const bounds = grid.element.getBoundingClientRect();
|
|
147
|
+
const crossGap = reference.crossGap ?? grid.crossGap;
|
|
148
|
+
if (crossGap !== undefined)
|
|
149
|
+
for (let row = 1; row < rows.length; row++) {
|
|
150
|
+
const previousEnd = Math.max(...rows[row - 1].map(box => grid.axis === 'x' ? box.bottom : box.right));
|
|
151
|
+
const actual = Math.min(...rows[row].map(box => grid.axis === 'x' ? box.top : box.left));
|
|
152
|
+
const expected = previousEnd + crossGap;
|
|
153
|
+
if (near(actual, expected))
|
|
154
|
+
continue;
|
|
155
|
+
for (const [edge, kind] of [[expected, 'reference'], [actual, 'actual']]) {
|
|
156
|
+
mark('line', { [`data-fault-${kind}`]: '', x1: grid.axis === 'x' ? bounds.left : edge, y1: grid.axis === 'x' ? edge : bounds.top,
|
|
157
|
+
x2: grid.axis === 'x' ? bounds.right : edge, y2: grid.axis === 'x' ? edge : bounds.bottom,
|
|
158
|
+
stroke: kind === 'reference' ? referenceInk : faultInk, 'stroke-width': kind === 'reference' ? 1 : 2,
|
|
159
|
+
'stroke-dasharray': kind === 'reference' ? '4 4' : '' }, `Row gap ${Math.round(actual - previousEnd)}px; reference ${Math.round(crossGap)}px`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const box = grid.element.getBoundingClientRect();
|
|
163
|
+
const label = mark('text', { 'data-fault-gap': '', x: Math.max(4, box.left), y: Math.max(16, Math.min(height - 4, box.top + 16)),
|
|
164
|
+
fill: faultInk, stroke: 'var(--ds-background-color, white)', 'stroke-width': 3, 'paint-order': 'stroke',
|
|
165
|
+
'font-family': 'var(--ds-typeface-regular, sans-serif)', 'font-size': 12 });
|
|
166
|
+
const gaps = grid.gaps.map(gap => Math.round(gap)).join('/');
|
|
167
|
+
const expected = reference.gaps.map(gap => Math.round(gap)).join('/');
|
|
168
|
+
label.textContent = `Gap ${gaps || '—'}px · reference ${expected || '—'}px` +
|
|
169
|
+
(grid.crossGap !== undefined && reference.crossGap !== undefined && !near(grid.crossGap, reference.crossGap)
|
|
170
|
+
? ` · row gap ${Math.round(grid.crossGap)}px / ${Math.round(reference.crossGap)}px` : '');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feedback-overlays.d.ts","sourceRoot":"","sources":["../../DS1/0-face/feedback-overlays.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kHAAkH;IAClH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mHAAmH;IACnH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"feedback-overlays.d.ts","sourceRoot":"","sources":["../../DS1/0-face/feedback-overlays.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kHAAkH;IAClH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mHAAmH;IACnH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAwID,uFAAuF;AACvF,wBAAgB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAInE;AAED,qFAAqF;AACrF,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAI1E;AAED,sFAAsF;AACtF,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ9E"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* `confirm()` and `prompt()`, for pages without Lit or any other framework.
|
|
4
4
|
*
|
|
5
5
|
* Each is drawn on the native `dialog.ds-overlay` frame from `1-root/controls.css`
|
|
6
|
-
* (which the page loads) with its native buttons, `.ds-button--primary`,
|
|
6
|
+
* (which the page loads), as a sheet from the screen's foot on a phone, with its native buttons, `.ds-button--primary`,
|
|
7
7
|
* `--secondary` and `--danger`, and opened with `showModal()`, so the browser
|
|
8
8
|
* keeps the rest of the page inert behind it. Their words default to the
|
|
9
9
|
* shared words (OK, Cancel) in the page's language where the page loads the
|
|
@@ -59,8 +59,10 @@ function show(spec) {
|
|
|
59
59
|
return new Promise(resolve => {
|
|
60
60
|
const id = `ds-feedback-${++count}`;
|
|
61
61
|
const opener = focused();
|
|
62
|
+
// A sheet from the foot of a phone's screen, never a modal there (Joachim, 20 October 2026).
|
|
63
|
+
const phone = typeof matchMedia === "function" && matchMedia("(max-width: 768px)").matches;
|
|
62
64
|
const dialog = element("dialog", {
|
|
63
|
-
class: "ds-overlay",
|
|
65
|
+
class: phone ? "ds-overlay ds-overlay--sheet" : "ds-overlay",
|
|
64
66
|
role: spec.kind === "prompt" ? "dialog" : "alertdialog",
|
|
65
67
|
"aria-labelledby": `${id}-title`,
|
|
66
68
|
"data-ds-feedback": spec.kind,
|
|
@@ -88,7 +90,7 @@ function show(spec) {
|
|
|
88
90
|
}
|
|
89
91
|
const footer = element("div", { "data-ds-overlay": "footer" });
|
|
90
92
|
const cancel = spec.cancel === undefined ? undefined : element("button", { type: "button", class: "ds-button ds-button--secondary", value: "cancel" }, spec.cancel);
|
|
91
|
-
const confirm = element("button", { type: "button", class: spec.danger ? "ds-button ds-button--
|
|
93
|
+
const confirm = element("button", { type: "button", class: spec.danger ? "ds-button ds-button--danger" : "ds-button ds-button--primary", value: "confirm" }, spec.confirm);
|
|
92
94
|
if (cancel)
|
|
93
95
|
footer.appendChild(cancel);
|
|
94
96
|
footer.appendChild(confirm);
|
|
@@ -38,4 +38,6 @@ export { copyText } from "./copy-text";
|
|
|
38
38
|
export type { CopyTextOptions } from "./copy-text";
|
|
39
39
|
export { setFeedbackWords } from "./feedback-words";
|
|
40
40
|
export type { FeedbackWord, FeedbackWords } from "./feedback-words";
|
|
41
|
+
export { reportFailure, FAILURE_EVENT } from "./failures";
|
|
42
|
+
export type { Failure } from "./failures";
|
|
41
43
|
//# sourceMappingURL=feedback.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../DS1/0-face/feedback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACjE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACnI,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../DS1/0-face/feedback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACjE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACnI,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEpE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/0-face/feedback.js
CHANGED
|
@@ -33,3 +33,4 @@ export { configureToaster, pageToaster, toast } from "./toaster";
|
|
|
33
33
|
export { alert, confirm, prompt } from "./feedback-overlays";
|
|
34
34
|
export { copyText } from "./copy-text";
|
|
35
35
|
export { setFeedbackWords } from "./feedback-words";
|
|
36
|
+
export { reportFailure, FAILURE_EVENT } from "./failures";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image focus: where a photo's subject is, so a picture cut to its box
|
|
3
|
+
* (`object-fit: cover`) keeps it in view instead of its middle. A person's
|
|
4
|
+
* face first, then whatever in the picture holds the most detail. Plain
|
|
5
|
+
* TypeScript with no imports, for the browser and for a build script alike.
|
|
6
|
+
*
|
|
7
|
+
* The focus is a point of the picture, across and down from 0 to 1, and it is
|
|
8
|
+
* written as the picture's `object-position` (`objectPosition()`), so a
|
|
9
|
+
* cover crop of any shape keeps that point in view. Work it out once, where
|
|
10
|
+
* the page is built, and write it into the markup, so the first paint is
|
|
11
|
+
* already cut right. On a Mac, `focus-vision.swift` finds the faces and the
|
|
12
|
+
* salient part with Apple's Vision framework, and `focusFromRegions()` turns
|
|
13
|
+
* them into the focus; elsewhere, or where it finds nothing, `focusOf()`
|
|
14
|
+
* reads the pixels:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* // swift 0-face/focus-vision.swift *.jpg > regions.json
|
|
18
|
+
* import { focusFromRegions, focusOf, objectPosition } from "./0-face/focus.ts";
|
|
19
|
+
* const focus = focusFromRegions(regions[name]) ?? focusOf(data, info.width, info.height, info.channels);
|
|
20
|
+
* // <img src="…" style="object-position: 50% 18%">
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* A page with no build step marks a picture `data-ds-focus="auto"` and calls
|
|
24
|
+
* `startFocus()`: once the picture has loaded, its focus is found and kept in
|
|
25
|
+
* the browser, so it is right from the first paint on the next visit. A
|
|
26
|
+
* picture whose focus a person chose says so, `data-ds-focus="40% 20%"`, and
|
|
27
|
+
* is never measured. A picture from another host without CORS cannot be read
|
|
28
|
+
* and keeps its middle.
|
|
29
|
+
*/
|
|
30
|
+
/** A point of a picture, across (`x`) and down (`y`), each from 0 to 1. */
|
|
31
|
+
export interface Focus {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
}
|
|
35
|
+
export declare const CENTRE: Focus;
|
|
36
|
+
/** The width a picture is measured at; enough to find a face, and cheap. */
|
|
37
|
+
export declare const FOCUS_SAMPLE = 64;
|
|
38
|
+
/**
|
|
39
|
+
* The focus of a picture from its pixels (RGB or RGBA, row by row), measured
|
|
40
|
+
* small (about `FOCUS_SAMPLE` across). Skin that gathers into a face wins:
|
|
41
|
+
* the highest band of rows dense with skin, since a face stands above hands
|
|
42
|
+
* and arms. Without one, the centre of the picture's detail (where neighbouring
|
|
43
|
+
* pixels differ most), drawn a little towards the middle so a busy edge does
|
|
44
|
+
* not take the crop.
|
|
45
|
+
*/
|
|
46
|
+
export declare function focusOf(pixels: ArrayLike<number>, width: number, height: number, channels?: number): Focus;
|
|
47
|
+
/** A part of a picture, as fractions of it from its top left corner. */
|
|
48
|
+
export interface Region {
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
w: number;
|
|
52
|
+
h: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The focus from what a detector found (`focus-vision.swift`: Apple's face
|
|
56
|
+
* detection and attention-based saliency), or `undefined` when it found
|
|
57
|
+
* nothing. Faces win: the point between them across, and down a little above
|
|
58
|
+
* the top of the highest, so a crop keeps the heads whole with room above
|
|
59
|
+
* them. Otherwise the middle of everything salient.
|
|
60
|
+
*/
|
|
61
|
+
export declare function focusFromRegions(found: {
|
|
62
|
+
faces?: Region[];
|
|
63
|
+
salient?: Region[];
|
|
64
|
+
}): Focus | undefined;
|
|
65
|
+
/** The focus as CSS `object-position`, in whole percents. */
|
|
66
|
+
export declare function objectPosition(focus: Focus): string;
|
|
67
|
+
/** Finds and sets the focus of one picture marked `data-ds-focus="auto"`, once it has loaded. */
|
|
68
|
+
export declare function focusImage(image: HTMLImageElement): void;
|
|
69
|
+
/** Sets the focus of every picture marked `data-ds-focus` in `root`. */
|
|
70
|
+
export declare function startFocus(root?: ParentNode): void;
|
|
71
|
+
//# sourceMappingURL=focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../DS1/0-face/focus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE;AAE/C,eAAO,MAAM,MAAM,EAAE,KAA0B,CAAC;AAEhD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,KAAK,CAAC;AAY/B;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,KAAK,CAqDrG;AAED,wEAAwE;AACxE,MAAM,WAAW,MAAM;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE;AAEtE;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,KAAK,GAAG,SAAS,CAkBnG;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEnD;AAID,iGAAiG;AACjG,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CA0BxD;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,IAAI,GAAE,UAAqB,GAAG,IAAI,CAE5D"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image focus: where a photo's subject is, so a picture cut to its box
|
|
3
|
+
* (`object-fit: cover`) keeps it in view instead of its middle. A person's
|
|
4
|
+
* face first, then whatever in the picture holds the most detail. Plain
|
|
5
|
+
* TypeScript with no imports, for the browser and for a build script alike.
|
|
6
|
+
*
|
|
7
|
+
* The focus is a point of the picture, across and down from 0 to 1, and it is
|
|
8
|
+
* written as the picture's `object-position` (`objectPosition()`), so a
|
|
9
|
+
* cover crop of any shape keeps that point in view. Work it out once, where
|
|
10
|
+
* the page is built, and write it into the markup, so the first paint is
|
|
11
|
+
* already cut right. On a Mac, `focus-vision.swift` finds the faces and the
|
|
12
|
+
* salient part with Apple's Vision framework, and `focusFromRegions()` turns
|
|
13
|
+
* them into the focus; elsewhere, or where it finds nothing, `focusOf()`
|
|
14
|
+
* reads the pixels:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* // swift 0-face/focus-vision.swift *.jpg > regions.json
|
|
18
|
+
* import { focusFromRegions, focusOf, objectPosition } from "./0-face/focus.ts";
|
|
19
|
+
* const focus = focusFromRegions(regions[name]) ?? focusOf(data, info.width, info.height, info.channels);
|
|
20
|
+
* // <img src="…" style="object-position: 50% 18%">
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* A page with no build step marks a picture `data-ds-focus="auto"` and calls
|
|
24
|
+
* `startFocus()`: once the picture has loaded, its focus is found and kept in
|
|
25
|
+
* the browser, so it is right from the first paint on the next visit. A
|
|
26
|
+
* picture whose focus a person chose says so, `data-ds-focus="40% 20%"`, and
|
|
27
|
+
* is never measured. A picture from another host without CORS cannot be read
|
|
28
|
+
* and keeps its middle.
|
|
29
|
+
*/
|
|
30
|
+
export const CENTRE = { x: 0.5, y: 0.5 };
|
|
31
|
+
/** The width a picture is measured at; enough to find a face, and cheap. */
|
|
32
|
+
export const FOCUS_SAMPLE = 64;
|
|
33
|
+
/** Whether a pixel's colour is skin, in YCbCr, for any skin tone. */
|
|
34
|
+
function isSkin(r, g, b) {
|
|
35
|
+
const y = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
36
|
+
const cb = 128 - 0.168736 * r - 0.331264 * g + 0.5 * b;
|
|
37
|
+
const cr = 128 + 0.5 * r - 0.418688 * g - 0.081312 * b;
|
|
38
|
+
return y > 40 && cb >= 77 && cb <= 127 && cr >= 137 && cr <= 173 && r > g && r > b;
|
|
39
|
+
}
|
|
40
|
+
const clamp = (value) => Math.min(1, Math.max(0, value));
|
|
41
|
+
/**
|
|
42
|
+
* The focus of a picture from its pixels (RGB or RGBA, row by row), measured
|
|
43
|
+
* small (about `FOCUS_SAMPLE` across). Skin that gathers into a face wins:
|
|
44
|
+
* the highest band of rows dense with skin, since a face stands above hands
|
|
45
|
+
* and arms. Without one, the centre of the picture's detail (where neighbouring
|
|
46
|
+
* pixels differ most), drawn a little towards the middle so a busy edge does
|
|
47
|
+
* not take the crop.
|
|
48
|
+
*/
|
|
49
|
+
export function focusOf(pixels, width, height, channels = 4) {
|
|
50
|
+
if (width < 2 || height < 2)
|
|
51
|
+
return CENTRE;
|
|
52
|
+
const at = (x, y) => (y * width + x) * channels;
|
|
53
|
+
const luma = new Float32Array(width * height);
|
|
54
|
+
const skin = new Uint8Array(width * height);
|
|
55
|
+
let skinCount = 0;
|
|
56
|
+
for (let y = 0; y < height; y++) {
|
|
57
|
+
for (let x = 0; x < width; x++) {
|
|
58
|
+
const i = at(x, y);
|
|
59
|
+
const r = pixels[i], g = pixels[i + 1], b = pixels[i + 2];
|
|
60
|
+
luma[y * width + x] = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
61
|
+
if (isSkin(r, g, b)) {
|
|
62
|
+
skin[y * width + x] = 1;
|
|
63
|
+
skinCount++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// A face: skin over at least half a percent of the picture, in a band of rows.
|
|
68
|
+
if (skinCount >= width * height * 0.005) {
|
|
69
|
+
const band = Math.max(2, Math.round(height / 10));
|
|
70
|
+
const rows = new Float32Array(height);
|
|
71
|
+
for (let y = 0; y < height; y++)
|
|
72
|
+
for (let x = 0; x < width; x++)
|
|
73
|
+
rows[y] += skin[y * width + x];
|
|
74
|
+
let densest = 0;
|
|
75
|
+
const bands = [];
|
|
76
|
+
for (let y = 0; y + band <= height; y++) {
|
|
77
|
+
let sum = 0;
|
|
78
|
+
for (let k = 0; k < band; k++)
|
|
79
|
+
sum += rows[y + k];
|
|
80
|
+
bands.push(sum);
|
|
81
|
+
densest = Math.max(densest, sum);
|
|
82
|
+
}
|
|
83
|
+
const top = bands.findIndex(sum => sum >= densest * 0.45);
|
|
84
|
+
if (top >= 0) {
|
|
85
|
+
let sx = 0, sy = 0, n = 0;
|
|
86
|
+
for (let y = top; y < Math.min(height, top + band * 2); y++) {
|
|
87
|
+
for (let x = 0; x < width; x++)
|
|
88
|
+
if (skin[y * width + x]) {
|
|
89
|
+
sx += x;
|
|
90
|
+
sy += y;
|
|
91
|
+
n++;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (n)
|
|
95
|
+
return { x: clamp((sx / n + 0.5) / width), y: clamp((sy / n + 0.5) / height) };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Otherwise the picture's detail.
|
|
99
|
+
let sx = 0, sy = 0, total = 0;
|
|
100
|
+
for (let y = 1; y < height - 1; y++) {
|
|
101
|
+
for (let x = 1; x < width - 1; x++) {
|
|
102
|
+
const i = y * width + x;
|
|
103
|
+
const energy = Math.abs(luma[i + 1] - luma[i - 1]) + Math.abs(luma[i + width] - luma[i - width]);
|
|
104
|
+
sx += x * energy;
|
|
105
|
+
sy += y * energy;
|
|
106
|
+
total += energy;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!total)
|
|
110
|
+
return CENTRE;
|
|
111
|
+
const pull = 0.35;
|
|
112
|
+
return {
|
|
113
|
+
x: clamp(((sx / total + 0.5) / width) * (1 - pull) + 0.5 * pull),
|
|
114
|
+
y: clamp(((sy / total + 0.5) / height) * (1 - pull) + 0.5 * pull),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The focus from what a detector found (`focus-vision.swift`: Apple's face
|
|
119
|
+
* detection and attention-based saliency), or `undefined` when it found
|
|
120
|
+
* nothing. Faces win: the point between them across, and down a little above
|
|
121
|
+
* the top of the highest, so a crop keeps the heads whole with room above
|
|
122
|
+
* them. Otherwise the middle of everything salient.
|
|
123
|
+
*/
|
|
124
|
+
export function focusFromRegions(found) {
|
|
125
|
+
const faces = (found.faces ?? []).filter(face => face.w * face.h > 0.0005);
|
|
126
|
+
if (faces.length) {
|
|
127
|
+
const biggest = Math.max(...faces.map(face => face.w * face.h));
|
|
128
|
+
const kept = faces.filter(face => face.w * face.h >= biggest * 0.25);
|
|
129
|
+
const left = Math.min(...kept.map(face => face.x));
|
|
130
|
+
const right = Math.max(...kept.map(face => face.x + face.w));
|
|
131
|
+
const top = Math.min(...kept.map(face => face.y));
|
|
132
|
+
const height = Math.max(...kept.map(face => face.h));
|
|
133
|
+
return { x: clamp((left + right) / 2), y: clamp(top - height * 0.35) };
|
|
134
|
+
}
|
|
135
|
+
const salient = found.salient ?? [];
|
|
136
|
+
if (!salient.length)
|
|
137
|
+
return undefined;
|
|
138
|
+
const left = Math.min(...salient.map(r => r.x));
|
|
139
|
+
const right = Math.max(...salient.map(r => r.x + r.w));
|
|
140
|
+
const top = Math.min(...salient.map(r => r.y));
|
|
141
|
+
const bottom = Math.max(...salient.map(r => r.y + r.h));
|
|
142
|
+
return { x: clamp((left + right) / 2), y: clamp((top + bottom) / 2) };
|
|
143
|
+
}
|
|
144
|
+
/** The focus as CSS `object-position`, in whole percents. */
|
|
145
|
+
export function objectPosition(focus) {
|
|
146
|
+
return `${Math.round(focus.x * 100)}% ${Math.round(focus.y * 100)}%`;
|
|
147
|
+
}
|
|
148
|
+
const KEY = "ds-focus:";
|
|
149
|
+
/** Finds and sets the focus of one picture marked `data-ds-focus="auto"`, once it has loaded. */
|
|
150
|
+
export function focusImage(image) {
|
|
151
|
+
const chosen = image.dataset.dsFocus;
|
|
152
|
+
if (chosen && chosen !== "auto") {
|
|
153
|
+
image.style.objectPosition = chosen;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const source = image.currentSrc || image.src;
|
|
157
|
+
try {
|
|
158
|
+
const kept = localStorage.getItem(KEY + source);
|
|
159
|
+
if (kept) {
|
|
160
|
+
image.style.objectPosition = kept;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch { /* Storage can be blocked. */ }
|
|
165
|
+
const measure = () => {
|
|
166
|
+
if (!image.naturalWidth)
|
|
167
|
+
return;
|
|
168
|
+
const width = FOCUS_SAMPLE;
|
|
169
|
+
const height = Math.max(2, Math.round((image.naturalHeight / image.naturalWidth) * width));
|
|
170
|
+
const canvas = document.createElement("canvas");
|
|
171
|
+
canvas.width = width;
|
|
172
|
+
canvas.height = height;
|
|
173
|
+
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
174
|
+
if (!context)
|
|
175
|
+
return;
|
|
176
|
+
try {
|
|
177
|
+
context.drawImage(image, 0, 0, width, height);
|
|
178
|
+
const position = objectPosition(focusOf(context.getImageData(0, 0, width, height).data, width, height, 4));
|
|
179
|
+
image.style.objectPosition = position;
|
|
180
|
+
try {
|
|
181
|
+
localStorage.setItem(KEY + source, position);
|
|
182
|
+
}
|
|
183
|
+
catch { /* Storage can be blocked. */ }
|
|
184
|
+
}
|
|
185
|
+
catch { /* A picture from another host without CORS cannot be read; it keeps its middle. */ }
|
|
186
|
+
};
|
|
187
|
+
if (image.complete)
|
|
188
|
+
measure();
|
|
189
|
+
else
|
|
190
|
+
image.addEventListener("load", measure, { once: true });
|
|
191
|
+
}
|
|
192
|
+
/** Sets the focus of every picture marked `data-ds-focus` in `root`. */
|
|
193
|
+
export function startFocus(root = document) {
|
|
194
|
+
for (const image of root.querySelectorAll("img[data-ds-focus]"))
|
|
195
|
+
focusImage(image);
|
|
196
|
+
}
|
package/dist/0-face/grid.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** The presses of one key, each within 800ms of the last, that toggle an overlay. */
|
|
2
|
+
export declare const GRID_PRESSES = 5;
|
|
3
|
+
/**
|
|
4
|
+
* Five presses of G toggle the grid and five of L inspect the layout, on every
|
|
5
|
+
* page that loads this module and for everyone who reads it: never put them
|
|
6
|
+
* behind a user, an owner or a development check. Escape hides both. Presses
|
|
7
|
+
* typed into a field, with a modifier or held down never count, and any other
|
|
8
|
+
* key starts the count again.
|
|
9
|
+
* A nested scrolling viewport opts in with data-ds-grid-scroll: its grid follows
|
|
10
|
+
* its content while the page grid remains aligned outside the viewport.
|
|
11
|
+
*/
|
|
2
12
|
export declare function initGridShortcut(): void;
|
|
3
13
|
//# sourceMappingURL=grid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../DS1/0-face/grid.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../DS1/0-face/grid.ts"],"names":[],"mappings":"AAIA,qFAAqF;AACrF,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAiLvC"}
|