@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
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
// ds-calendar.ts
|
|
2
|
-
// A month on whole squares: seven days across, a week to a row.
|
|
2
|
+
// A month on whole squares: seven days across, a week to a row. `view` shows
|
|
3
|
+
// one week instead (every event of each day, nothing folded behind "+N") or one
|
|
4
|
+
// day (its events without a time across the top, then its hours, one square
|
|
5
|
+
// each, with the timed events at their hour) or a swimlane (weeks across, a
|
|
6
|
+
// row to an event, each event one bar from its first week to its last);
|
|
7
|
+
// `views` puts Day, Week, Month and Swimlane in the header to change between
|
|
8
|
+
// them. An event over several days is one bar
|
|
9
|
+
// with its name written once, and words that do not fit fade out at the end.
|
|
10
|
+
// By default a
|
|
3
11
|
// day is four squares wide and four high (its date on the first square, two
|
|
4
|
-
// lines of events, one square to spare), drawn in hairline boxes
|
|
12
|
+
// lines of events, one square to spare), drawn in hairline boxes with a frame
|
|
13
|
+
// rounded more than a card's; the first week names its days inside its boxes,
|
|
14
|
+
// and a step back, Today and a step on are one plain split. `compact`
|
|
5
15
|
// makes a day one square: the small month a year is drawn from. `picker`
|
|
6
16
|
// makes the calendar a field that opens that small month below it, with the
|
|
7
17
|
// first and last day written out where they can be typed, a switch for a
|
|
@@ -13,16 +23,128 @@
|
|
|
13
23
|
// and a time, or two of them joined by a slash.
|
|
14
24
|
import { html, nothing, unsafeCSS } from "lit";
|
|
15
25
|
import { define } from "../0-face/define";
|
|
26
|
+
import { CutFades } from "../0-face/cut-fade";
|
|
16
27
|
import { getText } from "../0-face/i18n";
|
|
17
28
|
import { dateFormatter } from "../0-face/format";
|
|
18
|
-
import { addMonths, dateNumber, dayOf, eventsByDay, heatLevels, isDay, isoWeek, monthName, monthTitle, monthWeeks, sameMonth, startOfMonth, weekdayNames, } from "../0-face/calendar";
|
|
29
|
+
import { addDays, addMonths, compareDays, dateNumber, dayLabel, dayOf, eventsByDay, heatLevels, isDay, isoWeek, monthName, monthTitle, monthWeeks, sameMonth, startOfMonth, weekdayNames, weekdayOf, } from "../0-face/calendar";
|
|
19
30
|
import { CalendarBase, readMonth, readRange } from "./calendar-base";
|
|
20
31
|
import "../2-core/ds-icon";
|
|
32
|
+
import "../2-core/ds-button";
|
|
21
33
|
import metrics from "../1-root/component-metrics.css?inline";
|
|
22
34
|
import controls from "../1-root/controls.css?inline";
|
|
23
35
|
import styles from "./styles/ds-calendar.css?inline";
|
|
24
36
|
export * from "./calendar-base";
|
|
37
|
+
/** An activity day's fill: one colour, or bands side by side when several share it. */
|
|
38
|
+
function activityFill(events) {
|
|
39
|
+
if (!events.length)
|
|
40
|
+
return undefined;
|
|
41
|
+
const colours = [...new Set(events.map(event => event.color || "var(--ds-calendar-event-fill, var(--ds-apple-green))"))];
|
|
42
|
+
if (colours.length === 1)
|
|
43
|
+
return colours[0];
|
|
44
|
+
const share = 100 / colours.length;
|
|
45
|
+
return `linear-gradient(90deg, ${colours.map((colour, index) => `${colour} ${index * share}% ${(index + 1) * share}%`).join(", ")})`;
|
|
46
|
+
}
|
|
25
47
|
const whole = (value, least, most, fallback) => typeof value === "number" && Number.isFinite(value) ? Math.max(least, Math.min(most, Math.floor(value))) : fallback;
|
|
48
|
+
/** The views in the header, the shortest first, with their shared words. */
|
|
49
|
+
const VIEWS = [["day", "Day"], ["week", "Week"], ["month", "Month"], ["swimlane", "Swimlane"]];
|
|
50
|
+
const isView = (value) => VIEWS.some(([view]) => view === value);
|
|
51
|
+
/** `views` as an attribute: present and empty for every view the calendar draws, or the views to offer, in order. */
|
|
52
|
+
const viewsConverter = {
|
|
53
|
+
fromAttribute: (value) => {
|
|
54
|
+
if (value === null || value === "false")
|
|
55
|
+
return false;
|
|
56
|
+
const list = value.split(/[\s,]+/).filter(Boolean);
|
|
57
|
+
return list.length === 0 || value === "true" ? true : list;
|
|
58
|
+
},
|
|
59
|
+
toAttribute: (value) => (Array.isArray(value) ? value.join(" ") : value ? "" : null),
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Lays events out as a swimlane over `weeks` (each the first day of a week
|
|
63
|
+
* of seven): one row each, in the order `eventsByDay` lists them (by first
|
|
64
|
+
* day, the longer first), each a bar from the week holding its first day to
|
|
65
|
+
* the week holding its last, held inside the weeks drawn. Events wholly
|
|
66
|
+
* outside them are left out.
|
|
67
|
+
*/
|
|
68
|
+
export function swimlaneBars(events, weeks) {
|
|
69
|
+
if (!weeks.length)
|
|
70
|
+
return [];
|
|
71
|
+
const first = weeks[0], last = addDays(weeks.at(-1), 6);
|
|
72
|
+
const seen = new Set();
|
|
73
|
+
const ordered = [];
|
|
74
|
+
for (const list of eventsByDay(events, first, last).values())
|
|
75
|
+
for (const event of list)
|
|
76
|
+
if (!seen.has(event)) {
|
|
77
|
+
seen.add(event);
|
|
78
|
+
ordered.push(event);
|
|
79
|
+
}
|
|
80
|
+
ordered.sort((a, b) => compareDays(a.start, b.start) || compareDays(endOf(b), endOf(a)));
|
|
81
|
+
const weekOf = (day) => Math.max(0, Math.min(weeks.length - 1, Math.floor(daysBetween(first, day) / 7)));
|
|
82
|
+
return ordered.map((event, row) => ({ event, row, from: weekOf(event.start < first ? first : event.start), to: weekOf(endOf(event) > last ? last : endOf(event)) }));
|
|
83
|
+
}
|
|
84
|
+
/** An event's last day: its end, or its start for one day. */
|
|
85
|
+
const endOf = (event) => (event.end && isDay(event.end) && event.end > event.start ? event.end : event.start);
|
|
86
|
+
/** Whole days from `from` to `to`. */
|
|
87
|
+
const daysBetween = (from, to) => Math.round((Date.UTC(+to.slice(0, 4), +to.slice(5, 7) - 1, +to.slice(8, 10)) - Date.UTC(+from.slice(0, 4), +from.slice(5, 7) - 1, +from.slice(8, 10))) / 864e5);
|
|
88
|
+
/**
|
|
89
|
+
* Lays one week's events on lines, so an event over several days keeps its
|
|
90
|
+
* line and is one bar with its name written once: each event takes the
|
|
91
|
+
* lowest line free on all its days in the week, longest first as `byDay`
|
|
92
|
+
* lists them. A day whose events need more lines than `lines` keeps the last
|
|
93
|
+
* one for "+N", and a bar breaks there and goes on after it; `shown` says
|
|
94
|
+
* which days are drawn at all (a bar stops at a day that is not).
|
|
95
|
+
*/
|
|
96
|
+
export function weekLines(week, byDay, lines, shown = () => true) {
|
|
97
|
+
const lineOf = new Map();
|
|
98
|
+
const taken = week.map(() => new Set());
|
|
99
|
+
week.forEach((day, column) => {
|
|
100
|
+
for (const event of byDay.get(day) ?? []) {
|
|
101
|
+
if (lineOf.has(event))
|
|
102
|
+
continue;
|
|
103
|
+
const columns = [];
|
|
104
|
+
for (let next = column; next < week.length && (byDay.get(week[next]) ?? []).includes(event); next++)
|
|
105
|
+
columns.push(next);
|
|
106
|
+
let line = 0;
|
|
107
|
+
while (columns.some(next => taken[next].has(line)))
|
|
108
|
+
line++;
|
|
109
|
+
lineOf.set(event, line);
|
|
110
|
+
for (const next of columns)
|
|
111
|
+
taken[next].add(line);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// How many lines each day draws: all of them, or one fewer for "+N".
|
|
115
|
+
const room = week.map(day => {
|
|
116
|
+
if (!shown(day))
|
|
117
|
+
return 0;
|
|
118
|
+
const events = byDay.get(day) ?? [];
|
|
119
|
+
const deepest = Math.max(-1, ...events.map(event => lineOf.get(event)));
|
|
120
|
+
return deepest < lines ? lines : Math.max(0, lines - 1);
|
|
121
|
+
});
|
|
122
|
+
return week.map((day, column) => {
|
|
123
|
+
const events = byDay.get(day) ?? [];
|
|
124
|
+
const drawn = [];
|
|
125
|
+
for (let line = 0; line < room[column]; line++) {
|
|
126
|
+
const event = events.find(candidate => lineOf.get(candidate) === line);
|
|
127
|
+
if (!event) {
|
|
128
|
+
drawn.push(null);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const before = column > 0 && line < room[column - 1] && (byDay.get(week[column - 1]) ?? []).includes(event);
|
|
132
|
+
if (before) {
|
|
133
|
+
drawn.push("on");
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
let span = 1;
|
|
137
|
+
while (column + span < week.length && line < room[column + span] && (byDay.get(week[column + span]) ?? []).includes(event))
|
|
138
|
+
span++;
|
|
139
|
+
drawn.push({ event, span });
|
|
140
|
+
}
|
|
141
|
+
// Drop the empty lines at the foot, so a quiet day draws nothing under its date.
|
|
142
|
+
while (drawn.length && drawn.at(-1) === null)
|
|
143
|
+
drawn.pop();
|
|
144
|
+
const hidden = room[column] < lines ? events.filter(event => lineOf.get(event) >= room[column]).length : 0;
|
|
145
|
+
return { lines: drawn, hidden };
|
|
146
|
+
});
|
|
147
|
+
}
|
|
26
148
|
const TIME = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
27
149
|
/** Reads a value: `2026-10-21`, `2026-10-21T14:30`, or two of them joined by `/`. */
|
|
28
150
|
export function readDateValue(value) {
|
|
@@ -73,12 +195,38 @@ const openPickers = new Set();
|
|
|
73
195
|
* small month.
|
|
74
196
|
* @prop {number} dayWidth - Squares per day (`day-width`): 4 by default, 1
|
|
75
197
|
* when compact.
|
|
198
|
+
* @prop {string} view - `month` (the default), `week`, `day` or `swimlane`:
|
|
199
|
+
* the weeks from the month shown across (a week half a day wide, so it is
|
|
200
|
+
* as wide as the month), each event one row with one bar from its first
|
|
201
|
+
* week to its last. A compact calendar and a picker are always a month.
|
|
202
|
+
* @prop {boolean | string[]} views - Day, Week, Month and Swimlane in the
|
|
203
|
+
* header, to change `view`; or the views to offer, in order
|
|
204
|
+
* (`views="month swimlane"`). A name the calendar does not draw is the
|
|
205
|
+
* page's own view: chosen, the calendar keeps its header (the month's title,
|
|
206
|
+
* the arrows moving a month) and shows what the page puts in its slot of
|
|
207
|
+
* that name (`<div slot="earnings">`) in place of the days.
|
|
208
|
+
* @prop {Record<string, string>} viewNames - The words for each view in the
|
|
209
|
+
* switch (property only), over the shared Day, Week, Month and Swimlane;
|
|
210
|
+
* a page's own view is named by its name when left out.
|
|
211
|
+
* @prop {string} date - The day the week or day view shows, `YYYY-MM-DD`;
|
|
212
|
+
* today, or the first of the month shown, by default.
|
|
76
213
|
* @prop {number} lines - Lines of events under a day's date: 2 by default.
|
|
77
214
|
* @prop {boolean} weekNumbers - Write the week's number (`week-numbers`) on
|
|
78
215
|
* its first day.
|
|
79
|
-
* @prop {boolean} fixed - Always draw six weeks, so the month keeps its height
|
|
216
|
+
* @prop {boolean} fixed - Always draw six weeks, so the month keeps its height,
|
|
217
|
+
* and every other view stands in that same height (the weekdays and six
|
|
218
|
+
* weeks): the week's days grow to it, the day's hours fill it, the
|
|
219
|
+
* swimlane's rows fill it and scroll beyond it, and a page's own view gets
|
|
220
|
+
* it, so nothing under the calendar moves when the view changes.
|
|
80
221
|
* @prop {boolean} outsideDays - Draw the days of the months before and after
|
|
81
222
|
* in the title grey (`outside-days`); pressing one moves there.
|
|
223
|
+
* @prop {boolean} activity - The days as quiet squares, a contribution grid:
|
|
224
|
+
* weeks across a square each, as the swimlane runs, and the days down them,
|
|
225
|
+
* every other weekday named before them and the month over its weeks; a
|
|
226
|
+
* day on which something happens is filled with its events' colours, split
|
|
227
|
+
* into bands when several share it. Dates stay in each day's name and
|
|
228
|
+
* tooltip. Takes the place of the large calendar's months in squares.
|
|
229
|
+
* @prop {number} months - How many months activity draws from `month`: 1 by default.
|
|
82
230
|
* @prop {boolean} heat - Light each day by how much happens on it, as a
|
|
83
231
|
* contribution graph does: the events' `count`s added up (one each by
|
|
84
232
|
* default), in four steps of the busiest day shown.
|
|
@@ -87,7 +235,12 @@ const openPickers = new Set();
|
|
|
87
235
|
* by default.
|
|
88
236
|
* @prop {boolean} noHeader - Leave out the title and arrows (`no-header`).
|
|
89
237
|
* With a header, pressing the title travels by months and years: the
|
|
90
|
-
* twelve months of the year, then twelve years, and back down.
|
|
238
|
+
* twelve months of the year, then twelve years, and back down. With a
|
|
239
|
+
* header, a swipe sideways across the days (a finger or a pen), or a
|
|
240
|
+
* trackpad's sideways scroll, does what the arrows do, the next month
|
|
241
|
+
* towards the start and the one before towards the end, and stops where
|
|
242
|
+
* they stop; the days take sideways touches for it, so a carousel or a
|
|
243
|
+
* page around the calendar does not move with them.
|
|
91
244
|
* @prop {boolean} noToday - Leave out the Today button (`no-today`).
|
|
92
245
|
* @prop {string} min - The first day a person may choose.
|
|
93
246
|
* @prop {string} max - The last day a person may choose.
|
|
@@ -106,6 +259,11 @@ const openPickers = new Set();
|
|
|
106
259
|
* @prop {boolean} disabled - A picker cannot be opened.
|
|
107
260
|
* @prop {boolean} open - A picker's month is open.
|
|
108
261
|
* @prop {CalendarEvent[]} events - What happens on the days (property only).
|
|
262
|
+
* @prop {(month: Date, view: string) => string} monthHeading - Names the month view's title, and a page's own view's,
|
|
263
|
+
* (property only): given the first of the month shown, it returns the words,
|
|
264
|
+
* so a product can write "Events in October" instead of "October 2026". The
|
|
265
|
+
* week and day views, the twelve months and the twelve years keep their own
|
|
266
|
+
* titles, and the title button's label still says what it opens.
|
|
109
267
|
*
|
|
110
268
|
* @fires day-press - A day was pressed or chosen with Enter or Space;
|
|
111
269
|
* `{ day, events }`. Cancelable: cancelled, a selectable calendar keeps its value.
|
|
@@ -113,7 +271,8 @@ const openPickers = new Set();
|
|
|
113
271
|
* `{ value, previous, start, end }`, `end` empty while it is still to come.
|
|
114
272
|
* @fires input - A picker's value changed, the same moment as `change`.
|
|
115
273
|
* @fires event-press - An event was pressed; `{ event, day }`.
|
|
116
|
-
* @fires navigate - A person moved to another month; `{ month }`.
|
|
274
|
+
* @fires navigate - A person moved to another month, week or day; `{ month }`.
|
|
275
|
+
* @fires view-change - A person chose another view; `{ view }`.
|
|
117
276
|
* @fires ds-calendar-toggle - A picker's month opened or closed; `{ open }`.
|
|
118
277
|
*
|
|
119
278
|
* A selectable calendar shows Clear right under its dates while something is chosen, and `clear()`
|
|
@@ -127,6 +286,8 @@ const openPickers = new Set();
|
|
|
127
286
|
export class Calendar extends CalendarBase {
|
|
128
287
|
constructor() {
|
|
129
288
|
super();
|
|
289
|
+
/** Words cut short (the title, a weekday, the picker's value, an event's name on its bar) fade over their last square, never "…": marks them `data-cut="end"` while they do not fit. */
|
|
290
|
+
this.cuts = new CutFades(this, { selector: ".title:not(.title-button), .title-text, .weekday, .trigger .text, .event .name, .swimlane-month" });
|
|
130
291
|
this.weeksRun = "rows";
|
|
131
292
|
this.byDay = new Map();
|
|
132
293
|
this.heatByDay = new Map();
|
|
@@ -136,6 +297,15 @@ export class Calendar extends CalendarBase {
|
|
|
136
297
|
this.shown = false;
|
|
137
298
|
/** Whether opening a picker should move focus into the month (a key opened it). */
|
|
138
299
|
this.focusMonth = false;
|
|
300
|
+
/** The split button's choice; its own change event stays inside, since a calendar's change is a chosen day. */
|
|
301
|
+
this.onViewChange = (event) => {
|
|
302
|
+
event.stopPropagation();
|
|
303
|
+
const view = event.detail?.value;
|
|
304
|
+
if (view && (isView(view) || this.viewChoices.includes(view)))
|
|
305
|
+
this.showView(view);
|
|
306
|
+
};
|
|
307
|
+
/** Each shown day's lines of events, laid out a week at a time in render(). */
|
|
308
|
+
this.laidOut = new Map();
|
|
139
309
|
// Travelling by months and years: the title goes up a level, a choice comes back down.
|
|
140
310
|
/** A person has moved between levels, so a level's grid fades in when it comes. */
|
|
141
311
|
this.travelled = false;
|
|
@@ -207,10 +377,50 @@ export class Calendar extends CalendarBase {
|
|
|
207
377
|
if (!target)
|
|
208
378
|
return;
|
|
209
379
|
event.preventDefault();
|
|
210
|
-
|
|
211
|
-
this.showMonth(target, true);
|
|
380
|
+
this.bringIntoView(target);
|
|
212
381
|
void this.focusCell(target);
|
|
213
382
|
};
|
|
383
|
+
this.swipedAt = 0;
|
|
384
|
+
this.wheel = { dx: 0, at: 0, locked: 0 };
|
|
385
|
+
this.onSwipeStart = (event) => {
|
|
386
|
+
this.swipe = event.pointerType === "mouse" || !event.isPrimary ? undefined : { id: event.pointerId, x: event.clientX, y: event.clientY, at: event.timeStamp };
|
|
387
|
+
};
|
|
388
|
+
this.onSwipeEnd = (event) => {
|
|
389
|
+
const swipe = this.swipe;
|
|
390
|
+
this.swipe = undefined;
|
|
391
|
+
if (!swipe || event.pointerId !== swipe.id)
|
|
392
|
+
return;
|
|
393
|
+
const dx = (event.clientX - swipe.x) * (this.rtl ? -1 : 1);
|
|
394
|
+
const dy = event.clientY - swipe.y;
|
|
395
|
+
if (Math.abs(dx) < 40 || Math.abs(dx) < Math.abs(dy) * 2 || event.timeStamp - swipe.at > 800)
|
|
396
|
+
return;
|
|
397
|
+
// A day the swipe started on is not pressed by it.
|
|
398
|
+
if (this.swipeTo(dx < 0 ? 1 : -1))
|
|
399
|
+
this.swipedAt = Date.now();
|
|
400
|
+
};
|
|
401
|
+
this.onSwipeWheel = (event) => {
|
|
402
|
+
if (Math.abs(event.deltaX) <= Math.abs(event.deltaY))
|
|
403
|
+
return;
|
|
404
|
+
event.preventDefault();
|
|
405
|
+
const now = Date.now();
|
|
406
|
+
if (now < this.wheel.locked)
|
|
407
|
+
return;
|
|
408
|
+
if (now - this.wheel.at > 200)
|
|
409
|
+
this.wheel.dx = 0;
|
|
410
|
+
this.wheel.at = now;
|
|
411
|
+
this.wheel.dx += event.deltaX * (this.rtl ? -1 : 1);
|
|
412
|
+
if (Math.abs(this.wheel.dx) < 60)
|
|
413
|
+
return;
|
|
414
|
+
const direction = this.wheel.dx > 0 ? 1 : -1;
|
|
415
|
+
this.wheel = { dx: 0, at: 0, locked: now + 500 };
|
|
416
|
+
this.swipeTo(direction);
|
|
417
|
+
};
|
|
418
|
+
this.onSwipeClick = (event) => {
|
|
419
|
+
if (Date.now() - this.swipedAt > 400)
|
|
420
|
+
return;
|
|
421
|
+
event.preventDefault();
|
|
422
|
+
event.stopImmediatePropagation();
|
|
423
|
+
};
|
|
214
424
|
this.onClick = (event) => {
|
|
215
425
|
const path = event.composedPath();
|
|
216
426
|
const find = (selector) => path.find(node => node instanceof HTMLElement && node.matches(selector));
|
|
@@ -233,8 +443,7 @@ export class Calendar extends CalendarBase {
|
|
|
233
443
|
this.focusDay = day;
|
|
234
444
|
this.press(day);
|
|
235
445
|
// A day of the month before or after takes the calendar there.
|
|
236
|
-
|
|
237
|
-
this.showMonth(day, true);
|
|
446
|
+
this.bringIntoView(day);
|
|
238
447
|
};
|
|
239
448
|
/** While a range waits for its end, the day under the pointer previews it. */
|
|
240
449
|
this.onPointerOver = (event) => {
|
|
@@ -249,7 +458,7 @@ export class Calendar extends CalendarBase {
|
|
|
249
458
|
if (this.unfolded && !(event.relatedTarget instanceof Node && this.renderRoot.contains(event.relatedTarget)))
|
|
250
459
|
this.unfolded = undefined;
|
|
251
460
|
};
|
|
252
|
-
/**
|
|
461
|
+
/** Directly against the field, or above when there is more room there; held inside the screen. */
|
|
253
462
|
this.place = () => {
|
|
254
463
|
const panel = this.panel, trigger = this.trigger;
|
|
255
464
|
if (!this.shown || !panel || !trigger)
|
|
@@ -260,7 +469,7 @@ export class Calendar extends CalendarBase {
|
|
|
260
469
|
const left = viewport?.offsetLeft ?? 0, top = viewport?.offsetTop ?? 0;
|
|
261
470
|
const width = viewport?.width ?? view.innerWidth, height = viewport?.height ?? view.innerHeight;
|
|
262
471
|
const box = panel.getBoundingClientRect();
|
|
263
|
-
const gap =
|
|
472
|
+
const gap = 0;
|
|
264
473
|
// The face is one control high at the foot of its square: measure from that square.
|
|
265
474
|
const square = Math.max(rect.height, gap * 2);
|
|
266
475
|
const foot = rect.bottom, head = rect.bottom - square;
|
|
@@ -336,11 +545,14 @@ export class Calendar extends CalendarBase {
|
|
|
336
545
|
};
|
|
337
546
|
this.compact = false;
|
|
338
547
|
this.weekNumbers = false;
|
|
548
|
+
this.view = "month";
|
|
549
|
+
this.views = false;
|
|
339
550
|
this.fixed = false;
|
|
340
551
|
this.outsideDays = false;
|
|
341
552
|
this.noHeader = false;
|
|
342
553
|
this.noToday = false;
|
|
343
554
|
this.heat = false;
|
|
555
|
+
this.activity = false;
|
|
344
556
|
this.picker = false;
|
|
345
557
|
this.time = false;
|
|
346
558
|
this.required = false;
|
|
@@ -377,6 +589,79 @@ export class Calendar extends CalendarBase {
|
|
|
377
589
|
eventsOn(day) {
|
|
378
590
|
return this.byDay.get(day) ?? [];
|
|
379
591
|
}
|
|
592
|
+
/** The view drawn: a compact calendar and a picker are always a month. */
|
|
593
|
+
get shownView() {
|
|
594
|
+
if (this.picker || this.compact)
|
|
595
|
+
return "month";
|
|
596
|
+
if (isView(this.view))
|
|
597
|
+
return this.view;
|
|
598
|
+
return this.viewChoices.includes(this.view) ? this.view : "month";
|
|
599
|
+
}
|
|
600
|
+
/** The views offered in the header, in order: every one the calendar draws, or the page's list. */
|
|
601
|
+
get viewChoices() {
|
|
602
|
+
const views = this.views;
|
|
603
|
+
if (Array.isArray(views))
|
|
604
|
+
return [...new Set(views.map(view => String(view).trim()).filter(Boolean))];
|
|
605
|
+
return views ? VIEWS.map(([view]) => view) : [];
|
|
606
|
+
}
|
|
607
|
+
/** Whether the view shown is the page's own, drawn in its slot. */
|
|
608
|
+
get ownView() {
|
|
609
|
+
return !isView(this.shownView);
|
|
610
|
+
}
|
|
611
|
+
/** A view's words in the switch: the page's, else the shared ones, else its name. */
|
|
612
|
+
viewName(view) {
|
|
613
|
+
const shared = VIEWS.find(([choice]) => choice === view)?.[1];
|
|
614
|
+
const word = this.viewNames?.[view] ?? (shared ? this.words(shared) : view);
|
|
615
|
+
// The switch's options are written `value:words,value:words`.
|
|
616
|
+
return word.replace(/,/g, " ");
|
|
617
|
+
}
|
|
618
|
+
/** Whether the view moves by days (a week or a day) rather than by months (a month or a swimlane). */
|
|
619
|
+
get byDays() {
|
|
620
|
+
const view = this.shownView;
|
|
621
|
+
return view === "week" || view === "day";
|
|
622
|
+
}
|
|
623
|
+
/** The day the week or day view shows: `date`, else today in the month shown, else its first. */
|
|
624
|
+
get shownDay() {
|
|
625
|
+
if (isDay(this.date))
|
|
626
|
+
return this.date;
|
|
627
|
+
const month = this.shownMonth;
|
|
628
|
+
return sameMonth(this.todayDay, month) ? this.todayDay : month;
|
|
629
|
+
}
|
|
630
|
+
/** The seven days of the week `day` falls in. */
|
|
631
|
+
weekOf(day) {
|
|
632
|
+
const start = addDays(day, -((weekdayOf(day) - this.firstDay + 7) % 7));
|
|
633
|
+
return Array.from({ length: 7 }, (_, index) => addDays(start, index));
|
|
634
|
+
}
|
|
635
|
+
/** Shows another week or day around `day`, and says so with `navigate`. */
|
|
636
|
+
showDay(day, announce = false) {
|
|
637
|
+
if (!isDay(day) || day === this.date)
|
|
638
|
+
return;
|
|
639
|
+
this.date = day;
|
|
640
|
+
this.month = day.slice(0, 7);
|
|
641
|
+
this.unfolded = undefined;
|
|
642
|
+
if (announce)
|
|
643
|
+
this.announceMonth(day);
|
|
644
|
+
}
|
|
645
|
+
/** Changes the view, as Day, Week and Month do, and says so with `view-change`. */
|
|
646
|
+
showView(view) {
|
|
647
|
+
if (view === this.shownView)
|
|
648
|
+
return;
|
|
649
|
+
if (!isDay(this.date))
|
|
650
|
+
this.date = this.shownDay;
|
|
651
|
+
this.view = view;
|
|
652
|
+
this.unfolded = undefined;
|
|
653
|
+
this.dispatchEvent(new CustomEvent("view-change", { bubbles: true, composed: true, detail: { view } }));
|
|
654
|
+
}
|
|
655
|
+
/** Brings a day into view: its month, its week or the day itself. */
|
|
656
|
+
bringIntoView(day) {
|
|
657
|
+
const view = this.shownView;
|
|
658
|
+
if (!this.byDays) {
|
|
659
|
+
if (!sameMonth(day, this.shownMonth))
|
|
660
|
+
this.showMonth(day, true);
|
|
661
|
+
}
|
|
662
|
+
else if (view === "day" || !this.weekOf(this.shownDay).includes(day))
|
|
663
|
+
this.showDay(day, true);
|
|
664
|
+
}
|
|
380
665
|
willUpdate(changed) {
|
|
381
666
|
super.willUpdate(changed);
|
|
382
667
|
this.style.setProperty("--ds-calendar-day-squares", String(this.squaresPerDay));
|
|
@@ -397,6 +682,14 @@ export class Calendar extends CalendarBase {
|
|
|
397
682
|
}
|
|
398
683
|
updated(changed) {
|
|
399
684
|
super.updated(changed);
|
|
685
|
+
// A day opens its hours an hour before its first timed event, or at seven.
|
|
686
|
+
if (this.shownView === "day" && (changed.has("view") || changed.has("date") || changed.has("events"))) {
|
|
687
|
+
const hours = this.renderRoot.querySelector(".hours");
|
|
688
|
+
const first = hours?.querySelector(".hour[data-busy]")?.dataset.hour;
|
|
689
|
+
const open = hours?.querySelector(`.hour[data-hour="${Math.max(0, (first ? Number(first) : 8) - 1)}"]`);
|
|
690
|
+
if (hours && open)
|
|
691
|
+
hours.scrollTop = open.offsetTop;
|
|
692
|
+
}
|
|
400
693
|
if (changed.has("value") || changed.has("required")) {
|
|
401
694
|
this.internals?.setFormValue(this.value || null);
|
|
402
695
|
if (this.required && !this.value)
|
|
@@ -433,6 +726,8 @@ export class Calendar extends CalendarBase {
|
|
|
433
726
|
showToday() {
|
|
434
727
|
this.level = "days";
|
|
435
728
|
this.showMonth(this.todayDay, true);
|
|
729
|
+
if (this.shownView !== "month")
|
|
730
|
+
this.showDay(this.todayDay, true);
|
|
436
731
|
this.focusDay = this.todayDay;
|
|
437
732
|
}
|
|
438
733
|
/** Empties the value, as Clear does, and says so with `change`. */
|
|
@@ -475,8 +770,12 @@ export class Calendar extends CalendarBase {
|
|
|
475
770
|
}
|
|
476
771
|
/** The arrows: a month among the days, a year among the months, twelve years among the years. */
|
|
477
772
|
step(direction) {
|
|
478
|
-
if (this.level === "days")
|
|
773
|
+
if (this.level === "days") {
|
|
774
|
+
const view = this.shownView;
|
|
775
|
+
if (this.byDays)
|
|
776
|
+
return this.showDay(addDays(this.shownDay, direction * (view === "week" ? 7 : 1)), true);
|
|
479
777
|
return direction < 0 ? this.previousMonth() : this.nextMonth();
|
|
778
|
+
}
|
|
480
779
|
this.browseYear += direction * (this.level === "months" ? 1 : 12);
|
|
481
780
|
if (this.level === "years")
|
|
482
781
|
this.pickFocus = (this.pickFocus ?? this.browseYear) + direction * 12;
|
|
@@ -494,6 +793,8 @@ export class Calendar extends CalendarBase {
|
|
|
494
793
|
const month = `${String(this.browseYear).padStart(4, "0")}-${String(value + 1).padStart(2, "0")}-01`;
|
|
495
794
|
this.level = "days";
|
|
496
795
|
this.showMonth(month, true);
|
|
796
|
+
if (this.shownView !== "month")
|
|
797
|
+
this.showDay(month, false);
|
|
497
798
|
const day = [this.focusDay, this.chosen.start, this.todayDay].find(day => day && sameMonth(day, month)) ?? month;
|
|
498
799
|
void this.focusCell(day);
|
|
499
800
|
}
|
|
@@ -567,6 +868,16 @@ export class Calendar extends CalendarBase {
|
|
|
567
868
|
return day;
|
|
568
869
|
return month;
|
|
569
870
|
}
|
|
871
|
+
swipeTo(direction) {
|
|
872
|
+
const arrow = this.renderRoot.querySelector(`.header [part~="${direction < 0 ? "previous" : "next"}"]`);
|
|
873
|
+
if (!arrow || arrow.disabled)
|
|
874
|
+
return false;
|
|
875
|
+
this.step(direction);
|
|
876
|
+
return true;
|
|
877
|
+
}
|
|
878
|
+
get rtl() {
|
|
879
|
+
return getComputedStyle(this).direction === "rtl";
|
|
880
|
+
}
|
|
570
881
|
renderHeader() {
|
|
571
882
|
if (this.noHeader)
|
|
572
883
|
return nothing;
|
|
@@ -577,26 +888,41 @@ export class Calendar extends CalendarBase {
|
|
|
577
888
|
const level = this.level;
|
|
578
889
|
const year = this.browseYear;
|
|
579
890
|
const span = this.yearSpan;
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
? [
|
|
583
|
-
:
|
|
584
|
-
|
|
585
|
-
|
|
891
|
+
const view = this.shownView;
|
|
892
|
+
const labels = level === "days" && this.byDays
|
|
893
|
+
? view === "week" ? ["Previous week", "Next week"] : ["Previous day", "Next day"]
|
|
894
|
+
: { days: ["Previous month", "Next month"], months: ["Previous year", "Next year"], years: ["Earlier years", "Later years"] }[level];
|
|
895
|
+
const shownDays = view === "week" ? this.weekOf(this.shownDay) : [this.shownDay];
|
|
896
|
+
const blocked = level === "days" && this.byDays
|
|
897
|
+
? [Boolean(min && addDays(shownDays[0], -1) < min), Boolean(max && addDays(shownDays.at(-1), 1) > max)]
|
|
898
|
+
: level === "days"
|
|
899
|
+
? [before, after]
|
|
900
|
+
: level === "months"
|
|
901
|
+
? [Boolean(min && year - 1 < Number(min.slice(0, 4))), Boolean(max && year + 1 > Number(max.slice(0, 4)))]
|
|
902
|
+
: [Boolean(min && span[0] - 1 < Number(min.slice(0, 4))), Boolean(max && span[0] + 12 > Number(max.slice(0, 4)))];
|
|
586
903
|
const arrow = (which) => html `<button
|
|
587
|
-
class="
|
|
904
|
+
class="nav"
|
|
588
905
|
part=${which}
|
|
589
906
|
type="button"
|
|
590
907
|
aria-label=${this.words(labels[which === "previous" ? 0 : 1])}
|
|
591
908
|
?disabled=${blocked[which === "previous" ? 0 : 1]}
|
|
592
909
|
@click=${() => this.step(which === "previous" ? -1 : 1)}
|
|
593
|
-
><ds-icon type=${which === "previous" ? "
|
|
910
|
+
><ds-icon type=${(this.compact ? "chevron-" : "") + (which === "previous" ? "left" : "right")} size=${this.compact ? "large" : nothing} aria-hidden="true"></ds-icon></button>`;
|
|
594
911
|
const title = level === "days"
|
|
595
|
-
?
|
|
912
|
+
? view === "week"
|
|
913
|
+
? this.rangeTitle(shownDays[0], shownDays[6])
|
|
914
|
+
: view === "day"
|
|
915
|
+
? dayLabel(this.shownDay)
|
|
916
|
+
: view === "swimlane"
|
|
917
|
+
? this.monthRangeTitle(this.swimlaneWeeks)
|
|
918
|
+
: this.monthHeading
|
|
919
|
+
? this.monthHeading(new Date(Number(month.slice(0, 4)), Number(month.slice(5, 7)) - 1, 1), view)
|
|
920
|
+
: monthTitle(month, this.compact ? "short" : "long")
|
|
596
921
|
: level === "months"
|
|
597
922
|
? this.yearName(year)
|
|
598
923
|
: `${this.yearName(span[0])} – ${this.yearName(span[0] + 11)}`;
|
|
599
|
-
|
|
924
|
+
const switchable = this.viewChoices.length > 1 && !this.compact && !this.picker;
|
|
925
|
+
return html `<div class="header" part="header" ?data-views=${switchable}>
|
|
600
926
|
${level === "years"
|
|
601
927
|
? html `<span class="title" id="title" aria-live="polite">${title}</span>`
|
|
602
928
|
: html `<button
|
|
@@ -606,26 +932,37 @@ export class Calendar extends CalendarBase {
|
|
|
606
932
|
aria-label=${`${title}, ${this.words("Choose a month and year")}`}
|
|
607
933
|
@click=${this.levelUp}
|
|
608
934
|
><span class="title-text" id="title" aria-live="polite">${title}</span></button>`}
|
|
609
|
-
|
|
610
|
-
|
|
935
|
+
${switchable ? html `<ds-button
|
|
936
|
+
class="views"
|
|
937
|
+
part="views"
|
|
938
|
+
split
|
|
939
|
+
literal
|
|
940
|
+
aria-label=${this.words("View")}
|
|
941
|
+
.options=${this.viewChoices.map(choice => `${choice}:${this.viewName(choice)}`).join(",")}
|
|
942
|
+
.value=${view}
|
|
943
|
+
@change=${this.onViewChange}
|
|
944
|
+
></ds-button>` : nothing}
|
|
945
|
+
<span class="controls" role="group" aria-label=${this.words("Date")}>
|
|
611
946
|
${arrow("previous")}
|
|
947
|
+
${this.noToday || this.squaresPerDay < 2 ? nothing : html `<button class="today-button" part="today" type="button" @click=${() => this.showToday()}>${this.words("Today")}</button>`}
|
|
612
948
|
${arrow("next")}
|
|
613
949
|
</span>
|
|
614
950
|
</div>`;
|
|
615
951
|
}
|
|
616
|
-
renderDay(day,
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
952
|
+
renderDay(day, inView = sameMonth(day, this.shownMonth), tabDay = this.tabDay, label) {
|
|
953
|
+
const outside = !inView;
|
|
954
|
+
if (outside && !this.outsideDays) {
|
|
955
|
+
return html `<div role="gridcell" class="day outside" part="day outside">${label?.weekday || label?.week
|
|
956
|
+
? html `<span class="date-line" aria-hidden="true">${this.renderLabel(label)}</span>`
|
|
957
|
+
: nothing}</div>`;
|
|
958
|
+
}
|
|
621
959
|
const events = this.eventsOn(day);
|
|
622
960
|
const lines = this.eventLines;
|
|
623
961
|
const isToday = day === this.todayDay;
|
|
624
962
|
const { selected, inside, first, last } = this.selection(day);
|
|
625
963
|
const allowed = this.allowed(day);
|
|
626
964
|
const unfolded = this.unfolded === day;
|
|
627
|
-
const
|
|
628
|
-
const hidden = events.length - shown.length;
|
|
965
|
+
const laid = this.laidOut.get(day) ?? { lines: [], hidden: 0 };
|
|
629
966
|
const heat = this.heatByDay.get(day);
|
|
630
967
|
const parts = ["day", isToday ? "today" : "", selected ? "selected" : "", heat ? "heat" : ""].filter(Boolean).join(" ");
|
|
631
968
|
return html `<div
|
|
@@ -633,7 +970,7 @@ export class Calendar extends CalendarBase {
|
|
|
633
970
|
class="day"
|
|
634
971
|
part=${parts}
|
|
635
972
|
data-day=${day}
|
|
636
|
-
tabindex=${!outside && day ===
|
|
973
|
+
tabindex=${!outside && day === tabDay ? 0 : -1}
|
|
637
974
|
aria-label=${this.cellLabel(day, events)}
|
|
638
975
|
aria-selected=${this.selectable ? String(selected || inside) : nothing}
|
|
639
976
|
aria-current=${isToday ? "date" : nothing}
|
|
@@ -649,29 +986,302 @@ export class Calendar extends CalendarBase {
|
|
|
649
986
|
?data-open=${unfolded}
|
|
650
987
|
>
|
|
651
988
|
<span class="date-line" aria-hidden="true">
|
|
652
|
-
${
|
|
989
|
+
${label ? this.renderLabel(label) : nothing}
|
|
653
990
|
<span class="date">${dateNumber(day)}</span>
|
|
654
991
|
</span>
|
|
655
992
|
${lines > 0 && events.length
|
|
656
993
|
? html `<span class="events" aria-hidden="true">
|
|
657
|
-
${
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
${hidden > 0 && !unfolded ? html `<span class="more" part="more" data-more>+${hidden}</span>` : nothing}
|
|
994
|
+
${unfolded
|
|
995
|
+
? events.map(event => this.renderEvent(event, events, 1))
|
|
996
|
+
: laid.lines.map(line => line === null || line === "on"
|
|
997
|
+
? html `<span class="line" data-line=${line ?? "empty"}></span>`
|
|
998
|
+
: this.renderEvent(line.event, events, line.span))}
|
|
999
|
+
${laid.hidden > 0 && !unfolded ? html `<span class="more" part="more" data-more>+${laid.hidden}</span>` : nothing}
|
|
664
1000
|
</span>`
|
|
665
1001
|
: nothing}
|
|
666
1002
|
</div>`;
|
|
667
1003
|
}
|
|
1004
|
+
/** What a day writes before its date: its weekday's name in the first week, and the week's number on its first day. */
|
|
1005
|
+
renderLabel(label) {
|
|
1006
|
+
return html `${label.weekday ? html `<span class="weekday-name" ?data-today=${label.today}>${label.weekday}</span>` : nothing}${label.week
|
|
1007
|
+
? html `<span class="week-number">${this.words("W{week}", { week: label.week })}</span>`
|
|
1008
|
+
: nothing}`;
|
|
1009
|
+
}
|
|
1010
|
+
/** A week's days as one title: "Oct 18 – 24, 2026", in the language's own way. */
|
|
1011
|
+
rangeTitle(from, to) {
|
|
1012
|
+
const format = dateFormatter({ month: "short", day: "numeric", year: "numeric", timeZone: "UTC" });
|
|
1013
|
+
const at = (day) => Date.UTC(Number(day.slice(0, 4)), Number(day.slice(5, 7)) - 1, Number(day.slice(8, 10)), 12);
|
|
1014
|
+
return typeof format.formatRange === "function" ? format.formatRange(at(from), at(to)) : `${format.format(at(from))} – ${format.format(at(to))}`;
|
|
1015
|
+
}
|
|
1016
|
+
/** The first day of each week a swimlane draws: from the week holding the month's first, a week to each square the month has across. */
|
|
1017
|
+
get swimlaneWeeks() {
|
|
1018
|
+
const first = this.shownMonth;
|
|
1019
|
+
const start = addDays(first, -((weekdayOf(first) - this.firstDay + 7) % 7));
|
|
1020
|
+
const count = Math.max(4, 7 * this.squaresPerDay);
|
|
1021
|
+
return Array.from({ length: count }, (_, index) => addDays(start, index * 7));
|
|
1022
|
+
}
|
|
1023
|
+
/** The month owning most of a week: its Thursday's, counted from the week's first day. */
|
|
1024
|
+
ownerOf(weekStart) {
|
|
1025
|
+
return startOfMonth(addDays(weekStart, 3));
|
|
1026
|
+
}
|
|
1027
|
+
/** The months a swimlane covers as one title: "Oct 2026 – Jan 2027". */
|
|
1028
|
+
monthRangeTitle(weeks) {
|
|
1029
|
+
const from = this.ownerOf(weeks[0]), to = this.ownerOf(weeks.at(-1));
|
|
1030
|
+
const format = dateFormatter({ month: "short", year: "numeric", timeZone: "UTC" });
|
|
1031
|
+
const at = (day) => Date.UTC(Number(day.slice(0, 4)), Number(day.slice(5, 7)) - 1, 15);
|
|
1032
|
+
if (from === to)
|
|
1033
|
+
return monthTitle(from);
|
|
1034
|
+
return typeof format.formatRange === "function" ? format.formatRange(at(from), at(to)) : `${format.format(at(from))} – ${format.format(at(to))}`;
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* The events as a swimlane: weeks across, a square each; over them the
|
|
1038
|
+
* months, named where the month owning the week changes, and each week's
|
|
1039
|
+
* first date (today's date in its disc on today's week); then a row to an
|
|
1040
|
+
* event, a square high, each one bar from its first week to its last.
|
|
1041
|
+
*/
|
|
1042
|
+
renderSwimlane() {
|
|
1043
|
+
const weeks = this.swimlaneWeeks;
|
|
1044
|
+
const bars = swimlaneBars(this.events ?? [], weeks);
|
|
1045
|
+
// Fixed, the rows (a square each) fill the month's height under the months and dates, and scroll past it.
|
|
1046
|
+
const fit = this.fixed ? Math.max(1, 6 * (this.eventLines + 2) - 1) : 6;
|
|
1047
|
+
const rows = Math.max(fit, bars.length + 1);
|
|
1048
|
+
const today = this.todayDay;
|
|
1049
|
+
const todayWeek = weeks.findIndex(start => today >= start && today <= addDays(start, 6));
|
|
1050
|
+
const months = [];
|
|
1051
|
+
weeks.forEach((start, column) => {
|
|
1052
|
+
const month = this.ownerOf(start);
|
|
1053
|
+
const last = months.at(-1);
|
|
1054
|
+
if (last && last.month === month)
|
|
1055
|
+
last.span++;
|
|
1056
|
+
else
|
|
1057
|
+
months.push({ column, span: 1, month });
|
|
1058
|
+
});
|
|
1059
|
+
const range = (event) => {
|
|
1060
|
+
const end = event.end && isDay(event.end) && event.end > event.start ? event.end : event.start;
|
|
1061
|
+
return end === event.start ? dayLabel(event.start) : this.rangeTitle(event.start, end);
|
|
1062
|
+
};
|
|
1063
|
+
return this.swipeFrame(html `<div
|
|
1064
|
+
class="swimlane"
|
|
1065
|
+
part="swimlane"
|
|
1066
|
+
role="group"
|
|
1067
|
+
?data-travel=${this.travelled}
|
|
1068
|
+
aria-label=${this.nameOr(this.monthRangeTitle(weeks))}
|
|
1069
|
+
style=${`--ds-calendar-weeks: ${weeks.length}; --ds-calendar-rows: ${rows}; --ds-calendar-fit: ${fit}`}
|
|
1070
|
+
>
|
|
1071
|
+
<div class="swimlane-months" part="months" aria-hidden="true">
|
|
1072
|
+
${months.map(({ column, span, month }, index) => html `<span class="swimlane-month" style=${`grid-column: ${column + 1} / span ${span}`}>${index === 0 || month.slice(5, 7) === "01" ? monthTitle(month, "short") : monthName(month, "short")}</span>`)}
|
|
1073
|
+
</div>
|
|
1074
|
+
<div class="swimlane-dates" part="dates" aria-hidden="true">
|
|
1075
|
+
${weeks.map((start, column) => column === todayWeek
|
|
1076
|
+
? html `<span class="swimlane-date" data-today><span class="date">${dateNumber(today)}</span></span>`
|
|
1077
|
+
: html `<span class="swimlane-date"><span class="date">${dateNumber(start)}</span></span>`)}
|
|
1078
|
+
</div>
|
|
1079
|
+
<div class="swimlane-scroll" part="scroll"><div class="swimlane-grid" part="grid">
|
|
1080
|
+
${Array.from({ length: rows }, (_, row) => weeks.map((_, column) => html `<span
|
|
1081
|
+
class="cell"
|
|
1082
|
+
aria-hidden="true"
|
|
1083
|
+
style=${`grid-row: ${row + 1}; grid-column: ${column + 1}`}
|
|
1084
|
+
?data-first-row=${row === 0}
|
|
1085
|
+
?data-last-row=${row === rows - 1}
|
|
1086
|
+
?data-first-column=${column === 0}
|
|
1087
|
+
?data-last-column=${column === weeks.length - 1}
|
|
1088
|
+
></span>`))}
|
|
1089
|
+
${bars.map(({ event, row, from, to }, index) => {
|
|
1090
|
+
const fill = event.color ? `--ds-calendar-event-fill: ${event.color}; --ds-calendar-event-ink: var(--ds-slate); ` : "";
|
|
1091
|
+
return html `<button
|
|
1092
|
+
type="button"
|
|
1093
|
+
class="event"
|
|
1094
|
+
part="event"
|
|
1095
|
+
data-event=${index}
|
|
1096
|
+
aria-label=${`${event.title}, ${range(event)}`}
|
|
1097
|
+
style=${`${fill}grid-row: ${row + 1}; grid-column: ${from + 1} / ${to + 2}`}
|
|
1098
|
+
@click=${() => this.pressEvent(event, event.start)}
|
|
1099
|
+
><span class="name">${event.title}</span></button>`;
|
|
1100
|
+
})}
|
|
1101
|
+
</div></div>
|
|
1102
|
+
</div>`);
|
|
1103
|
+
}
|
|
1104
|
+
/** The first day of each week activity draws: from the week holding the month's first to the one holding its last month's last day. */
|
|
1105
|
+
get activityWeeks() {
|
|
1106
|
+
const first = this.shownMonth;
|
|
1107
|
+
const end = addDays(addMonths(first, whole(this.months, 1, 36, 1)), -1);
|
|
1108
|
+
const weeks = [];
|
|
1109
|
+
for (let day = addDays(first, -((weekdayOf(first) - this.firstDay + 7) % 7)); day <= end; day = addDays(day, 7))
|
|
1110
|
+
weeks.push(day);
|
|
1111
|
+
return weeks;
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* The days as quiet squares: every other weekday named down the start, the
|
|
1115
|
+
* months over their weeks, and a week to a column a square wide, its days
|
|
1116
|
+
* down it, each a square drawn two pixels in with a picture's corners,
|
|
1117
|
+
* filled with its events' colours. Days outside the months stay empty.
|
|
1118
|
+
*/
|
|
1119
|
+
renderActivity() {
|
|
1120
|
+
const weeks = this.activityWeeks;
|
|
1121
|
+
const first = this.shownMonth;
|
|
1122
|
+
const end = addMonths(first, whole(this.months, 1, 36, 1));
|
|
1123
|
+
this.byDay = eventsByDay(this.events ?? [], weeks[0], addDays(weeks.at(-1), 6));
|
|
1124
|
+
const short = weekdayNames(this.firstDay, "short");
|
|
1125
|
+
const narrow = weekdayNames(this.firstDay, "narrow");
|
|
1126
|
+
const long = weekdayNames(this.firstDay, "long");
|
|
1127
|
+
const today = this.todayDay;
|
|
1128
|
+
const months = [];
|
|
1129
|
+
// A week is named by the month owning most of it, held to the months drawn.
|
|
1130
|
+
const lastMonth = addMonths(end, -1);
|
|
1131
|
+
weeks.forEach((start, column) => {
|
|
1132
|
+
const owner = this.ownerOf(start);
|
|
1133
|
+
const month = owner < first ? first : owner > lastMonth ? lastMonth : owner;
|
|
1134
|
+
const last = months.at(-1);
|
|
1135
|
+
if (last && last.month === month)
|
|
1136
|
+
last.span++;
|
|
1137
|
+
else
|
|
1138
|
+
months.push({ column, span: 1, month });
|
|
1139
|
+
});
|
|
1140
|
+
return html `<div class="calendar" part="calendar">
|
|
1141
|
+
${this.renderHeader()}
|
|
1142
|
+
<div class="activity" part="activity" style=${`--ds-calendar-weeks: ${weeks.length}`}>
|
|
1143
|
+
<div class="activity-rail" part="weekdays" aria-hidden="true">
|
|
1144
|
+
${short.map((name, row) => html `<span class="activity-weekday" data-narrow=${narrow[row]}>${row % 2 === 1 ? name : ""}</span>`)}
|
|
1145
|
+
</div>
|
|
1146
|
+
<div class="activity-weeks">
|
|
1147
|
+
<div class="activity-months" part="months" aria-hidden="true">
|
|
1148
|
+
${months.map(({ column, span, month }, index) => html `<span class="activity-month" style=${`grid-column: ${column + 1} / span ${span}`}>${index === 0 || month.slice(5, 7) === "01" ? monthTitle(month, "short") : monthName(month, "short")}</span>`)}
|
|
1149
|
+
</div>
|
|
1150
|
+
<div
|
|
1151
|
+
class="activity-grid"
|
|
1152
|
+
part="grid"
|
|
1153
|
+
role="grid"
|
|
1154
|
+
aria-label=${this.nameOr(months.length > 1 ? this.monthRangeTitle(weeks) : monthTitle(first))}
|
|
1155
|
+
@click=${this.onClick}
|
|
1156
|
+
>
|
|
1157
|
+
${short.map((_, row) => html `<div role="row" class="activity-row">
|
|
1158
|
+
<span role="rowheader" class="activity-hidden">${long[row]}</span>
|
|
1159
|
+
${weeks.map((start, column) => {
|
|
1160
|
+
const day = addDays(start, row);
|
|
1161
|
+
const style = `grid-row: ${row + 1}; grid-column: ${column + 1}`;
|
|
1162
|
+
if (day < first || day >= end)
|
|
1163
|
+
return html `<span role="gridcell" class="activity-day" aria-hidden="true" style=${style}></span>`;
|
|
1164
|
+
const events = this.eventsOn(day);
|
|
1165
|
+
const fill = activityFill(events);
|
|
1166
|
+
const label = this.cellLabel(day, events);
|
|
1167
|
+
const { selected } = this.selection(day);
|
|
1168
|
+
return html `<span
|
|
1169
|
+
role="gridcell"
|
|
1170
|
+
class="activity-day"
|
|
1171
|
+
part=${["day", day === today ? "today" : "", events.length ? "filled" : ""].filter(Boolean).join(" ")}
|
|
1172
|
+
data-day=${day}
|
|
1173
|
+
aria-label=${label}
|
|
1174
|
+
title=${label}
|
|
1175
|
+
aria-current=${day === today ? "date" : nothing}
|
|
1176
|
+
aria-selected=${this.selectable ? String(selected) : nothing}
|
|
1177
|
+
?data-filled=${events.length > 0}
|
|
1178
|
+
?data-selected=${selected}
|
|
1179
|
+
style=${`${style};${fill ? ` --ds-calendar-cell-fill: ${fill};` : ""}`}
|
|
1180
|
+
></span>`;
|
|
1181
|
+
})}
|
|
1182
|
+
</div>`)}
|
|
1183
|
+
</div>
|
|
1184
|
+
</div>
|
|
1185
|
+
</div>
|
|
1186
|
+
</div>`;
|
|
1187
|
+
}
|
|
1188
|
+
/** A view drawn under the header that swipes as the arrows move: the swimlane and a page's own view. */
|
|
1189
|
+
swipeFrame(content) {
|
|
1190
|
+
const swipes = !this.noHeader;
|
|
1191
|
+
return html `<div
|
|
1192
|
+
class="calendar"
|
|
1193
|
+
part="calendar"
|
|
1194
|
+
?data-swipe=${swipes}
|
|
1195
|
+
@pointerdown=${swipes ? this.onSwipeStart : nothing}
|
|
1196
|
+
@pointerup=${swipes ? this.onSwipeEnd : nothing}
|
|
1197
|
+
@pointercancel=${() => (this.swipe = undefined)}
|
|
1198
|
+
@wheel=${swipes ? this.onSwipeWheel : nothing}
|
|
1199
|
+
@click=${{ handleEvent: this.onSwipeClick, capture: true }}
|
|
1200
|
+
>
|
|
1201
|
+
${this.renderHeader()}
|
|
1202
|
+
${content}
|
|
1203
|
+
</div>`;
|
|
1204
|
+
}
|
|
1205
|
+
/** A page's own view: what it puts in the slot named after the view, as wide as the month. */
|
|
1206
|
+
renderOwnView() {
|
|
1207
|
+
const view = this.shownView;
|
|
1208
|
+
return this.swipeFrame(html `<div class="own-view" part="own-view" data-view=${view} ?data-travel=${this.travelled}><slot name=${view}></slot></div>`);
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* One day: its events without a time across the top, a day's width each,
|
|
1212
|
+
* then its hours, a square each, in an area that scrolls, with each timed
|
|
1213
|
+
* event at its hour beside the others of that hour.
|
|
1214
|
+
*/
|
|
1215
|
+
renderDayView() {
|
|
1216
|
+
const day = this.shownDay;
|
|
1217
|
+
this.byDay = eventsByDay(this.events ?? [], day, day);
|
|
1218
|
+
const events = this.eventsOn(day);
|
|
1219
|
+
const allDay = events.filter(event => !event.time);
|
|
1220
|
+
const hourName = dateFormatter({ hour: "numeric", timeZone: "UTC" });
|
|
1221
|
+
const hours = Array.from({ length: 24 }, (_, hour) => ({
|
|
1222
|
+
hour,
|
|
1223
|
+
name: hourName.format(Date.UTC(2000, 0, 1, hour)),
|
|
1224
|
+
events: events.filter(event => event.time && Number(event.time.slice(0, 2)) === hour),
|
|
1225
|
+
}));
|
|
1226
|
+
return html `<div class="calendar" part="calendar">
|
|
1227
|
+
${this.renderHeader()}
|
|
1228
|
+
${this.level !== "days" ? this.renderPicks(6) : html `<div
|
|
1229
|
+
class="day-view"
|
|
1230
|
+
part="day-view"
|
|
1231
|
+
data-day=${day}
|
|
1232
|
+
aria-label=${this.cellLabel(day, events)}
|
|
1233
|
+
@click=${this.onClick}
|
|
1234
|
+
>
|
|
1235
|
+
${allDay.length ? html `<div class="all-day" part="all-day">${allDay.map(event => this.renderEvent(event, events, 1))}</div>` : nothing}
|
|
1236
|
+
<div class="hours" part="hours">
|
|
1237
|
+
${hours.map(({ hour, name, events: atHour }) => html `<div class="hour" part="hour" data-hour=${hour} ?data-busy=${atHour.length > 0}>
|
|
1238
|
+
<span class="hour-name">${name}</span>
|
|
1239
|
+
<span class="hour-events">${atHour.map(event => this.renderEvent(event, events, 1))}</span>
|
|
1240
|
+
</div>`)}
|
|
1241
|
+
</div>
|
|
1242
|
+
</div>`}
|
|
1243
|
+
</div>`;
|
|
1244
|
+
}
|
|
1245
|
+
/** An event on its line: one bar over `span` days, its name written once. */
|
|
1246
|
+
renderEvent(event, events, span) {
|
|
1247
|
+
const fill = event.color ? `--ds-calendar-event-fill: ${event.color}; --ds-calendar-event-ink: var(--ds-slate);` : "";
|
|
1248
|
+
return html `<span
|
|
1249
|
+
class="event"
|
|
1250
|
+
part="event"
|
|
1251
|
+
data-event=${events.indexOf(event)}
|
|
1252
|
+
data-span=${span > 1 ? span : nothing}
|
|
1253
|
+
style=${fill || span > 1 ? `${fill}${span > 1 ? ` --ds-calendar-event-span: ${span}` : ""}` : nothing}
|
|
1254
|
+
>${event.time ? html `<span class="time">${event.time}</span>` : nothing}<span class="name">${event.title}</span></span>`;
|
|
1255
|
+
}
|
|
668
1256
|
render() {
|
|
669
1257
|
if (this.picker)
|
|
670
1258
|
return this.renderPicker();
|
|
1259
|
+
if (this.activity && this.level === "days")
|
|
1260
|
+
return this.renderActivity();
|
|
671
1261
|
const month = this.shownMonth;
|
|
672
1262
|
const first = this.firstDay;
|
|
673
|
-
const
|
|
1263
|
+
const view = this.shownView;
|
|
1264
|
+
if (view === "day" && this.level === "days")
|
|
1265
|
+
return this.renderDayView();
|
|
1266
|
+
if (view === "swimlane" && this.level === "days")
|
|
1267
|
+
return this.renderSwimlane();
|
|
1268
|
+
if (this.ownView && this.level === "days")
|
|
1269
|
+
return this.renderOwnView();
|
|
1270
|
+
const weeks = view === "week" ? [this.weekOf(this.shownDay)] : monthWeeks(month, first, this.fixed);
|
|
674
1271
|
this.byDay = eventsByDay(this.events ?? [], weeks[0][0], weeks.at(-1)[6]);
|
|
1272
|
+
this.laidOut = new Map();
|
|
1273
|
+
// In view: the week's days, or the month's (the days around it are drawn only with outside-days).
|
|
1274
|
+
const inView = (day) => view === "week" || sameMonth(day, month);
|
|
1275
|
+
const drawn = (day) => inView(day) || this.outsideDays;
|
|
1276
|
+
// A week shows every event of each day: as many lines as its fullest day needs.
|
|
1277
|
+
const depth = view === "week"
|
|
1278
|
+
? Math.max(this.eventLines, ...weekLines(weeks[0], this.byDay, 99).map(day => day.lines.length))
|
|
1279
|
+
: this.eventLines;
|
|
1280
|
+
for (const week of weeks)
|
|
1281
|
+
weekLines(week, this.byDay, depth, drawn).forEach((laid, column) => this.laidOut.set(week[column], laid));
|
|
1282
|
+
const tabDay = view === "week"
|
|
1283
|
+
? [this.focusDay, this.chosen.start, this.todayDay].find(day => day && weeks[0].includes(day)) ?? weeks[0][0]
|
|
1284
|
+
: this.tabDay;
|
|
675
1285
|
// Heat is measured over the days of the month shown, so the neighbours' days never set its scale.
|
|
676
1286
|
this.heatByDay = this.heat ? heatLevels(new Map([...this.byDay].filter(([day]) => sameMonth(day, month))), this.heatMax) : new Map();
|
|
677
1287
|
// A compact month names its days in a letter (one square) or two (wider); a full month in short.
|
|
@@ -681,14 +1291,33 @@ export class Calendar extends CalendarBase {
|
|
|
681
1291
|
: weekdayNames(first, "short").map(name => (/^\p{Script=Latin}/u.test(name) ? name.replace(/\.$/, "").slice(0, 2) : name))
|
|
682
1292
|
: weekdayNames(first, "short");
|
|
683
1293
|
const long = weekdayNames(first, "long");
|
|
684
|
-
|
|
1294
|
+
// Inside a day's box the name is short where the day is three squares or more, and a letter where it is narrower.
|
|
1295
|
+
const inside = this.squaresPerDay >= 3 ? short : weekdayNames(first, "narrow");
|
|
1296
|
+
const today = this.todayDay;
|
|
1297
|
+
const todayColumn = drawn(today) && weeks.some(week => week.includes(today)) ? (weekdayOf(today) - first + 7) % 7 : -1;
|
|
1298
|
+
const swipes = !this.noHeader;
|
|
1299
|
+
return html `<div
|
|
1300
|
+
class="calendar"
|
|
1301
|
+
part="calendar"
|
|
1302
|
+
?data-swipe=${swipes}
|
|
1303
|
+
@focusout=${this.onFocusOut}
|
|
1304
|
+
@pointerover=${this.onPointerOver}
|
|
1305
|
+
@pointerleave=${() => (this.hoverDay = undefined)}
|
|
1306
|
+
@pointerdown=${swipes ? this.onSwipeStart : nothing}
|
|
1307
|
+
@pointerup=${swipes ? this.onSwipeEnd : nothing}
|
|
1308
|
+
@pointercancel=${() => (this.swipe = undefined)}
|
|
1309
|
+
@wheel=${swipes ? this.onSwipeWheel : nothing}
|
|
1310
|
+
@click=${{ handleEvent: this.onSwipeClick, capture: true }}
|
|
1311
|
+
>
|
|
685
1312
|
${this.renderHeader()}
|
|
686
1313
|
${this.level !== "days" && !this.noHeader ? this.renderPicks(weeks.length) : html `<div
|
|
687
1314
|
class="grid"
|
|
688
1315
|
part="grid"
|
|
689
1316
|
role="grid"
|
|
1317
|
+
data-view=${view}
|
|
690
1318
|
?data-travel=${this.travelled}
|
|
691
|
-
aria-label=${this.nameOr(monthTitle(month))}
|
|
1319
|
+
aria-label=${this.nameOr(view === "week" ? this.rangeTitle(weeks[0][0], weeks[0][6]) : monthTitle(month))}
|
|
1320
|
+
style=${view === "week" ? `--ds-calendar-lines: ${depth}` : nothing}
|
|
692
1321
|
aria-multiselectable=${this.selectable ? "true" : nothing}
|
|
693
1322
|
@keydown=${this.onKeyDown}
|
|
694
1323
|
@click=${this.onClick}
|
|
@@ -696,7 +1325,13 @@ export class Calendar extends CalendarBase {
|
|
|
696
1325
|
<div role="row" class="weekdays" part="weekdays">
|
|
697
1326
|
${short.map((name, index) => html `<span role="columnheader" class="weekday" aria-label=${long[index]}>${name}</span>`)}
|
|
698
1327
|
</div>
|
|
699
|
-
${weeks.map(week => html `<div role="row" class="week" part="week">${week.map((day, column) => this.renderDay(day,
|
|
1328
|
+
${weeks.map((week, row) => html `<div role="row" class="week" part="week">${week.map((day, column) => this.renderDay(day, inView(day), tabDay, this.compact ? undefined : {
|
|
1329
|
+
// A full month names its days inside the first week's boxes, at their start, today's weekday in today's red.
|
|
1330
|
+
weekday: row === 0 ? inside[column] : undefined,
|
|
1331
|
+
today: row === 0 && todayColumn === column,
|
|
1332
|
+
// The week's number on its first day, counted from the week's middle so a week from Sunday takes its Monday's.
|
|
1333
|
+
week: this.weekNumbers && column === 0 && this.squaresPerDay >= 3 && week.some(drawn) ? isoWeek(addDays(day, 3)) : undefined,
|
|
1334
|
+
}))}</div>`)}
|
|
700
1335
|
</div>`}
|
|
701
1336
|
${this.renderClear()}
|
|
702
1337
|
</div>`;
|
|
@@ -943,11 +1578,17 @@ Calendar.properties = {
|
|
|
943
1578
|
dayWidth: { type: Number, attribute: "day-width" },
|
|
944
1579
|
lines: { type: Number },
|
|
945
1580
|
weekNumbers: { type: Boolean, attribute: "week-numbers", reflect: true },
|
|
1581
|
+
view: { type: String, reflect: true },
|
|
1582
|
+
views: { reflect: true, converter: viewsConverter },
|
|
1583
|
+
viewNames: { attribute: false },
|
|
1584
|
+
date: { type: String, reflect: true },
|
|
946
1585
|
fixed: { type: Boolean, reflect: true },
|
|
947
1586
|
outsideDays: { type: Boolean, attribute: "outside-days", reflect: true },
|
|
948
1587
|
noHeader: { type: Boolean, attribute: "no-header", reflect: true },
|
|
949
1588
|
noToday: { type: Boolean, attribute: "no-today", reflect: true },
|
|
950
1589
|
heat: { type: Boolean, reflect: true },
|
|
1590
|
+
activity: { type: Boolean, reflect: true },
|
|
1591
|
+
months: { type: Number },
|
|
951
1592
|
heatMax: { type: Number, attribute: "heat-max" },
|
|
952
1593
|
picker: { type: Boolean, reflect: true },
|
|
953
1594
|
name: { type: String, reflect: true },
|
|
@@ -959,6 +1600,7 @@ Calendar.properties = {
|
|
|
959
1600
|
open: { type: Boolean, reflect: true },
|
|
960
1601
|
unfolded: { state: true },
|
|
961
1602
|
embedded: { attribute: false },
|
|
1603
|
+
monthHeading: { attribute: false },
|
|
962
1604
|
level: { state: true },
|
|
963
1605
|
browseYear: { state: true },
|
|
964
1606
|
pickFocus: { state: true },
|