@livx.cc/bare-v3 0.1.0-alpha.35 → 0.1.0-alpha.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bare.css +5 -1
- package/dist/bare.min.css +1 -1
- package/dist/elements/date-picker.js +506 -0
- package/dist/manifest.json +7 -6
- package/dist/references/date-picker.md +127 -0
- package/dist/references/layout.md +1 -1
- package/dist/references/mobile.md +1 -1
- package/dist/references/page-layout.md +2 -2
- package/dist/ui.js +109 -0
- package/package.json +3 -2
package/dist/bare.css
CHANGED
|
@@ -149,6 +149,10 @@
|
|
|
149
149
|
overflow: auto;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
dialog.b3-stack > .b3-scroll {
|
|
153
|
+
min-block-size: min(6rem, 30dvh);
|
|
154
|
+
}
|
|
155
|
+
|
|
152
156
|
.b3-stack:has( > .b3-scroll) > :not(.b3-scroll) {
|
|
153
157
|
flex-shrink: 0;
|
|
154
158
|
}
|
|
@@ -1869,7 +1873,7 @@
|
|
|
1869
1873
|
max-block-size: min(85dvh, calc(100dvh - env(safe-area-inset-top, 0px) - 1rem));
|
|
1870
1874
|
overscroll-behavior: contain;
|
|
1871
1875
|
border: 1px solid var(--b3-color-border);
|
|
1872
|
-
padding: 1.5rem 1.5rem max(1.5rem, env(safe-area-inset-bottom, 0px));
|
|
1876
|
+
padding: 1.5rem min(1.5rem, 5vi) max(1.5rem, env(safe-area-inset-bottom, 0px));
|
|
1873
1877
|
background: var(--b3-color-surface);
|
|
1874
1878
|
color: var(--b3-color-text);
|
|
1875
1879
|
border-radius: 1.5rem 1.5rem 0 0;
|
package/dist/bare.min.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer bare.reset{:where(.b3-root),:where(.b3-root *){box-sizing:border-box}:where(.b3-root){font-family:var(--b3-font-body);background:var(--b3-color-canvas);color:var(--b3-color-text);color-scheme:light;margin:0;font-size:1rem;line-height:1.5}:where(.b3-root>body){margin:0}:where(.b3-root) :where(button,input,select,textarea){font:inherit}:where(.b3-root) :where(h1,h2,h3,h4,h5,h6,p){margin:0}:where(.b3-root) :where(button,a,input,select,textarea,summary,[tabindex]):focus-visible{outline:none;box-shadow:inset 0 0 0 2px}@media (forced-colors:active){:where(.b3-root) :where(button,a,input,select,textarea,summary,[tabindex]):focus-visible{outline-offset:-2px;outline:1px solid highlight}}:where(.b3-root) :where(img,svg){max-inline-size:100%}@media (prefers-reduced-motion:reduce){:where(.b3-root *),:where(.b3-root *):before,:where(.b3-root *):after{transition:none!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}[data-b3-motion=reduce] *,[data-b3-motion=reduce] :before,[data-b3-motion=reduce] :after,[data-b3-motion=reduce] ::backdrop{scroll-behavior:auto!important;transition:none!important;animation:none!important}:where(.b3-root [hidden]):not([hidden=until-found]){display:none!important}:where(.b3-root) :where(input[type=checkbox],input[type=radio],input[type=range]){accent-color:var(--b3-color-accent)}}@layer bare.tokens{.b3-root{--b3-color-canvas:#f6f5f0;--b3-color-surface:#fff;--b3-color-text:#202923;--b3-color-muted:#59655d;--b3-color-border:#d5dbd3;--b3-color-accent:#245c42;--b3-color-on-accent:#fff;--b3-color-danger:#a62c35;--b3-color-focus:#276bdd;--b3-font-body:ui-sans-serif, system-ui, sans-serif;--b3-font-display:var(--b3-font-body);--b3-radius:.75rem;--b3-space:1rem;--b3-content:68rem}.b3-root[data-b3-theme=dark]{color-scheme:dark;--b3-color-canvas:#141c19;--b3-color-surface:#202c26;--b3-color-text:#edf3ec;--b3-color-muted:#a8b9ad;--b3-color-border:#415348;--b3-color-accent:#aadbb8;--b3-color-on-accent:#132b1b;--b3-color-danger:#ffadb1;--b3-color-focus:#9ac4ff}.b3-root{--b3-space-1:.25rem;--b3-space-2:.5rem;--b3-space-3:.75rem;--b3-space-4:1rem;--b3-space-6:1.5rem;--b3-space-8:2rem;--b3-space-12:3rem;--b3-radius-small:.375rem;--b3-radius-large:1.25rem;--b3-shadow:0 8px 32px #14231b14;--b3-shadow-raised:0 16px 56px #14231b24;--b3-color-success:#256443;--b3-color-warning:#805100;--b3-color-info:#275f99;--b3-duration:.16s}.b3-root[data-b3-theme=dark]{--b3-shadow:0 8px 32px #0004;--b3-shadow-raised:0 16px 56px #0007;--b3-color-success:#99d9ab;--b3-color-warning:#f2c76c;--b3-color-info:#a2cfff}}@layer bare.layout{.b3-shell{inline-size:min(100%, var(--b3-content));margin-inline:auto;padding:clamp(1rem,4vw,3rem)}.b3-stack{gap:var(--b3-space);flex-direction:column;min-inline-size:0;display:flex}.b3-stack:where(dialog:not([open])){display:none}.b3-scroll{overscroll-behavior:contain;scrollbar-gutter:stable;flex:auto;min-block-size:0;min-inline-size:0;overflow:auto}.b3-stack:has(>.b3-scroll)>:not(.b3-scroll){flex-shrink:0}.b3-cluster{align-items:center;gap:var(--b3-space);flex-wrap:wrap;min-inline-size:0;display:flex}.b3-cluster>*,.b3-split>*{min-inline-size:0}.b3-inline{vertical-align:middle;align-items:center;gap:.5em;min-inline-size:0;max-inline-size:100%;display:inline-flex}.b3-inline>*{min-inline-size:0}.b3-grid{grid-template-columns:repeat(auto-fit, minmax(min(100%, var(--b3-grid-min,17rem)), 1fr));gap:var(--b3-space);display:grid}.b3-split{justify-content:space-between;align-items:center;gap:var(--b3-space);flex-wrap:wrap;display:flex}.b3-page{flex-direction:column;min-block-size:100svh;display:flex}.b3-page-body{flex:1;min-inline-size:0}.b3-app-layout{grid-template-columns:minmax(12rem,16rem) minmax(0,1fr);min-block-size:100svh;display:grid}.b3-sidebar{padding:var(--b3-space-6);border-inline-end:1px solid var(--b3-color-border);background:var(--b3-color-surface);min-inline-size:0}.b3-center{padding:var(--b3-space-6);place-items:center;display:grid}.b3-cover{min-block-size:min(42rem,85svh);padding-block:var(--b3-space-12);flex-direction:column;justify-content:center;display:flex}.b3-reel{gap:var(--b3-space);scroll-snap-type:x proximity;padding-block-end:var(--b3-space-2);display:flex;overflow-x:auto}.b3-reel>*{scroll-snap-align:start;flex:0 0 min(85%,20rem)}@media (width<=48rem){.b3-app-layout{grid-template-columns:minmax(0,1fr)}.b3-sidebar{border-inline-end:0;border-block-end:1px solid var(--b3-color-border)}}.b3-reel:has(>.b3-badge){scrollbar-width:none;align-items:center;gap:.5rem;padding-block:.625rem}.b3-reel:has(>.b3-badge)::-webkit-scrollbar{display:none}.b3-reel>.b3-badge{flex:none}.b3-stack>.b3-reel{flex-shrink:0}@supports (animation-timeline:scroll(self inline)){.b3-reel:has(>.b3-badge){mask-image:linear-gradient(to right, #000 calc(100% - var(--b3-reel-fade)), #0000);animation:linear both b3-reel-fade scroll(self inline)}.b3-reel:has(>.b3-badge):dir(rtl){mask-image:linear-gradient(to left, #000 calc(100% - var(--b3-reel-fade)), #0000)}@keyframes b3-reel-fade{90%{--b3-reel-fade:2.5rem}to{--b3-reel-fade:0rem}}}}@layer bare.components{.b3-title{font-family:var(--b3-font-display);letter-spacing:-.04em;overflow-wrap:anywhere;font-size:clamp(2rem,7vw,4rem);line-height:1.05}.b3-heading{font-family:var(--b3-font-display);letter-spacing:-.02em;overflow-wrap:anywhere;font-size:1.375rem;line-height:1.25}.b3-muted{color:var(--b3-color-muted)}.b3-label{letter-spacing:.06em;text-transform:uppercase;font-size:.8125rem;font-weight:650}.b3-surface{background:var(--b3-color-surface);color:var(--b3-color-text);border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);padding:clamp(1rem,3vw,2rem)}.b3-button{border-radius:var(--b3-radius);background:var(--b3-color-accent);min-block-size:2.75rem;color:var(--b3-color-on-accent);cursor:pointer;border:1px solid #0000;justify-content:center;align-items:center;gap:.5rem;padding:.625rem 1rem;font-weight:650;text-decoration:none;display:inline-flex}.b3-button :where(svg){flex-shrink:0;display:block}.b3-button>:where([aria-hidden=true]):has(>svg){flex-shrink:0}.b3-button[data-b3-emphasis=quiet]{color:var(--b3-color-text);border-color:var(--b3-color-border);background:0 0}.b3-button:disabled{opacity:.5;cursor:not-allowed}.b3-field{align-content:start;gap:.375rem;min-inline-size:0;display:grid}.b3-input{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);min-block-size:2.75rem;inline-size:100%;min-inline-size:0;color:var(--b3-color-text);padding:.625rem .75rem}.b3-error{color:var(--b3-color-danger);font-size:.875rem}select.b3-input:not([multiple]):not([size]),select.b3-input[size="1"]:not([multiple]){appearance:none;background-image:linear-gradient(45deg,#0000 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,#0000 50%);background-position:right calc(1rem + 5px) center,right 1rem center;background-repeat:no-repeat;background-size:5px 5px;padding-inline-end:2.5rem}select.b3-input:not([multiple]):not([size]):dir(rtl),select.b3-input[size="1"]:not([multiple]):dir(rtl){background-position:1rem,calc(1rem + 5px)}@media (forced-colors:active){select.b3-input:not([multiple]):not([size]),select.b3-input[size="1"]:not([multiple]){appearance:auto;background-image:none}}:where(ul,ol):has(>.b3-row){margin:0;padding-inline-start:0}.b3-row{border-block-end:1px solid var(--b3-color-border);align-items:center;gap:.75rem;padding-block:1rem;display:flex}.b3-row:where(.b3-stack){align-items:stretch;gap:var(--b3-space)}.b3-badge{overflow-wrap:anywhere;border:1px solid var(--b3-color-border);border-radius:100vmax;align-items:center;inline-size:fit-content;max-inline-size:100%;padding:.125rem .5rem;font-size:.75rem;font-weight:650;display:inline-flex}.b3-progress{block-size:.5rem;inline-size:100%;accent-color:var(--b3-color-accent)}.b3-button{transition:box-shadow var(--b3-duration), border-color var(--b3-duration)}@media (hover:hover){.b3-button:not(:disabled):hover{box-shadow:inset 0 0 0 100vmax #00000012}}.b3-button:not(:disabled):active{box-shadow:inset 0 0 0 100vmax #00000024}.b3-button[data-b3-emphasis=outline]{color:var(--b3-color-accent);background:0 0;border-color:currentColor}.b3-button[data-b3-emphasis=danger]{background:var(--b3-color-danger);color:var(--b3-color-canvas)}.b3-button[data-b3-size=small]{padding:.5rem .75rem;font-size:.875rem}.b3-button[data-b3-size=large]{min-block-size:3.25rem;padding:.875rem 1.5rem}.b3-button[aria-busy=true]{cursor:progress}.b3-icon{vertical-align:-.2em;flex:none;block-size:1.25em;inline-size:1.25em;display:inline-block}.b3-input:disabled{opacity:.6;cursor:not-allowed}.b3-input[readonly]{background:var(--b3-color-canvas)}.b3-input::placeholder{color:var(--b3-color-muted);opacity:.8}.b3-input-group{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);align-items:stretch;min-inline-size:0;display:flex;overflow:clip}.b3-input-group>.b3-input{border:0;border-radius:0;flex:1}.b3-input-group:has(>.b3-button){flex-wrap:wrap;justify-content:end}.b3-input-group:has(>.b3-button)>.b3-input{flex-basis:12ch}.b3-input-group:focus-within{outline:none;box-shadow:inset 0 0 0 2px}.b3-input-affix{color:var(--b3-color-muted);background:var(--b3-color-canvas);align-items:center;padding-inline:.75rem;display:flex}.b3-choice{cursor:pointer;align-items:start;gap:.75rem;padding-block:.5rem;display:flex}.b3-choice input{--b3-choice-control:1.125rem;inline-size:var(--b3-choice-control);block-size:var(--b3-choice-control);flex:none;margin:0;margin-block-start:max(0px, calc((1lh - var(--b3-choice-control)) / 2))}.b3-choice>.b3-switch{--b3-choice-control:1.625rem}.b3-switch{appearance:none;background:var(--b3-color-muted);border:2px solid var(--b3-color-muted);cursor:pointer;border-radius:2rem;position:relative;block-size:1.625rem!important;inline-size:2.75rem!important}.b3-switch:before{content:"";background:var(--b3-color-surface);border-radius:50%;block-size:1.125rem;inline-size:1.125rem;position:absolute;inset-block-start:.125rem;inset-inline-start:.125rem}.b3-switch:checked{background:var(--b3-color-accent);border-color:var(--b3-color-accent)}.b3-switch:checked:before{background:var(--b3-color-on-accent);inset-inline-start:calc(100% - 1.25rem)}.b3-switch:disabled{opacity:.5;cursor:not-allowed}.b3-input[type=number]{appearance:textfield}.b3-input[type=number]::-webkit-inner-spin-button,.b3-input[type=number]::-webkit-outer-spin-button{appearance:none;margin:0}.b3-input::-webkit-datetime-edit,.b3-input::-webkit-datetime-edit-fields-wrapper{padding-block:0}.b3-input-affix{white-space:nowrap}.b3-card-header,.b3-card-footer{justify-content:space-between;align-items:center;gap:var(--b3-space);flex-wrap:wrap;display:flex}.b3-card-header{margin-block-end:var(--b3-space-4)}.b3-card-footer{border-block-start:1px solid var(--b3-color-border);margin-block-start:var(--b3-space-4);padding-block-start:var(--b3-space-4)}.b3-surface[data-b3-elevation=raised]{box-shadow:var(--b3-shadow)}.b3-divider{border:0;border-block-start:1px solid var(--b3-color-border);margin-block:var(--b3-space)}.b3-alert,.b3-toast{overflow-wrap:anywhere;min-inline-size:0}.b3-alert>*,.b3-toast>*{min-inline-size:0}.b3-alert pre{max-inline-size:100%;overflow-x:auto}.b3-alert{--b3-status-color:var(--b3-color-info);border:1px solid var(--b3-status-color);border-radius:var(--b3-radius-small);color:var(--b3-color-text);background:color-mix(in srgb, var(--b3-status-color) 8%, var(--b3-color-surface));border-inline-start-width:4px;align-items:start;gap:.75rem;padding:1rem;display:flex}.b3-alert[data-b3-tone=success],.b3-badge[data-b3-tone=success]{--b3-status-color:var(--b3-color-success)}.b3-alert[data-b3-tone=warning],.b3-badge[data-b3-tone=warning]{--b3-status-color:var(--b3-color-warning)}.b3-alert[data-b3-tone=danger],.b3-badge[data-b3-tone=danger]{--b3-status-color:var(--b3-color-danger)}.b3-badge[data-b3-tone]{color:var(--b3-status-color,var(--b3-color-info));background:color-mix(in srgb, currentColor 7%, transparent);border-color:currentColor}.b3-toast-region{z-index:100;pointer-events:none;gap:.75rem;inline-size:min(24rem,100% - 2rem);display:grid;position:fixed;inset-block-end:1rem;inset-inline-end:1rem}.b3-toast{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);pointer-events:auto;flex-wrap:wrap;align-items:start;gap:1rem;padding:1rem;display:flex}.b3-toast>:not(button,.b3-button){flex:12rem}.b3-toast>:is(button,.b3-button){flex:none;max-inline-size:100%}.b3-spinner{vertical-align:-.125em;border:2px solid;border-inline-end-color:#0000;border-radius:50%;flex:none;block-size:1.125em;inline-size:1.125em;animation:.8s linear infinite b3-spin;display:inline-block}@keyframes b3-spin{to{transform:rotate(360deg)}}.b3-skeleton{background:var(--b3-color-border);border-radius:var(--b3-radius-small);min-block-size:1rem;animation:1.8s ease-in-out infinite b3-pulse}@keyframes b3-pulse{50%{opacity:.45}}:is(button,a).b3-badge{min-block-size:auto;color:var(--b3-color-text);cursor:pointer;background:0 0;gap:.25rem;text-decoration:none;position:relative}:is(button,a).b3-badge:after{content:"";position:absolute;inset:-10px 0}:is(button,a).b3-badge[data-b3-tone]{color:var(--b3-status-color,var(--b3-color-info))}:is(button,a).b3-badge:is([aria-pressed=true],[aria-current]:not([aria-current=false])){color:var(--b3-color-on-accent);background:var(--b3-color-accent);border-color:var(--b3-color-accent)}.b3-avatar{background:var(--b3-color-accent);block-size:2.5rem;inline-size:2.5rem;color:var(--b3-color-on-accent);border-radius:50%;flex:none;place-items:center;font-size:.875rem;font-weight:650;display:inline-grid;overflow:hidden}.b3-avatar>img{object-fit:cover;block-size:100%;inline-size:100%}.b3-avatar-stack{padding-inline-start:.5rem;display:flex}.b3-avatar-stack>.b3-avatar{border:2px solid var(--b3-color-surface);margin-inline-start:-.5rem}.b3-kbd{border:1px solid var(--b3-color-border);background:var(--b3-color-surface);color:var(--b3-color-muted);border-block-end-width:2px;border-radius:.25rem;padding:.15rem .35rem;font:.75rem ui-monospace,monospace}.b3-table-wrap{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);position:relative;overflow-x:auto}.b3-table{border-collapse:collapse;text-align:start;font-variant-numeric:tabular-nums;inline-size:100%}.b3-table th{color:var(--b3-color-muted);background:var(--b3-color-canvas);font-size:.75rem;font-weight:650}.b3-table :is(th,td){border-block-end:1px solid var(--b3-color-border);text-align:start;vertical-align:middle;padding:.875rem 1rem}.b3-table tbody tr:last-child td{border-block-end:0}.b3-table[data-b3-density=compact] :is(th,td){padding:.5rem .75rem}.b3-table tbody tr[aria-selected=true]{background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface))}.b3-definition{grid-template-columns:minmax(0,1fr) minmax(0,2fr);gap:.75rem 1.5rem;margin:0;display:grid;container:b3-definition/inline-size}.b3-definition dt{overflow-wrap:anywhere;min-inline-size:0;color:var(--b3-color-muted)}.b3-definition dd{overflow-wrap:anywhere;margin:0}@container b3-definition (width<=26rem){.b3-definition>:is(dt,dd){grid-column:1/-1}.b3-definition>dt:not(:first-child){margin-block-start:.75rem}}.b3-stat{gap:.5rem;display:grid}.b3-stat-value{letter-spacing:-.045em;font-variant-numeric:tabular-nums;font-size:clamp(2rem,5vw,3rem);font-weight:650;line-height:1.1}.b3-nav{border-block-end:1px solid var(--b3-color-border);flex-wrap:wrap;align-items:center;gap:.5rem;padding:.75rem;display:flex}.b3-nav[data-b3-orientation=vertical]{border-block-end:0;flex-direction:column;align-items:stretch}.b3-nav-link{border-radius:var(--b3-radius-small);min-block-size:2.75rem;color:var(--b3-color-muted);align-items:center;gap:.5rem;padding:.625rem .875rem;text-decoration:none;display:flex}.b3-nav-link[aria-current=page]{background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface));color:var(--b3-color-accent);font-weight:650}.b3-nav-link:hover{background:var(--b3-color-surface);color:var(--b3-color-text)}.b3-breadcrumbs{color:var(--b3-color-muted);flex-wrap:wrap;align-items:center;gap:.5rem;margin:0;padding:0;font-size:.875rem;list-style:none;display:flex}.b3-breadcrumbs li+li:before{content:"/";color:var(--b3-color-border);margin-inline-end:.5rem}.b3-tablist{border-block-end:1px solid var(--b3-color-border);gap:.25rem;display:flex;overflow-x:auto}.b3-tab{appearance:none;color:var(--b3-color-muted);font:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:0;border-block-end:2px solid #0000;min-block-size:2.75rem;padding:.75rem 1rem}.b3-tab[aria-selected=true]{color:var(--b3-color-accent);border-block-end-color:currentColor;font-weight:650}.b3-tab:disabled{opacity:.5;cursor:not-allowed}.b3-tabpanel{padding-block:var(--b3-space-4)}.b3-accordion{border-block-end:1px solid var(--b3-color-border)}.b3-accordion>summary{cursor:pointer;padding:1rem .25rem;font-weight:650}.b3-accordion>:not(summary){padding:0 .25rem 1rem}.b3-dropdown{display:inline-block;position:relative}.b3-dropdown>summary{list-style:none}.b3-dropdown>summary::-webkit-details-marker{display:none}.b3-dropdown-panel{z-index:20;border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);max-block-size:70svh;inline-size:max-content;min-inline-size:min(12rem,85vw);max-inline-size:min(22rem,85vw);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);padding:.5rem;position:absolute;inset-block-start:calc(100% + .5rem);inset-inline-start:0;overflow-y:auto}.b3-dialog{overscroll-behavior:contain;border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-large);background:var(--b3-color-surface);max-block-size:calc(100svh - 2rem);inline-size:min(32rem,100% - 2rem);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);padding:min(1.5rem,5vi);overflow:auto}.b3-dialog::backdrop{background:#101b17a6}.b3-dialog[data-b3-placement=end]{border-radius:0;block-size:100svh;max-block-size:100svh;inline-size:min(28rem,100%);max-inline-size:100%;margin:0;margin-inline-start:auto}@media (prefers-reduced-motion:no-preference){.b3-dialog[open]{animation:.28s cubic-bezier(.16,1,.3,1) b3-dialog-enter}.b3-dialog[open][data-b3-placement=end]{animation-name:b3-drawer-enter}.b3-dialog::backdrop,.b3-sheet::backdrop{transition:opacity .16s ease-out}.b3-dialog[data-b3-closing]::backdrop,.b3-sheet[data-b3-closing]::backdrop{opacity:0}@keyframes b3-dialog-enter{0%{opacity:0;transform:translateY(8px)scale(.96)}}@keyframes b3-drawer-enter{0%{opacity:0;translate:var(--b3-drawer-offset,1rem)}}.b3-dialog[dir=rtl][data-b3-placement=end],[dir=rtl] .b3-dialog[data-b3-placement=end]{--b3-drawer-offset:-1rem}}.b3-dialog>form{gap:var(--b3-space);flex-direction:column;margin:0;display:flex}.b3-dialog>form>header:has(>button:last-child){grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:.75rem;display:grid}.b3-dialog>form>header:has(>button:last-child)>:not(:last-child){grid-column:1;min-inline-size:0}.b3-dialog>form>header>button:last-child:not(:first-child){grid-area:1/2}.b3-dialog>form>footer{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:.75rem;display:flex}.b3-dialog>form>footer>[data-b3-emphasis=quiet]:first-child:not(:last-child){margin-inline-end:auto}.b3-tree{border-inline-start:1px solid var(--b3-color-border);padding-inline-start:1rem;list-style:none}.b3-tree summary{cursor:pointer;padding-block:.5rem}.b3-prose{overflow-wrap:anywhere;max-inline-size:65ch;line-height:1.75}.b3-prose :is(p,ul,ol,blockquote,pre){margin-block:1rem}.b3-prose :is(h1,h2,h3,h4,h5,h6){margin-block:1.75rem .75rem;line-height:1.25}.b3-prose :is(h5,h6){font-size:1em}.b3-prose>:first-child{margin-block-start:0}.b3-prose img{block-size:auto}.b3-prose blockquote{border-inline-start:3px solid var(--b3-color-accent);color:var(--b3-color-muted);margin-inline:0;padding-inline-start:1rem}.b3-prose pre{background:var(--b3-color-surface);border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-small);padding:1rem;overflow-x:auto}.b3-visually-hidden{clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;position:absolute;overflow:hidden}.b3-skip-link{z-index:1000;border-radius:var(--b3-radius-small);background:var(--b3-color-accent);max-inline-size:calc(100% - 1.5rem);color:var(--b3-color-on-accent);padding:.75rem 1rem;font-weight:650;position:fixed;inset-block-start:max(.75rem, env(safe-area-inset-top,0px));inset-inline-start:.75rem}.b3-skip-link:not(:focus){clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;padding:0;overflow:hidden}.b3-hero{grid-template-columns:repeat(2,minmax(0,1fr));align-items:center;gap:clamp(2rem,6vw,6rem);padding-block:clamp(3rem,8vw,7rem);display:grid}.b3-hero[data-b3-align=center]{text-align:center;grid-template-columns:minmax(0,1fr);justify-items:center}.b3-hero-copy{gap:1.5rem;max-inline-size:40rem;display:grid}.b3-feature{grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:center;gap:clamp(1.5rem,5vw,5rem);padding-block:clamp(2rem,6vw,5rem);display:grid}.b3-feature[data-b3-reverse=true]>:first-child{order:2}.b3-feature-icon{border-radius:var(--b3-radius);background:var(--b3-color-accent);block-size:3rem;inline-size:3rem;color:var(--b3-color-on-accent);place-items:center;display:inline-grid}.b3-pricing{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-large);background:var(--b3-color-surface);color:var(--b3-color-text);flex-direction:column;gap:1.25rem;padding:clamp(1.25rem,3vw,2rem);display:flex}.b3-pricing[data-b3-featured=true]{border:2px solid var(--b3-color-accent);box-shadow:var(--b3-shadow)}.b3-pricing>.b3-button:last-child{margin-block-start:auto}.b3-price{font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:.375rem;display:flex}.b3-price>strong{letter-spacing:-.05em;font-size:3.25rem;line-height:1.1}.b3-checklist{gap:.75rem;margin:0;padding:0;list-style:none;display:grid}.b3-checklist>li{align-items:start;gap:.625rem;display:flex}.b3-checklist>li:before{content:"✓";color:var(--b3-color-accent);font-weight:700}.b3-quote{border-inline-start:3px solid var(--b3-color-accent);margin:0;padding:1.5rem}.b3-quote blockquote{margin:0 0 1rem;font-size:1.25rem;line-height:1.5}.b3-art{isolation:isolate;border-radius:var(--b3-radius-large);background:var(--b3-color-surface);position:relative;overflow:hidden}.b3-art:before{content:"";z-index:-1;pointer-events:none;position:absolute;inset:0}.b3-art[data-b3-art=dots]:before{background-image:radial-gradient(var(--b3-color-border) 1px,transparent 1px);background-size:16px 16px}.b3-art[data-b3-art=glow]:before{background:radial-gradient(ellipse at 20% 20%,color-mix(in srgb,var(--b3-color-accent) 20%,transparent),transparent 65%)}.b3-art[data-b3-art=wash]:before{background:linear-gradient(135deg,color-mix(in srgb,var(--b3-color-accent) 14%,transparent),transparent 70%)}@media (width<=48rem){.b3-hero,.b3-feature{grid-template-columns:minmax(0,1fr)}.b3-feature[data-b3-reverse=true]>:first-child{order:initial}}.b3-reading{grid-template-columns:minmax(0,1fr) minmax(12rem,16rem);grid-template-areas:"content outline";align-items:start;gap:clamp(2rem,5vw,5rem);display:grid}.b3-reading>:not(.b3-toc){grid-area:content;min-inline-size:0}.b3-toc{max-block-size:calc(100svh - var(--b3-outline-top,1rem) - 1rem);border-inline-start:1px solid var(--b3-color-border);grid-area:outline;padding-inline-start:1rem;font-size:.875rem;position:sticky;inset-block-start:var(--b3-outline-top,1rem);overflow-y:auto}.b3-toc ol{gap:.25rem;margin:.75rem 0 0;padding:0;list-style:none;display:grid}.b3-toc ol ol{margin:.25rem 0;padding-inline-start:1rem}.b3-toc-link{border-radius:var(--b3-radius-small);color:var(--b3-color-muted);overflow-wrap:anywhere;padding:.625rem .75rem;text-decoration:none;display:block}.b3-toc-link:hover{color:var(--b3-color-text);background:var(--b3-color-surface)}.b3-toc-link[aria-current=location]{color:var(--b3-color-accent);background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface));font-weight:650}@media (width<=48rem){.b3-reading{grid-template-columns:minmax(0,1fr);grid-template-areas:"outline""content";gap:2rem}.b3-toc{max-block-size:none;position:static}}.b3-command{inline-size:min(38rem,100% - 2rem);padding:0}.b3-command-search{border-block-end:1px solid var(--b3-color-border);align-items:center;gap:.75rem;padding:1rem;display:flex}.b3-command-search>input{flex:1;min-inline-size:0}.b3-command-list{overscroll-behavior:contain;max-block-size:50svh;padding:.5rem;overflow-y:auto}.b3-command-group+.b3-command-group{border-block-start:1px solid var(--b3-color-border);margin-block-start:.5rem;padding-block-start:.5rem}.b3-command-group>:first-child:not([role=option]){color:var(--b3-color-muted);padding:.5rem .75rem;font-size:.75rem;display:block}.b3-command-item{border-radius:var(--b3-radius-small);cursor:pointer;justify-content:space-between;align-items:center;gap:1rem;min-block-size:2.75rem;padding:.875rem .75rem;display:flex}.b3-command-item>:first-child{overflow-wrap:anywhere;min-inline-size:0}.b3-command-item[aria-selected=true]{background:var(--b3-color-accent);color:var(--b3-color-on-accent)}.b3-command-item[aria-selected=true] .b3-muted{color:inherit}.b3-command-item[aria-disabled=true]{opacity:.5;cursor:not-allowed}.b3-command-item:not([aria-disabled=true]):hover{outline:1px solid var(--b3-color-border);outline-offset:-1px}.b3-form-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,14rem),1fr));align-items:start;gap:1.25rem;display:grid}.b3-form-grid[data-b3-layout=inline]{flex-wrap:wrap;align-items:end;display:flex}.b3-form-grid[data-b3-layout=inline]>.b3-field{flex:12rem;min-inline-size:0}.b3-form-grid[data-b3-layout=inline]>.b3-button{overflow-wrap:anywhere;flex:0 auto;max-inline-size:100%}.b3-fieldset{border:0;min-inline-size:0;margin:0;padding:0}.b3-fieldset>legend{padding:0 0 .75rem;font-weight:650}.b3-help{color:var(--b3-color-muted);font-size:.875rem}.b3-help[data-b3-tone=success]{color:var(--b3-color-success)}.b3-help[data-b3-tone=warning]{color:var(--b3-color-warning)}.b3-input[data-b3-size=small]{padding:.5rem .75rem}.b3-input[data-b3-size=large]{min-block-size:3.25rem;padding:.875rem 1rem}.b3-input[data-b3-emphasis=subtle]{background-color:var(--b3-color-canvas);border-color:#0000}.b3-input[data-b3-emphasis=outline]{background-color:#0000;border-width:2px}.b3-input[data-b3-tone=success]{border-color:var(--b3-color-success)}.b3-input[data-b3-tone=warning]{border-color:var(--b3-color-warning)}.b3-input[aria-invalid=true]{border-color:var(--b3-color-danger)}textarea.b3-input{resize:vertical}select.b3-input[multiple]{min-block-size:8rem}.b3-input[type=file]{padding:.375rem}.b3-input::file-selector-button{font:inherit;border-radius:var(--b3-radius-small);background:var(--b3-color-accent);color:var(--b3-color-on-accent);cursor:pointer;border:0;margin-inline-end:.75rem;padding:.5rem .75rem}.b3-input[type=color]{inline-size:5rem;padding:.25rem}.b3-range{min-block-size:2.75rem;inline-size:100%;accent-color:var(--b3-color-accent);margin:0}.b3-choice-card{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);cursor:pointer;align-items:start;gap:.75rem;padding:1rem;display:flex}.b3-choice-card>input{flex:none;block-size:1.125rem;inline-size:1.125rem;margin-block-start:.3rem}.b3-choice-card:has(input:checked){border-color:var(--b3-color-accent);background:color-mix(in srgb, var(--b3-color-accent) 7%, var(--b3-color-surface));box-shadow:inset 0 0 0 1px var(--b3-color-accent)}.b3-choice-card:has(input:focus-visible){outline:none;box-shadow:inset 0 0 0 2px}.b3-choice-card:has(input:disabled){opacity:.5;cursor:not-allowed}.b3-choice-card:has(input[aria-invalid=true]){border-color:var(--b3-color-danger)}.b3-range[aria-invalid=true]{accent-color:var(--b3-color-danger)}.b3-stepper{flex-wrap:wrap;gap:1rem 2rem;margin:0;padding:0;list-style:none;display:flex}.b3-step{color:var(--b3-color-muted);align-items:center;gap:.625rem;font-size:.875rem;display:flex}.b3-step-marker{border:1px solid var(--b3-color-border);font-variant-numeric:tabular-nums;border-radius:50%;flex:none;place-items:center;block-size:2rem;inline-size:2rem;display:grid}.b3-step[aria-current=step]{color:var(--b3-color-text);font-weight:650}.b3-step[aria-current=step] .b3-step-marker{background:var(--b3-color-accent);color:var(--b3-color-on-accent);border-color:var(--b3-color-accent)}.b3-step[data-b3-complete=true] .b3-step-marker{border-color:var(--b3-color-success);color:var(--b3-color-success)}.b3-conversation{gap:1.5rem;min-inline-size:0;margin:0;padding:0;list-style:none;display:grid}.b3-message{justify-self:start;gap:.375rem;min-inline-size:0;max-inline-size:min(85%,38rem);display:grid}.b3-message[data-b3-side=self]{justify-self:end}.b3-message-body{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);white-space:pre-wrap;overflow-wrap:anywhere;padding:.875rem 1rem}.b3-message[data-b3-side=self]>.b3-message-body{background:var(--b3-color-accent);color:var(--b3-color-on-accent);border-color:#0000}.b3-message-meta{color:var(--b3-color-muted);flex-wrap:wrap;gap:.35rem .75rem;font-size:.8125rem;display:flex}.b3-message[data-b3-side=self]>.b3-message-meta{justify-content:end}.b3-mobile-app{--b3-touch:44px;min-block-size:100svh;max-inline-size:var(--b3-app-width,70rem);margin-inline:auto;padding-block-end:calc(5.5rem + env(safe-area-inset-bottom,0px))}.b3-mobile-app[data-b3-platform=android]{--b3-touch:48px}.b3-mobile-app :where(button,.b3-button,select,input:not([type=checkbox],[type=radio])){min-block-size:var(--b3-touch)}.b3-app-bar{padding:max(.75rem, env(safe-area-inset-top,0px)) 1.25rem .75rem;align-items:center;gap:.75rem;display:flex}.b3-app-bar>:last-child:not(:first-child){margin-inline-start:auto}.b3-bottom-nav{z-index:10;max-inline-size:var(--b3-app-width,70rem);padding:.5rem 1rem max(.5rem, env(safe-area-inset-bottom,0px));background:var(--b3-color-surface);color:var(--b3-color-text);border-block-start:1px solid var(--b3-color-border);justify-content:space-around;gap:.5rem;margin-inline:auto;display:flex;position:fixed;inset-block-end:0;inset-inline:0}.b3-bottom-link{min-block-size:var(--b3-touch,44px);min-inline-size:0;color:var(--b3-color-muted);border-radius:1rem;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:.15rem;padding:.25rem .5rem;font-size:.75rem;text-decoration:none;display:flex}.b3-bottom-link[aria-current=page]{color:var(--b3-color-accent);font-weight:700}[data-b3-platform=android] .b3-bottom-link[aria-current=page]{background:var(--b3-color-canvas)}.b3-mobile-list{border:1px solid var(--b3-color-border);background:var(--b3-color-surface);border-radius:1rem;margin:0;padding:0;list-style:none;overflow:hidden}.b3-mobile-list>li+li{border-block-start:1px solid var(--b3-color-border)}.b3-mobile-row{min-block-size:var(--b3-touch,44px);color:var(--b3-color-text);align-items:center;gap:1rem;padding:.875rem 1rem;text-decoration:none;display:flex}.b3-mobile-row>:last-child:not(:first-child){margin-inline-start:auto}.b3-sheet{inline-size:min(100%, var(--b3-overlay-width,32rem));max-inline-size:none;max-block-size:min(85dvh, calc(100dvh - env(safe-area-inset-top,0px) - 1rem));overscroll-behavior:contain;border:1px solid var(--b3-color-border);padding:1.5rem 1.5rem max(1.5rem, env(safe-area-inset-bottom,0px));background:var(--b3-color-surface);color:var(--b3-color-text);border-radius:1.5rem 1.5rem 0 0;margin:0 auto;inset:auto 0 0;overflow-y:auto}.b3-sheet::backdrop{background:#0007}.b3-sheet [data-b3-initial-focus]:focus{outline:none}.b3-sheet-handle{min-block-size:44px;inline-size:5rem;color:var(--b3-color-muted);touch-action:none;cursor:grab;background:0 0;border:0;border-radius:1rem;flex:none;align-self:center;place-items:center;margin-block:-1rem -.5rem;padding:0;display:grid}.b3-sheet-handle:before{content:"";background:currentColor;border-radius:1rem;block-size:.25rem;inline-size:2.25rem}.b3-sheet[data-b3-dragging]{animation:none}.b3-sheet[data-b3-dragging] .b3-sheet-handle{cursor:grabbing}[data-b3-platform=android] .b3-mobile-list{border-radius:1.5rem}@media (prefers-reduced-motion:no-preference){.b3-sheet[open]{animation:.32s cubic-bezier(.16,1,.3,1) b3-sheet-enter}@keyframes b3-sheet-enter{0%{opacity:0;transform:translateY(3rem)}to{opacity:1;transform:translateY(0)}}}.b3-root:has(dialog:modal){overflow:hidden}.b3-bottom-link[aria-current=page]{background:color-mix(in srgb, var(--b3-color-accent) 12%, transparent)}.b3-bottom-link :where(svg:not([width])){flex:none;block-size:1.375rem;inline-size:1.375rem}.b3-app-frame{block-size:var(--b3-frame-height,100dvh);min-block-size:0;max-inline-size:var(--b3-app-width,70rem);padding:env(safe-area-inset-top,0px) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px);grid-template-rows:auto minmax(0,1fr) auto;margin-inline:auto;display:grid;overflow:clip}.b3-app-frame>header{grid-row:1;min-inline-size:0}.b3-app-frame>main{overscroll-behavior:contain;grid-area:2/1;min-block-size:0;min-inline-size:0;overflow:auto}.b3-app-frame>:is(nav,footer){grid-row:3;min-inline-size:0;position:relative}.b3-app-frame>.b3-toast-region{overscroll-behavior:contain;grid-area:2/1;place-self:end;min-block-size:0;max-block-size:calc(100% - 2rem);margin:1rem;position:relative;inset:auto;overflow-y:auto}.b3-app-frame>.b3-app-bar{padding-block-start:.75rem}.b3-app-frame .b3-bottom-nav{inline-size:100%;max-inline-size:none;padding-block-end:.5rem;position:static}}@property --b3-reel-fade{syntax:"<length>";inherits:false;initial-value:2.5rem}
|
|
1
|
+
@layer bare.reset{:where(.b3-root),:where(.b3-root *){box-sizing:border-box}:where(.b3-root){font-family:var(--b3-font-body);background:var(--b3-color-canvas);color:var(--b3-color-text);color-scheme:light;margin:0;font-size:1rem;line-height:1.5}:where(.b3-root>body){margin:0}:where(.b3-root) :where(button,input,select,textarea){font:inherit}:where(.b3-root) :where(h1,h2,h3,h4,h5,h6,p){margin:0}:where(.b3-root) :where(button,a,input,select,textarea,summary,[tabindex]):focus-visible{outline:none;box-shadow:inset 0 0 0 2px}@media (forced-colors:active){:where(.b3-root) :where(button,a,input,select,textarea,summary,[tabindex]):focus-visible{outline-offset:-2px;outline:1px solid highlight}}:where(.b3-root) :where(img,svg){max-inline-size:100%}@media (prefers-reduced-motion:reduce){:where(.b3-root *),:where(.b3-root *):before,:where(.b3-root *):after{transition:none!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}[data-b3-motion=reduce] *,[data-b3-motion=reduce] :before,[data-b3-motion=reduce] :after,[data-b3-motion=reduce] ::backdrop{scroll-behavior:auto!important;transition:none!important;animation:none!important}:where(.b3-root [hidden]):not([hidden=until-found]){display:none!important}:where(.b3-root) :where(input[type=checkbox],input[type=radio],input[type=range]){accent-color:var(--b3-color-accent)}}@layer bare.tokens{.b3-root{--b3-color-canvas:#f6f5f0;--b3-color-surface:#fff;--b3-color-text:#202923;--b3-color-muted:#59655d;--b3-color-border:#d5dbd3;--b3-color-accent:#245c42;--b3-color-on-accent:#fff;--b3-color-danger:#a62c35;--b3-color-focus:#276bdd;--b3-font-body:ui-sans-serif, system-ui, sans-serif;--b3-font-display:var(--b3-font-body);--b3-radius:.75rem;--b3-space:1rem;--b3-content:68rem}.b3-root[data-b3-theme=dark]{color-scheme:dark;--b3-color-canvas:#141c19;--b3-color-surface:#202c26;--b3-color-text:#edf3ec;--b3-color-muted:#a8b9ad;--b3-color-border:#415348;--b3-color-accent:#aadbb8;--b3-color-on-accent:#132b1b;--b3-color-danger:#ffadb1;--b3-color-focus:#9ac4ff}.b3-root{--b3-space-1:.25rem;--b3-space-2:.5rem;--b3-space-3:.75rem;--b3-space-4:1rem;--b3-space-6:1.5rem;--b3-space-8:2rem;--b3-space-12:3rem;--b3-radius-small:.375rem;--b3-radius-large:1.25rem;--b3-shadow:0 8px 32px #14231b14;--b3-shadow-raised:0 16px 56px #14231b24;--b3-color-success:#256443;--b3-color-warning:#805100;--b3-color-info:#275f99;--b3-duration:.16s}.b3-root[data-b3-theme=dark]{--b3-shadow:0 8px 32px #0004;--b3-shadow-raised:0 16px 56px #0007;--b3-color-success:#99d9ab;--b3-color-warning:#f2c76c;--b3-color-info:#a2cfff}}@layer bare.layout{.b3-shell{inline-size:min(100%, var(--b3-content));margin-inline:auto;padding:clamp(1rem,4vw,3rem)}.b3-stack{gap:var(--b3-space);flex-direction:column;min-inline-size:0;display:flex}.b3-stack:where(dialog:not([open])){display:none}.b3-scroll{overscroll-behavior:contain;scrollbar-gutter:stable;flex:auto;min-block-size:0;min-inline-size:0;overflow:auto}dialog.b3-stack>.b3-scroll{min-block-size:min(6rem,30dvh)}.b3-stack:has(>.b3-scroll)>:not(.b3-scroll){flex-shrink:0}.b3-cluster{align-items:center;gap:var(--b3-space);flex-wrap:wrap;min-inline-size:0;display:flex}.b3-cluster>*,.b3-split>*{min-inline-size:0}.b3-inline{vertical-align:middle;align-items:center;gap:.5em;min-inline-size:0;max-inline-size:100%;display:inline-flex}.b3-inline>*{min-inline-size:0}.b3-grid{grid-template-columns:repeat(auto-fit, minmax(min(100%, var(--b3-grid-min,17rem)), 1fr));gap:var(--b3-space);display:grid}.b3-split{justify-content:space-between;align-items:center;gap:var(--b3-space);flex-wrap:wrap;display:flex}.b3-page{flex-direction:column;min-block-size:100svh;display:flex}.b3-page-body{flex:1;min-inline-size:0}.b3-app-layout{grid-template-columns:minmax(12rem,16rem) minmax(0,1fr);min-block-size:100svh;display:grid}.b3-sidebar{padding:var(--b3-space-6);border-inline-end:1px solid var(--b3-color-border);background:var(--b3-color-surface);min-inline-size:0}.b3-center{padding:var(--b3-space-6);place-items:center;display:grid}.b3-cover{min-block-size:min(42rem,85svh);padding-block:var(--b3-space-12);flex-direction:column;justify-content:center;display:flex}.b3-reel{gap:var(--b3-space);scroll-snap-type:x proximity;padding-block-end:var(--b3-space-2);display:flex;overflow-x:auto}.b3-reel>*{scroll-snap-align:start;flex:0 0 min(85%,20rem)}@media (width<=48rem){.b3-app-layout{grid-template-columns:minmax(0,1fr)}.b3-sidebar{border-inline-end:0;border-block-end:1px solid var(--b3-color-border)}}.b3-reel:has(>.b3-badge){scrollbar-width:none;align-items:center;gap:.5rem;padding-block:.625rem}.b3-reel:has(>.b3-badge)::-webkit-scrollbar{display:none}.b3-reel>.b3-badge{flex:none}.b3-stack>.b3-reel{flex-shrink:0}@supports (animation-timeline:scroll(self inline)){.b3-reel:has(>.b3-badge){mask-image:linear-gradient(to right, #000 calc(100% - var(--b3-reel-fade)), #0000);animation:linear both b3-reel-fade scroll(self inline)}.b3-reel:has(>.b3-badge):dir(rtl){mask-image:linear-gradient(to left, #000 calc(100% - var(--b3-reel-fade)), #0000)}@keyframes b3-reel-fade{90%{--b3-reel-fade:2.5rem}to{--b3-reel-fade:0rem}}}}@layer bare.components{.b3-title{font-family:var(--b3-font-display);letter-spacing:-.04em;overflow-wrap:anywhere;font-size:clamp(2rem,7vw,4rem);line-height:1.05}.b3-heading{font-family:var(--b3-font-display);letter-spacing:-.02em;overflow-wrap:anywhere;font-size:1.375rem;line-height:1.25}.b3-muted{color:var(--b3-color-muted)}.b3-label{letter-spacing:.06em;text-transform:uppercase;font-size:.8125rem;font-weight:650}.b3-surface{background:var(--b3-color-surface);color:var(--b3-color-text);border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);padding:clamp(1rem,3vw,2rem)}.b3-button{border-radius:var(--b3-radius);background:var(--b3-color-accent);min-block-size:2.75rem;color:var(--b3-color-on-accent);cursor:pointer;border:1px solid #0000;justify-content:center;align-items:center;gap:.5rem;padding:.625rem 1rem;font-weight:650;text-decoration:none;display:inline-flex}.b3-button :where(svg){flex-shrink:0;display:block}.b3-button>:where([aria-hidden=true]):has(>svg){flex-shrink:0}.b3-button[data-b3-emphasis=quiet]{color:var(--b3-color-text);border-color:var(--b3-color-border);background:0 0}.b3-button:disabled{opacity:.5;cursor:not-allowed}.b3-field{align-content:start;gap:.375rem;min-inline-size:0;display:grid}.b3-input{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);min-block-size:2.75rem;inline-size:100%;min-inline-size:0;color:var(--b3-color-text);padding:.625rem .75rem}.b3-error{color:var(--b3-color-danger);font-size:.875rem}select.b3-input:not([multiple]):not([size]),select.b3-input[size="1"]:not([multiple]){appearance:none;background-image:linear-gradient(45deg,#0000 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,#0000 50%);background-position:right calc(1rem + 5px) center,right 1rem center;background-repeat:no-repeat;background-size:5px 5px;padding-inline-end:2.5rem}select.b3-input:not([multiple]):not([size]):dir(rtl),select.b3-input[size="1"]:not([multiple]):dir(rtl){background-position:1rem,calc(1rem + 5px)}@media (forced-colors:active){select.b3-input:not([multiple]):not([size]),select.b3-input[size="1"]:not([multiple]){appearance:auto;background-image:none}}:where(ul,ol):has(>.b3-row){margin:0;padding-inline-start:0}.b3-row{border-block-end:1px solid var(--b3-color-border);align-items:center;gap:.75rem;padding-block:1rem;display:flex}.b3-row:where(.b3-stack){align-items:stretch;gap:var(--b3-space)}.b3-badge{overflow-wrap:anywhere;border:1px solid var(--b3-color-border);border-radius:100vmax;align-items:center;inline-size:fit-content;max-inline-size:100%;padding:.125rem .5rem;font-size:.75rem;font-weight:650;display:inline-flex}.b3-progress{block-size:.5rem;inline-size:100%;accent-color:var(--b3-color-accent)}.b3-button{transition:box-shadow var(--b3-duration), border-color var(--b3-duration)}@media (hover:hover){.b3-button:not(:disabled):hover{box-shadow:inset 0 0 0 100vmax #00000012}}.b3-button:not(:disabled):active{box-shadow:inset 0 0 0 100vmax #00000024}.b3-button[data-b3-emphasis=outline]{color:var(--b3-color-accent);background:0 0;border-color:currentColor}.b3-button[data-b3-emphasis=danger]{background:var(--b3-color-danger);color:var(--b3-color-canvas)}.b3-button[data-b3-size=small]{padding:.5rem .75rem;font-size:.875rem}.b3-button[data-b3-size=large]{min-block-size:3.25rem;padding:.875rem 1.5rem}.b3-button[aria-busy=true]{cursor:progress}.b3-icon{vertical-align:-.2em;flex:none;block-size:1.25em;inline-size:1.25em;display:inline-block}.b3-input:disabled{opacity:.6;cursor:not-allowed}.b3-input[readonly]{background:var(--b3-color-canvas)}.b3-input::placeholder{color:var(--b3-color-muted);opacity:.8}.b3-input-group{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);align-items:stretch;min-inline-size:0;display:flex;overflow:clip}.b3-input-group>.b3-input{border:0;border-radius:0;flex:1}.b3-input-group:has(>.b3-button){flex-wrap:wrap;justify-content:end}.b3-input-group:has(>.b3-button)>.b3-input{flex-basis:12ch}.b3-input-group:focus-within{outline:none;box-shadow:inset 0 0 0 2px}.b3-input-affix{color:var(--b3-color-muted);background:var(--b3-color-canvas);align-items:center;padding-inline:.75rem;display:flex}.b3-choice{cursor:pointer;align-items:start;gap:.75rem;padding-block:.5rem;display:flex}.b3-choice input{--b3-choice-control:1.125rem;inline-size:var(--b3-choice-control);block-size:var(--b3-choice-control);flex:none;margin:0;margin-block-start:max(0px, calc((1lh - var(--b3-choice-control)) / 2))}.b3-choice>.b3-switch{--b3-choice-control:1.625rem}.b3-switch{appearance:none;background:var(--b3-color-muted);border:2px solid var(--b3-color-muted);cursor:pointer;border-radius:2rem;position:relative;block-size:1.625rem!important;inline-size:2.75rem!important}.b3-switch:before{content:"";background:var(--b3-color-surface);border-radius:50%;block-size:1.125rem;inline-size:1.125rem;position:absolute;inset-block-start:.125rem;inset-inline-start:.125rem}.b3-switch:checked{background:var(--b3-color-accent);border-color:var(--b3-color-accent)}.b3-switch:checked:before{background:var(--b3-color-on-accent);inset-inline-start:calc(100% - 1.25rem)}.b3-switch:disabled{opacity:.5;cursor:not-allowed}.b3-input[type=number]{appearance:textfield}.b3-input[type=number]::-webkit-inner-spin-button,.b3-input[type=number]::-webkit-outer-spin-button{appearance:none;margin:0}.b3-input::-webkit-datetime-edit,.b3-input::-webkit-datetime-edit-fields-wrapper{padding-block:0}.b3-input-affix{white-space:nowrap}.b3-card-header,.b3-card-footer{justify-content:space-between;align-items:center;gap:var(--b3-space);flex-wrap:wrap;display:flex}.b3-card-header{margin-block-end:var(--b3-space-4)}.b3-card-footer{border-block-start:1px solid var(--b3-color-border);margin-block-start:var(--b3-space-4);padding-block-start:var(--b3-space-4)}.b3-surface[data-b3-elevation=raised]{box-shadow:var(--b3-shadow)}.b3-divider{border:0;border-block-start:1px solid var(--b3-color-border);margin-block:var(--b3-space)}.b3-alert,.b3-toast{overflow-wrap:anywhere;min-inline-size:0}.b3-alert>*,.b3-toast>*{min-inline-size:0}.b3-alert pre{max-inline-size:100%;overflow-x:auto}.b3-alert{--b3-status-color:var(--b3-color-info);border:1px solid var(--b3-status-color);border-radius:var(--b3-radius-small);color:var(--b3-color-text);background:color-mix(in srgb, var(--b3-status-color) 8%, var(--b3-color-surface));border-inline-start-width:4px;align-items:start;gap:.75rem;padding:1rem;display:flex}.b3-alert[data-b3-tone=success],.b3-badge[data-b3-tone=success]{--b3-status-color:var(--b3-color-success)}.b3-alert[data-b3-tone=warning],.b3-badge[data-b3-tone=warning]{--b3-status-color:var(--b3-color-warning)}.b3-alert[data-b3-tone=danger],.b3-badge[data-b3-tone=danger]{--b3-status-color:var(--b3-color-danger)}.b3-badge[data-b3-tone]{color:var(--b3-status-color,var(--b3-color-info));background:color-mix(in srgb, currentColor 7%, transparent);border-color:currentColor}.b3-toast-region{z-index:100;pointer-events:none;gap:.75rem;inline-size:min(24rem,100% - 2rem);display:grid;position:fixed;inset-block-end:1rem;inset-inline-end:1rem}.b3-toast{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);pointer-events:auto;flex-wrap:wrap;align-items:start;gap:1rem;padding:1rem;display:flex}.b3-toast>:not(button,.b3-button){flex:12rem}.b3-toast>:is(button,.b3-button){flex:none;max-inline-size:100%}.b3-spinner{vertical-align:-.125em;border:2px solid;border-inline-end-color:#0000;border-radius:50%;flex:none;block-size:1.125em;inline-size:1.125em;animation:.8s linear infinite b3-spin;display:inline-block}@keyframes b3-spin{to{transform:rotate(360deg)}}.b3-skeleton{background:var(--b3-color-border);border-radius:var(--b3-radius-small);min-block-size:1rem;animation:1.8s ease-in-out infinite b3-pulse}@keyframes b3-pulse{50%{opacity:.45}}:is(button,a).b3-badge{min-block-size:auto;color:var(--b3-color-text);cursor:pointer;background:0 0;gap:.25rem;text-decoration:none;position:relative}:is(button,a).b3-badge:after{content:"";position:absolute;inset:-10px 0}:is(button,a).b3-badge[data-b3-tone]{color:var(--b3-status-color,var(--b3-color-info))}:is(button,a).b3-badge:is([aria-pressed=true],[aria-current]:not([aria-current=false])){color:var(--b3-color-on-accent);background:var(--b3-color-accent);border-color:var(--b3-color-accent)}.b3-avatar{background:var(--b3-color-accent);block-size:2.5rem;inline-size:2.5rem;color:var(--b3-color-on-accent);border-radius:50%;flex:none;place-items:center;font-size:.875rem;font-weight:650;display:inline-grid;overflow:hidden}.b3-avatar>img{object-fit:cover;block-size:100%;inline-size:100%}.b3-avatar-stack{padding-inline-start:.5rem;display:flex}.b3-avatar-stack>.b3-avatar{border:2px solid var(--b3-color-surface);margin-inline-start:-.5rem}.b3-kbd{border:1px solid var(--b3-color-border);background:var(--b3-color-surface);color:var(--b3-color-muted);border-block-end-width:2px;border-radius:.25rem;padding:.15rem .35rem;font:.75rem ui-monospace,monospace}.b3-table-wrap{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);position:relative;overflow-x:auto}.b3-table{border-collapse:collapse;text-align:start;font-variant-numeric:tabular-nums;inline-size:100%}.b3-table th{color:var(--b3-color-muted);background:var(--b3-color-canvas);font-size:.75rem;font-weight:650}.b3-table :is(th,td){border-block-end:1px solid var(--b3-color-border);text-align:start;vertical-align:middle;padding:.875rem 1rem}.b3-table tbody tr:last-child td{border-block-end:0}.b3-table[data-b3-density=compact] :is(th,td){padding:.5rem .75rem}.b3-table tbody tr[aria-selected=true]{background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface))}.b3-definition{grid-template-columns:minmax(0,1fr) minmax(0,2fr);gap:.75rem 1.5rem;margin:0;display:grid;container:b3-definition/inline-size}.b3-definition dt{overflow-wrap:anywhere;min-inline-size:0;color:var(--b3-color-muted)}.b3-definition dd{overflow-wrap:anywhere;margin:0}@container b3-definition (width<=26rem){.b3-definition>:is(dt,dd){grid-column:1/-1}.b3-definition>dt:not(:first-child){margin-block-start:.75rem}}.b3-stat{gap:.5rem;display:grid}.b3-stat-value{letter-spacing:-.045em;font-variant-numeric:tabular-nums;font-size:clamp(2rem,5vw,3rem);font-weight:650;line-height:1.1}.b3-nav{border-block-end:1px solid var(--b3-color-border);flex-wrap:wrap;align-items:center;gap:.5rem;padding:.75rem;display:flex}.b3-nav[data-b3-orientation=vertical]{border-block-end:0;flex-direction:column;align-items:stretch}.b3-nav-link{border-radius:var(--b3-radius-small);min-block-size:2.75rem;color:var(--b3-color-muted);align-items:center;gap:.5rem;padding:.625rem .875rem;text-decoration:none;display:flex}.b3-nav-link[aria-current=page]{background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface));color:var(--b3-color-accent);font-weight:650}.b3-nav-link:hover{background:var(--b3-color-surface);color:var(--b3-color-text)}.b3-breadcrumbs{color:var(--b3-color-muted);flex-wrap:wrap;align-items:center;gap:.5rem;margin:0;padding:0;font-size:.875rem;list-style:none;display:flex}.b3-breadcrumbs li+li:before{content:"/";color:var(--b3-color-border);margin-inline-end:.5rem}.b3-tablist{border-block-end:1px solid var(--b3-color-border);gap:.25rem;display:flex;overflow-x:auto}.b3-tab{appearance:none;color:var(--b3-color-muted);font:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:0;border-block-end:2px solid #0000;min-block-size:2.75rem;padding:.75rem 1rem}.b3-tab[aria-selected=true]{color:var(--b3-color-accent);border-block-end-color:currentColor;font-weight:650}.b3-tab:disabled{opacity:.5;cursor:not-allowed}.b3-tabpanel{padding-block:var(--b3-space-4)}.b3-accordion{border-block-end:1px solid var(--b3-color-border)}.b3-accordion>summary{cursor:pointer;padding:1rem .25rem;font-weight:650}.b3-accordion>:not(summary){padding:0 .25rem 1rem}.b3-dropdown{display:inline-block;position:relative}.b3-dropdown>summary{list-style:none}.b3-dropdown>summary::-webkit-details-marker{display:none}.b3-dropdown-panel{z-index:20;border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);max-block-size:70svh;inline-size:max-content;min-inline-size:min(12rem,85vw);max-inline-size:min(22rem,85vw);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);padding:.5rem;position:absolute;inset-block-start:calc(100% + .5rem);inset-inline-start:0;overflow-y:auto}.b3-dialog{overscroll-behavior:contain;border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-large);background:var(--b3-color-surface);max-block-size:calc(100svh - 2rem);inline-size:min(32rem,100% - 2rem);color:var(--b3-color-text);box-shadow:var(--b3-shadow-raised);padding:min(1.5rem,5vi);overflow:auto}.b3-dialog::backdrop{background:#101b17a6}.b3-dialog[data-b3-placement=end]{border-radius:0;block-size:100svh;max-block-size:100svh;inline-size:min(28rem,100%);max-inline-size:100%;margin:0;margin-inline-start:auto}@media (prefers-reduced-motion:no-preference){.b3-dialog[open]{animation:.28s cubic-bezier(.16,1,.3,1) b3-dialog-enter}.b3-dialog[open][data-b3-placement=end]{animation-name:b3-drawer-enter}.b3-dialog::backdrop,.b3-sheet::backdrop{transition:opacity .16s ease-out}.b3-dialog[data-b3-closing]::backdrop,.b3-sheet[data-b3-closing]::backdrop{opacity:0}@keyframes b3-dialog-enter{0%{opacity:0;transform:translateY(8px)scale(.96)}}@keyframes b3-drawer-enter{0%{opacity:0;translate:var(--b3-drawer-offset,1rem)}}.b3-dialog[dir=rtl][data-b3-placement=end],[dir=rtl] .b3-dialog[data-b3-placement=end]{--b3-drawer-offset:-1rem}}.b3-dialog>form{gap:var(--b3-space);flex-direction:column;margin:0;display:flex}.b3-dialog>form>header:has(>button:last-child){grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:.75rem;display:grid}.b3-dialog>form>header:has(>button:last-child)>:not(:last-child){grid-column:1;min-inline-size:0}.b3-dialog>form>header>button:last-child:not(:first-child){grid-area:1/2}.b3-dialog>form>footer{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:.75rem;display:flex}.b3-dialog>form>footer>[data-b3-emphasis=quiet]:first-child:not(:last-child){margin-inline-end:auto}.b3-tree{border-inline-start:1px solid var(--b3-color-border);padding-inline-start:1rem;list-style:none}.b3-tree summary{cursor:pointer;padding-block:.5rem}.b3-prose{overflow-wrap:anywhere;max-inline-size:65ch;line-height:1.75}.b3-prose :is(p,ul,ol,blockquote,pre){margin-block:1rem}.b3-prose :is(h1,h2,h3,h4,h5,h6){margin-block:1.75rem .75rem;line-height:1.25}.b3-prose :is(h5,h6){font-size:1em}.b3-prose>:first-child{margin-block-start:0}.b3-prose img{block-size:auto}.b3-prose blockquote{border-inline-start:3px solid var(--b3-color-accent);color:var(--b3-color-muted);margin-inline:0;padding-inline-start:1rem}.b3-prose pre{background:var(--b3-color-surface);border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-small);padding:1rem;overflow-x:auto}.b3-visually-hidden{clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;position:absolute;overflow:hidden}.b3-skip-link{z-index:1000;border-radius:var(--b3-radius-small);background:var(--b3-color-accent);max-inline-size:calc(100% - 1.5rem);color:var(--b3-color-on-accent);padding:.75rem 1rem;font-weight:650;position:fixed;inset-block-start:max(.75rem, env(safe-area-inset-top,0px));inset-inline-start:.75rem}.b3-skip-link:not(:focus){clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;padding:0;overflow:hidden}.b3-hero{grid-template-columns:repeat(2,minmax(0,1fr));align-items:center;gap:clamp(2rem,6vw,6rem);padding-block:clamp(3rem,8vw,7rem);display:grid}.b3-hero[data-b3-align=center]{text-align:center;grid-template-columns:minmax(0,1fr);justify-items:center}.b3-hero-copy{gap:1.5rem;max-inline-size:40rem;display:grid}.b3-feature{grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:center;gap:clamp(1.5rem,5vw,5rem);padding-block:clamp(2rem,6vw,5rem);display:grid}.b3-feature[data-b3-reverse=true]>:first-child{order:2}.b3-feature-icon{border-radius:var(--b3-radius);background:var(--b3-color-accent);block-size:3rem;inline-size:3rem;color:var(--b3-color-on-accent);place-items:center;display:inline-grid}.b3-pricing{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius-large);background:var(--b3-color-surface);color:var(--b3-color-text);flex-direction:column;gap:1.25rem;padding:clamp(1.25rem,3vw,2rem);display:flex}.b3-pricing[data-b3-featured=true]{border:2px solid var(--b3-color-accent);box-shadow:var(--b3-shadow)}.b3-pricing>.b3-button:last-child{margin-block-start:auto}.b3-price{font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:.375rem;display:flex}.b3-price>strong{letter-spacing:-.05em;font-size:3.25rem;line-height:1.1}.b3-checklist{gap:.75rem;margin:0;padding:0;list-style:none;display:grid}.b3-checklist>li{align-items:start;gap:.625rem;display:flex}.b3-checklist>li:before{content:"✓";color:var(--b3-color-accent);font-weight:700}.b3-quote{border-inline-start:3px solid var(--b3-color-accent);margin:0;padding:1.5rem}.b3-quote blockquote{margin:0 0 1rem;font-size:1.25rem;line-height:1.5}.b3-art{isolation:isolate;border-radius:var(--b3-radius-large);background:var(--b3-color-surface);position:relative;overflow:hidden}.b3-art:before{content:"";z-index:-1;pointer-events:none;position:absolute;inset:0}.b3-art[data-b3-art=dots]:before{background-image:radial-gradient(var(--b3-color-border) 1px,transparent 1px);background-size:16px 16px}.b3-art[data-b3-art=glow]:before{background:radial-gradient(ellipse at 20% 20%,color-mix(in srgb,var(--b3-color-accent) 20%,transparent),transparent 65%)}.b3-art[data-b3-art=wash]:before{background:linear-gradient(135deg,color-mix(in srgb,var(--b3-color-accent) 14%,transparent),transparent 70%)}@media (width<=48rem){.b3-hero,.b3-feature{grid-template-columns:minmax(0,1fr)}.b3-feature[data-b3-reverse=true]>:first-child{order:initial}}.b3-reading{grid-template-columns:minmax(0,1fr) minmax(12rem,16rem);grid-template-areas:"content outline";align-items:start;gap:clamp(2rem,5vw,5rem);display:grid}.b3-reading>:not(.b3-toc){grid-area:content;min-inline-size:0}.b3-toc{max-block-size:calc(100svh - var(--b3-outline-top,1rem) - 1rem);border-inline-start:1px solid var(--b3-color-border);grid-area:outline;padding-inline-start:1rem;font-size:.875rem;position:sticky;inset-block-start:var(--b3-outline-top,1rem);overflow-y:auto}.b3-toc ol{gap:.25rem;margin:.75rem 0 0;padding:0;list-style:none;display:grid}.b3-toc ol ol{margin:.25rem 0;padding-inline-start:1rem}.b3-toc-link{border-radius:var(--b3-radius-small);color:var(--b3-color-muted);overflow-wrap:anywhere;padding:.625rem .75rem;text-decoration:none;display:block}.b3-toc-link:hover{color:var(--b3-color-text);background:var(--b3-color-surface)}.b3-toc-link[aria-current=location]{color:var(--b3-color-accent);background:color-mix(in srgb, var(--b3-color-accent) 10%, var(--b3-color-surface));font-weight:650}@media (width<=48rem){.b3-reading{grid-template-columns:minmax(0,1fr);grid-template-areas:"outline""content";gap:2rem}.b3-toc{max-block-size:none;position:static}}.b3-command{inline-size:min(38rem,100% - 2rem);padding:0}.b3-command-search{border-block-end:1px solid var(--b3-color-border);align-items:center;gap:.75rem;padding:1rem;display:flex}.b3-command-search>input{flex:1;min-inline-size:0}.b3-command-list{overscroll-behavior:contain;max-block-size:50svh;padding:.5rem;overflow-y:auto}.b3-command-group+.b3-command-group{border-block-start:1px solid var(--b3-color-border);margin-block-start:.5rem;padding-block-start:.5rem}.b3-command-group>:first-child:not([role=option]){color:var(--b3-color-muted);padding:.5rem .75rem;font-size:.75rem;display:block}.b3-command-item{border-radius:var(--b3-radius-small);cursor:pointer;justify-content:space-between;align-items:center;gap:1rem;min-block-size:2.75rem;padding:.875rem .75rem;display:flex}.b3-command-item>:first-child{overflow-wrap:anywhere;min-inline-size:0}.b3-command-item[aria-selected=true]{background:var(--b3-color-accent);color:var(--b3-color-on-accent)}.b3-command-item[aria-selected=true] .b3-muted{color:inherit}.b3-command-item[aria-disabled=true]{opacity:.5;cursor:not-allowed}.b3-command-item:not([aria-disabled=true]):hover{outline:1px solid var(--b3-color-border);outline-offset:-1px}.b3-form-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,14rem),1fr));align-items:start;gap:1.25rem;display:grid}.b3-form-grid[data-b3-layout=inline]{flex-wrap:wrap;align-items:end;display:flex}.b3-form-grid[data-b3-layout=inline]>.b3-field{flex:12rem;min-inline-size:0}.b3-form-grid[data-b3-layout=inline]>.b3-button{overflow-wrap:anywhere;flex:0 auto;max-inline-size:100%}.b3-fieldset{border:0;min-inline-size:0;margin:0;padding:0}.b3-fieldset>legend{padding:0 0 .75rem;font-weight:650}.b3-help{color:var(--b3-color-muted);font-size:.875rem}.b3-help[data-b3-tone=success]{color:var(--b3-color-success)}.b3-help[data-b3-tone=warning]{color:var(--b3-color-warning)}.b3-input[data-b3-size=small]{padding:.5rem .75rem}.b3-input[data-b3-size=large]{min-block-size:3.25rem;padding:.875rem 1rem}.b3-input[data-b3-emphasis=subtle]{background-color:var(--b3-color-canvas);border-color:#0000}.b3-input[data-b3-emphasis=outline]{background-color:#0000;border-width:2px}.b3-input[data-b3-tone=success]{border-color:var(--b3-color-success)}.b3-input[data-b3-tone=warning]{border-color:var(--b3-color-warning)}.b3-input[aria-invalid=true]{border-color:var(--b3-color-danger)}textarea.b3-input{resize:vertical}select.b3-input[multiple]{min-block-size:8rem}.b3-input[type=file]{padding:.375rem}.b3-input::file-selector-button{font:inherit;border-radius:var(--b3-radius-small);background:var(--b3-color-accent);color:var(--b3-color-on-accent);cursor:pointer;border:0;margin-inline-end:.75rem;padding:.5rem .75rem}.b3-input[type=color]{inline-size:5rem;padding:.25rem}.b3-range{min-block-size:2.75rem;inline-size:100%;accent-color:var(--b3-color-accent);margin:0}.b3-choice-card{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);cursor:pointer;align-items:start;gap:.75rem;padding:1rem;display:flex}.b3-choice-card>input{flex:none;block-size:1.125rem;inline-size:1.125rem;margin-block-start:.3rem}.b3-choice-card:has(input:checked){border-color:var(--b3-color-accent);background:color-mix(in srgb, var(--b3-color-accent) 7%, var(--b3-color-surface));box-shadow:inset 0 0 0 1px var(--b3-color-accent)}.b3-choice-card:has(input:focus-visible){outline:none;box-shadow:inset 0 0 0 2px}.b3-choice-card:has(input:disabled){opacity:.5;cursor:not-allowed}.b3-choice-card:has(input[aria-invalid=true]){border-color:var(--b3-color-danger)}.b3-range[aria-invalid=true]{accent-color:var(--b3-color-danger)}.b3-stepper{flex-wrap:wrap;gap:1rem 2rem;margin:0;padding:0;list-style:none;display:flex}.b3-step{color:var(--b3-color-muted);align-items:center;gap:.625rem;font-size:.875rem;display:flex}.b3-step-marker{border:1px solid var(--b3-color-border);font-variant-numeric:tabular-nums;border-radius:50%;flex:none;place-items:center;block-size:2rem;inline-size:2rem;display:grid}.b3-step[aria-current=step]{color:var(--b3-color-text);font-weight:650}.b3-step[aria-current=step] .b3-step-marker{background:var(--b3-color-accent);color:var(--b3-color-on-accent);border-color:var(--b3-color-accent)}.b3-step[data-b3-complete=true] .b3-step-marker{border-color:var(--b3-color-success);color:var(--b3-color-success)}.b3-conversation{gap:1.5rem;min-inline-size:0;margin:0;padding:0;list-style:none;display:grid}.b3-message{justify-self:start;gap:.375rem;min-inline-size:0;max-inline-size:min(85%,38rem);display:grid}.b3-message[data-b3-side=self]{justify-self:end}.b3-message-body{border:1px solid var(--b3-color-border);border-radius:var(--b3-radius);background:var(--b3-color-surface);color:var(--b3-color-text);white-space:pre-wrap;overflow-wrap:anywhere;padding:.875rem 1rem}.b3-message[data-b3-side=self]>.b3-message-body{background:var(--b3-color-accent);color:var(--b3-color-on-accent);border-color:#0000}.b3-message-meta{color:var(--b3-color-muted);flex-wrap:wrap;gap:.35rem .75rem;font-size:.8125rem;display:flex}.b3-message[data-b3-side=self]>.b3-message-meta{justify-content:end}.b3-mobile-app{--b3-touch:44px;min-block-size:100svh;max-inline-size:var(--b3-app-width,70rem);margin-inline:auto;padding-block-end:calc(5.5rem + env(safe-area-inset-bottom,0px))}.b3-mobile-app[data-b3-platform=android]{--b3-touch:48px}.b3-mobile-app :where(button,.b3-button,select,input:not([type=checkbox],[type=radio])){min-block-size:var(--b3-touch)}.b3-app-bar{padding:max(.75rem, env(safe-area-inset-top,0px)) 1.25rem .75rem;align-items:center;gap:.75rem;display:flex}.b3-app-bar>:last-child:not(:first-child){margin-inline-start:auto}.b3-bottom-nav{z-index:10;max-inline-size:var(--b3-app-width,70rem);padding:.5rem 1rem max(.5rem, env(safe-area-inset-bottom,0px));background:var(--b3-color-surface);color:var(--b3-color-text);border-block-start:1px solid var(--b3-color-border);justify-content:space-around;gap:.5rem;margin-inline:auto;display:flex;position:fixed;inset-block-end:0;inset-inline:0}.b3-bottom-link{min-block-size:var(--b3-touch,44px);min-inline-size:0;color:var(--b3-color-muted);border-radius:1rem;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:.15rem;padding:.25rem .5rem;font-size:.75rem;text-decoration:none;display:flex}.b3-bottom-link[aria-current=page]{color:var(--b3-color-accent);font-weight:700}[data-b3-platform=android] .b3-bottom-link[aria-current=page]{background:var(--b3-color-canvas)}.b3-mobile-list{border:1px solid var(--b3-color-border);background:var(--b3-color-surface);border-radius:1rem;margin:0;padding:0;list-style:none;overflow:hidden}.b3-mobile-list>li+li{border-block-start:1px solid var(--b3-color-border)}.b3-mobile-row{min-block-size:var(--b3-touch,44px);color:var(--b3-color-text);align-items:center;gap:1rem;padding:.875rem 1rem;text-decoration:none;display:flex}.b3-mobile-row>:last-child:not(:first-child){margin-inline-start:auto}.b3-sheet{inline-size:min(100%, var(--b3-overlay-width,32rem));max-inline-size:none;max-block-size:min(85dvh, calc(100dvh - env(safe-area-inset-top,0px) - 1rem));overscroll-behavior:contain;border:1px solid var(--b3-color-border);padding:1.5rem min(1.5rem, 5vi) max(1.5rem, env(safe-area-inset-bottom,0px));background:var(--b3-color-surface);color:var(--b3-color-text);border-radius:1.5rem 1.5rem 0 0;margin:0 auto;inset:auto 0 0;overflow-y:auto}.b3-sheet::backdrop{background:#0007}.b3-sheet [data-b3-initial-focus]:focus{outline:none}.b3-sheet-handle{min-block-size:44px;inline-size:5rem;color:var(--b3-color-muted);touch-action:none;cursor:grab;background:0 0;border:0;border-radius:1rem;flex:none;align-self:center;place-items:center;margin-block:-1rem -.5rem;padding:0;display:grid}.b3-sheet-handle:before{content:"";background:currentColor;border-radius:1rem;block-size:.25rem;inline-size:2.25rem}.b3-sheet[data-b3-dragging]{animation:none}.b3-sheet[data-b3-dragging] .b3-sheet-handle{cursor:grabbing}[data-b3-platform=android] .b3-mobile-list{border-radius:1.5rem}@media (prefers-reduced-motion:no-preference){.b3-sheet[open]{animation:.32s cubic-bezier(.16,1,.3,1) b3-sheet-enter}@keyframes b3-sheet-enter{0%{opacity:0;transform:translateY(3rem)}to{opacity:1;transform:translateY(0)}}}.b3-root:has(dialog:modal){overflow:hidden}.b3-bottom-link[aria-current=page]{background:color-mix(in srgb, var(--b3-color-accent) 12%, transparent)}.b3-bottom-link :where(svg:not([width])){flex:none;block-size:1.375rem;inline-size:1.375rem}.b3-app-frame{block-size:var(--b3-frame-height,100dvh);min-block-size:0;max-inline-size:var(--b3-app-width,70rem);padding:env(safe-area-inset-top,0px) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px);grid-template-rows:auto minmax(0,1fr) auto;margin-inline:auto;display:grid;overflow:clip}.b3-app-frame>header{grid-row:1;min-inline-size:0}.b3-app-frame>main{overscroll-behavior:contain;grid-area:2/1;min-block-size:0;min-inline-size:0;overflow:auto}.b3-app-frame>:is(nav,footer){grid-row:3;min-inline-size:0;position:relative}.b3-app-frame>.b3-toast-region{overscroll-behavior:contain;grid-area:2/1;place-self:end;min-block-size:0;max-block-size:calc(100% - 2rem);margin:1rem;position:relative;inset:auto;overflow-y:auto}.b3-app-frame>.b3-app-bar{padding-block-start:.75rem}.b3-app-frame .b3-bottom-nav{inline-size:100%;max-inline-size:none;padding-block-end:.5rem;position:static}}@property --b3-reel-fade{syntax:"<length>";inherits:false;initial-value:2.5rem}
|
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
// src/elements/date-picker.js
|
|
2
|
+
var Base = typeof HTMLElement === "function" ? HTMLElement : class {
|
|
3
|
+
};
|
|
4
|
+
var pad = (value) => String(value).padStart(2, "0");
|
|
5
|
+
function toIso(date) {
|
|
6
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
7
|
+
}
|
|
8
|
+
function parse(value) {
|
|
9
|
+
const match = /^(\d{4})-(\d{2})(?:-(\d{2}))?$/.exec(String(value ?? "").trim());
|
|
10
|
+
if (!match)
|
|
11
|
+
return null;
|
|
12
|
+
const [, year, month, day] = match;
|
|
13
|
+
const date = new Date(Number(year), Number(month) - 1, day === undefined ? 1 : Number(day));
|
|
14
|
+
if (date.getMonth() !== Number(month) - 1 || day !== undefined && date.getDate() !== Number(day))
|
|
15
|
+
return null;
|
|
16
|
+
return date;
|
|
17
|
+
}
|
|
18
|
+
var today = () => toIso(new Date);
|
|
19
|
+
function addDays(iso, count) {
|
|
20
|
+
const date = parse(iso);
|
|
21
|
+
if (!date)
|
|
22
|
+
return iso;
|
|
23
|
+
date.setDate(date.getDate() + count);
|
|
24
|
+
return toIso(date);
|
|
25
|
+
}
|
|
26
|
+
function addMonths(iso, count) {
|
|
27
|
+
const date = parse(iso);
|
|
28
|
+
if (!date)
|
|
29
|
+
return iso;
|
|
30
|
+
const day = date.getDate();
|
|
31
|
+
date.setDate(1);
|
|
32
|
+
date.setMonth(date.getMonth() + count);
|
|
33
|
+
date.setDate(Math.min(day, daysInMonth(date.getFullYear(), date.getMonth())));
|
|
34
|
+
return toIso(date);
|
|
35
|
+
}
|
|
36
|
+
var daysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
|
|
37
|
+
var STYLE_ID = "b3-date-picker-style";
|
|
38
|
+
var STYLE = `
|
|
39
|
+
.b3-date-picker{display:block;position:relative;color:var(--b3-color-text,#202923);
|
|
40
|
+
background:var(--b3-color-surface,#fff);border:1px solid var(--b3-color-border,#d5dbd3);
|
|
41
|
+
border-radius:var(--b3-radius,.75rem);padding:var(--b3-space,1rem);
|
|
42
|
+
-webkit-user-select:none;user-select:none;}
|
|
43
|
+
.b3-date-picker > :not(.b3-date-picker-ui){display:none;}
|
|
44
|
+
/* A required control that is not RENDERED cannot be focused, so Chrome refuses to submit the
|
|
45
|
+
form and has nowhere to anchor the validation bubble: the button dies silently. Clip that one
|
|
46
|
+
case instead of removing it, so the constraint still blocks the submit and still SHOWS why. */
|
|
47
|
+
.b3-date-picker > :not(.b3-date-picker-ui):has(input:required),
|
|
48
|
+
.b3-date-picker > input:required{display:block;position:absolute;
|
|
49
|
+
inset-block-start:var(--b3-space,1rem);inset-inline-start:var(--b3-space,1rem);
|
|
50
|
+
width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none;white-space:nowrap;}
|
|
51
|
+
.b3-date-picker-bar{display:flex;align-items:center;gap:.5rem;margin-block-end:.5rem;}
|
|
52
|
+
.b3-date-picker-title{flex:1;text-align:center;font-weight:600;}
|
|
53
|
+
.b3-date-picker-nav{display:inline-flex;align-items:center;justify-content:center;
|
|
54
|
+
min-width:var(--b3-touch,44px);min-height:var(--b3-touch,44px);font:inherit;line-height:1;
|
|
55
|
+
border:1px solid var(--b3-color-border,#d5dbd3);border-radius:var(--b3-radius-small,.375rem);
|
|
56
|
+
background:var(--b3-color-surface,#fff);color:inherit;cursor:pointer;}
|
|
57
|
+
.b3-date-picker-nav::before{content:"\\2039";font-size:1.25em;}
|
|
58
|
+
.b3-date-picker-nav[data-b3-step="1"]::before{content:"\\203A";}
|
|
59
|
+
.b3-date-picker:dir(rtl) .b3-date-picker-nav::before{content:"\\203A";}
|
|
60
|
+
.b3-date-picker:dir(rtl) .b3-date-picker-nav[data-b3-step="1"]::before{content:"\\2039";}
|
|
61
|
+
.b3-date-picker-nav[disabled]{opacity:.4;cursor:default;}
|
|
62
|
+
.b3-date-picker-grid{width:100%;border-collapse:collapse;table-layout:fixed;}
|
|
63
|
+
.b3-date-picker-grid th{font-weight:500;font-size:.8125em;padding-block:.25rem;
|
|
64
|
+
color:var(--b3-color-muted,#5d6b60);}
|
|
65
|
+
.b3-date-picker-grid td{padding:1px;text-align:center;}
|
|
66
|
+
.b3-date-picker-grid td[data-b3-date]{cursor:pointer;border-radius:var(--b3-radius-small,.375rem);
|
|
67
|
+
line-height:calc(var(--b3-touch,44px) - 2px);}
|
|
68
|
+
.b3-date-picker-grid td[data-b3-date]:hover{background:var(--b3-color-canvas,#f6f5f0);}
|
|
69
|
+
.b3-date-picker-grid td:focus-visible{outline:2px solid var(--b3-color-focus,#276bdd);outline-offset:-2px;}
|
|
70
|
+
.b3-date-picker-grid td[data-b3-today]{box-shadow:inset 0 0 0 1px var(--b3-color-border,#d5dbd3);}
|
|
71
|
+
.b3-date-picker-grid td[aria-selected="true"]{background:var(--b3-color-accent,#276bdd);
|
|
72
|
+
color:var(--b3-color-on-accent,#fff);}
|
|
73
|
+
.b3-date-picker-grid td[aria-disabled="true"]{color:var(--b3-color-muted,#5d6b60);opacity:.45;cursor:default;}
|
|
74
|
+
.b3-date-picker-grid td[aria-disabled="true"]:hover{background:none;}
|
|
75
|
+
`;
|
|
76
|
+
function ensureStyle(document) {
|
|
77
|
+
if (document.getElementById(STYLE_ID))
|
|
78
|
+
return;
|
|
79
|
+
const style = document.createElement("style");
|
|
80
|
+
style.id = STYLE_ID;
|
|
81
|
+
style.textContent = STYLE;
|
|
82
|
+
document.head.append(style);
|
|
83
|
+
}
|
|
84
|
+
var tokens = (value) => String(value ?? "").split(/[\s,]+/).filter(Boolean);
|
|
85
|
+
|
|
86
|
+
class B3DatePicker extends Base {
|
|
87
|
+
static observedAttributes = [
|
|
88
|
+
"value",
|
|
89
|
+
"month",
|
|
90
|
+
"min",
|
|
91
|
+
"max",
|
|
92
|
+
"week-start",
|
|
93
|
+
"locale",
|
|
94
|
+
"disabled-dates",
|
|
95
|
+
"disabled-weekdays"
|
|
96
|
+
];
|
|
97
|
+
#upgraded = false;
|
|
98
|
+
#controller = null;
|
|
99
|
+
#focus = null;
|
|
100
|
+
#month = null;
|
|
101
|
+
#grid = null;
|
|
102
|
+
#bar = null;
|
|
103
|
+
#title = null;
|
|
104
|
+
#ui = null;
|
|
105
|
+
#observer = null;
|
|
106
|
+
#titleId = `b3-date-picker-title-${Math.random().toString(36).slice(2, 8)}`;
|
|
107
|
+
get value() {
|
|
108
|
+
return this.getAttribute("value") && parse(this.getAttribute("value")) ? this.getAttribute("value") : "";
|
|
109
|
+
}
|
|
110
|
+
set value(next) {
|
|
111
|
+
if (next == null || next === "")
|
|
112
|
+
this.removeAttribute("value");
|
|
113
|
+
else
|
|
114
|
+
this.setAttribute("value", next);
|
|
115
|
+
}
|
|
116
|
+
get month() {
|
|
117
|
+
const explicit = this.#month ?? this.getAttribute("month");
|
|
118
|
+
return parse(explicit) ? explicit.slice(0, 7) : (this.value || today()).slice(0, 7);
|
|
119
|
+
}
|
|
120
|
+
set month(next) {
|
|
121
|
+
if (next == null)
|
|
122
|
+
this.removeAttribute("month");
|
|
123
|
+
else
|
|
124
|
+
this.setAttribute("month", next);
|
|
125
|
+
}
|
|
126
|
+
get min() {
|
|
127
|
+
return parse(this.getAttribute("min")) ? this.getAttribute("min") : "";
|
|
128
|
+
}
|
|
129
|
+
set min(next) {
|
|
130
|
+
if (next == null)
|
|
131
|
+
this.removeAttribute("min");
|
|
132
|
+
else
|
|
133
|
+
this.setAttribute("min", next);
|
|
134
|
+
}
|
|
135
|
+
get max() {
|
|
136
|
+
return parse(this.getAttribute("max")) ? this.getAttribute("max") : "";
|
|
137
|
+
}
|
|
138
|
+
set max(next) {
|
|
139
|
+
if (next == null)
|
|
140
|
+
this.removeAttribute("max");
|
|
141
|
+
else
|
|
142
|
+
this.setAttribute("max", next);
|
|
143
|
+
}
|
|
144
|
+
get weekStart() {
|
|
145
|
+
const value = Number(this.getAttribute("week-start"));
|
|
146
|
+
return Number.isInteger(value) && value >= 0 && value <= 6 ? value : 0;
|
|
147
|
+
}
|
|
148
|
+
set weekStart(next) {
|
|
149
|
+
this.setAttribute("week-start", String(next));
|
|
150
|
+
}
|
|
151
|
+
get locale() {
|
|
152
|
+
return this.getAttribute("locale") || this.ownerDocument?.documentElement?.lang || undefined;
|
|
153
|
+
}
|
|
154
|
+
set locale(next) {
|
|
155
|
+
if (next == null)
|
|
156
|
+
this.removeAttribute("locale");
|
|
157
|
+
else
|
|
158
|
+
this.setAttribute("locale", next);
|
|
159
|
+
}
|
|
160
|
+
#disabledDates() {
|
|
161
|
+
return new Set(tokens(this.getAttribute("disabled-dates")).filter(parse));
|
|
162
|
+
}
|
|
163
|
+
#disabledWeekdays() {
|
|
164
|
+
return new Set(tokens(this.getAttribute("disabled-weekdays")).map(Number).filter((day) => day >= 0 && day <= 6));
|
|
165
|
+
}
|
|
166
|
+
isDisabled(iso) {
|
|
167
|
+
const date = parse(iso);
|
|
168
|
+
if (!date)
|
|
169
|
+
return true;
|
|
170
|
+
if (this.min && iso < this.min)
|
|
171
|
+
return true;
|
|
172
|
+
if (this.max && iso > this.max)
|
|
173
|
+
return true;
|
|
174
|
+
if (this.#disabledWeekdays().has(date.getDay()))
|
|
175
|
+
return true;
|
|
176
|
+
return this.#disabledDates().has(iso);
|
|
177
|
+
}
|
|
178
|
+
#fallbackInput() {
|
|
179
|
+
return this.querySelector('input[type="date"], input[type="month"]');
|
|
180
|
+
}
|
|
181
|
+
connectedCallback() {
|
|
182
|
+
if (this.#upgraded)
|
|
183
|
+
return;
|
|
184
|
+
this.#upgraded = true;
|
|
185
|
+
ensureStyle(this.ownerDocument);
|
|
186
|
+
this.classList.add("b3-date-picker");
|
|
187
|
+
if (!this.hasAttribute("role"))
|
|
188
|
+
this.setAttribute("role", "group");
|
|
189
|
+
if (!this.hasAttribute("aria-label") && !this.hasAttribute("aria-labelledby"))
|
|
190
|
+
this.setAttribute("aria-label", "Choose a date");
|
|
191
|
+
const seed = this.#fallbackInput()?.value;
|
|
192
|
+
if (!this.hasAttribute("value") && seed && parse(seed))
|
|
193
|
+
this.setAttribute("value", seed);
|
|
194
|
+
this.#syncInput();
|
|
195
|
+
this.#ui ??= this.ownerDocument.createElement("div");
|
|
196
|
+
this.#ui.className = "b3-date-picker-ui";
|
|
197
|
+
for (const stray of this.querySelectorAll(":scope > .b3-date-picker-ui"))
|
|
198
|
+
if (stray !== this.#ui)
|
|
199
|
+
stray.remove();
|
|
200
|
+
this.append(this.#ui);
|
|
201
|
+
this.#listen();
|
|
202
|
+
this.#render();
|
|
203
|
+
this.#observer = new MutationObserver(() => {
|
|
204
|
+
if (!this.#ui.isConnected) {
|
|
205
|
+
this.append(this.#ui);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
this.#observer.observe(this, { childList: true });
|
|
209
|
+
}
|
|
210
|
+
disconnectedCallback() {
|
|
211
|
+
this.#controller?.abort();
|
|
212
|
+
this.#controller = null;
|
|
213
|
+
this.#observer?.disconnect();
|
|
214
|
+
this.#observer = null;
|
|
215
|
+
this.#upgraded = false;
|
|
216
|
+
}
|
|
217
|
+
attributeChangedCallback(name, previous, next) {
|
|
218
|
+
if (previous === next || !this.#upgraded)
|
|
219
|
+
return;
|
|
220
|
+
if (name === "month")
|
|
221
|
+
this.#month = null;
|
|
222
|
+
if (name === "value")
|
|
223
|
+
this.#month = this.value ? this.value.slice(0, 7) : null;
|
|
224
|
+
this.#render();
|
|
225
|
+
}
|
|
226
|
+
select(iso) {
|
|
227
|
+
if (!parse(iso) || this.isDisabled(iso))
|
|
228
|
+
return false;
|
|
229
|
+
const changed = this.value !== iso;
|
|
230
|
+
this.#focus = iso;
|
|
231
|
+
this.value = iso;
|
|
232
|
+
if (!changed)
|
|
233
|
+
this.#render();
|
|
234
|
+
const input = this.#fallbackInput();
|
|
235
|
+
if (input && this.#syncInput()) {
|
|
236
|
+
for (const type of ["input", "change"])
|
|
237
|
+
input.dispatchEvent(new Event(type, { bubbles: true }));
|
|
238
|
+
}
|
|
239
|
+
this.#emit("b3-select", { value: iso, date: parse(iso) });
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
#syncInput() {
|
|
243
|
+
const input = this.#fallbackInput();
|
|
244
|
+
if (!input)
|
|
245
|
+
return false;
|
|
246
|
+
const next = !this.value ? "" : input.type === "month" ? this.value.slice(0, 7) : this.value;
|
|
247
|
+
if (input.value === next)
|
|
248
|
+
return false;
|
|
249
|
+
input.value = next;
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
#adoptInput() {
|
|
253
|
+
const input = this.#fallbackInput();
|
|
254
|
+
if (!input)
|
|
255
|
+
return;
|
|
256
|
+
const raw = input.value;
|
|
257
|
+
const iso = !raw ? "" : input.type === "month" ? `${raw}-01` : raw;
|
|
258
|
+
if (iso === this.value)
|
|
259
|
+
return;
|
|
260
|
+
if (!iso) {
|
|
261
|
+
this.value = "";
|
|
262
|
+
this.#emit("b3-select", { value: "", date: null });
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (!this.select(iso))
|
|
266
|
+
this.#syncInput();
|
|
267
|
+
}
|
|
268
|
+
goTo(month) {
|
|
269
|
+
const target = parse(month);
|
|
270
|
+
if (!target)
|
|
271
|
+
return false;
|
|
272
|
+
const next = toIso(target).slice(0, 7);
|
|
273
|
+
if (next === this.month)
|
|
274
|
+
return true;
|
|
275
|
+
this.#month = next;
|
|
276
|
+
this.#focus = null;
|
|
277
|
+
this.#render();
|
|
278
|
+
this.#emit("b3-month", { month: next, year: target.getFullYear(), monthIndex: target.getMonth() });
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
#emit(type, detail) {
|
|
282
|
+
this.dispatchEvent(new CustomEvent(type, { bubbles: true, composed: true, detail }));
|
|
283
|
+
}
|
|
284
|
+
#weekdayNames() {
|
|
285
|
+
const long = new Intl.DateTimeFormat(this.locale, { weekday: "long" });
|
|
286
|
+
const short = new Intl.DateTimeFormat(this.locale, { weekday: "short" });
|
|
287
|
+
const names = [];
|
|
288
|
+
for (let index = 0;index < 7; index++) {
|
|
289
|
+
const date = new Date(2024, 0, 7 + (this.weekStart + index) % 7);
|
|
290
|
+
names.push({ long: long.format(date), short: short.format(date) });
|
|
291
|
+
}
|
|
292
|
+
return names;
|
|
293
|
+
}
|
|
294
|
+
#render() {
|
|
295
|
+
const document = this.ownerDocument;
|
|
296
|
+
const month = parse(this.month);
|
|
297
|
+
const year = month.getFullYear(), index = month.getMonth();
|
|
298
|
+
const total = daysInMonth(year, index);
|
|
299
|
+
const lead = (month.getDay() - this.weekStart + 7) % 7;
|
|
300
|
+
const selected = this.value;
|
|
301
|
+
const now = today();
|
|
302
|
+
if (!this.#focus || this.#focus.slice(0, 7) !== this.month) {
|
|
303
|
+
this.#focus = selected.slice(0, 7) === this.month ? selected : now.slice(0, 7) === this.month ? now : `${this.month}-01`;
|
|
304
|
+
}
|
|
305
|
+
this.#ensureBar();
|
|
306
|
+
for (const button of this.#bar.querySelectorAll(".b3-date-picker-nav"))
|
|
307
|
+
button.disabled = this.#monthOutOfRange(addMonths(`${this.month}-01`, Number(button.dataset.b3Step)));
|
|
308
|
+
this.#title.textContent = new Intl.DateTimeFormat(this.locale, { month: "long", year: "numeric" }).format(month);
|
|
309
|
+
const table = document.createElement("table");
|
|
310
|
+
table.className = "b3-date-picker-grid";
|
|
311
|
+
table.setAttribute("role", "grid");
|
|
312
|
+
table.setAttribute("aria-labelledby", this.#title.id);
|
|
313
|
+
const head = document.createElement("thead");
|
|
314
|
+
const headRow = document.createElement("tr");
|
|
315
|
+
for (const name of this.#weekdayNames()) {
|
|
316
|
+
const cell = document.createElement("th");
|
|
317
|
+
cell.scope = "col";
|
|
318
|
+
cell.setAttribute("aria-label", name.long);
|
|
319
|
+
cell.textContent = name.short;
|
|
320
|
+
headRow.append(cell);
|
|
321
|
+
}
|
|
322
|
+
head.append(headRow);
|
|
323
|
+
table.append(head);
|
|
324
|
+
const body = document.createElement("tbody");
|
|
325
|
+
const label = new Intl.DateTimeFormat(this.locale, { weekday: "long", day: "numeric", month: "long", year: "numeric" });
|
|
326
|
+
let row = document.createElement("tr");
|
|
327
|
+
for (let slot = 0;slot < lead; slot++)
|
|
328
|
+
row.append(document.createElement("td"));
|
|
329
|
+
for (let day = 1;day <= total; day++) {
|
|
330
|
+
if (row.children.length === 7) {
|
|
331
|
+
body.append(row);
|
|
332
|
+
row = document.createElement("tr");
|
|
333
|
+
}
|
|
334
|
+
const iso = `${year}-${pad(index + 1)}-${pad(day)}`;
|
|
335
|
+
const cell = document.createElement("td");
|
|
336
|
+
cell.setAttribute("role", "gridcell");
|
|
337
|
+
cell.dataset.b3Date = iso;
|
|
338
|
+
cell.textContent = String(day);
|
|
339
|
+
cell.setAttribute("aria-label", label.format(new Date(year, index, day)));
|
|
340
|
+
cell.setAttribute("aria-selected", String(iso === selected));
|
|
341
|
+
if (this.isDisabled(iso))
|
|
342
|
+
cell.setAttribute("aria-disabled", "true");
|
|
343
|
+
if (iso === now)
|
|
344
|
+
cell.dataset.b3Today = "";
|
|
345
|
+
cell.tabIndex = iso === this.#focus ? 0 : -1;
|
|
346
|
+
row.append(cell);
|
|
347
|
+
}
|
|
348
|
+
while (row.children.length < 7)
|
|
349
|
+
row.append(document.createElement("td"));
|
|
350
|
+
body.append(row);
|
|
351
|
+
table.append(body);
|
|
352
|
+
if (this.#grid?.parentNode === this.#ui)
|
|
353
|
+
this.#grid.replaceWith(table);
|
|
354
|
+
else
|
|
355
|
+
this.#ui.append(table);
|
|
356
|
+
this.#grid = table;
|
|
357
|
+
}
|
|
358
|
+
#ensureBar() {
|
|
359
|
+
if (this.#bar?.parentNode === this.#ui)
|
|
360
|
+
return;
|
|
361
|
+
const document = this.ownerDocument;
|
|
362
|
+
this.#bar ??= document.createElement("div");
|
|
363
|
+
this.#bar.className = "b3-date-picker-bar";
|
|
364
|
+
if (!this.#title) {
|
|
365
|
+
this.#title = document.createElement("div");
|
|
366
|
+
this.#title.className = "b3-date-picker-title";
|
|
367
|
+
this.#title.id = this.#titleId;
|
|
368
|
+
this.#title.setAttribute("aria-live", "polite");
|
|
369
|
+
const nav = [-1, 1].map((step) => {
|
|
370
|
+
const button = document.createElement("button");
|
|
371
|
+
button.type = "button";
|
|
372
|
+
button.className = "b3-date-picker-nav";
|
|
373
|
+
button.dataset.b3Step = String(step);
|
|
374
|
+
button.setAttribute("aria-label", step < 0 ? "Previous month" : "Next month");
|
|
375
|
+
return button;
|
|
376
|
+
});
|
|
377
|
+
this.#bar.append(nav[0], this.#title, nav[1]);
|
|
378
|
+
}
|
|
379
|
+
this.#ui.prepend(this.#bar);
|
|
380
|
+
}
|
|
381
|
+
#monthOutOfRange(iso) {
|
|
382
|
+
const date = parse(iso);
|
|
383
|
+
const last = `${iso.slice(0, 7)}-${pad(daysInMonth(date.getFullYear(), date.getMonth()))}`;
|
|
384
|
+
return this.max && `${iso.slice(0, 7)}-01` > this.max || this.min && last < this.min;
|
|
385
|
+
}
|
|
386
|
+
#cell(iso) {
|
|
387
|
+
return this.#grid?.querySelector(`td[data-b3-date="${iso}"]`);
|
|
388
|
+
}
|
|
389
|
+
#moveFocus(iso) {
|
|
390
|
+
const date = parse(iso);
|
|
391
|
+
if (!date)
|
|
392
|
+
return;
|
|
393
|
+
const month = iso.slice(0, 7);
|
|
394
|
+
this.#focus = iso;
|
|
395
|
+
if (month !== this.month) {
|
|
396
|
+
this.#month = month;
|
|
397
|
+
this.#render();
|
|
398
|
+
this.#emit("b3-month", { month, year: date.getFullYear(), monthIndex: date.getMonth() });
|
|
399
|
+
} else {
|
|
400
|
+
for (const cell2 of this.#grid.querySelectorAll("td[data-b3-date]"))
|
|
401
|
+
cell2.tabIndex = -1;
|
|
402
|
+
}
|
|
403
|
+
const cell = this.#cell(iso);
|
|
404
|
+
if (cell) {
|
|
405
|
+
cell.tabIndex = 0;
|
|
406
|
+
cell.focus();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
#listen() {
|
|
410
|
+
this.#controller = new AbortController;
|
|
411
|
+
const options = { signal: this.#controller.signal };
|
|
412
|
+
this.addEventListener("click", (event) => {
|
|
413
|
+
const nav = event.target.closest?.(".b3-date-picker-nav");
|
|
414
|
+
if (nav) {
|
|
415
|
+
this.goTo(addMonths(`${this.month}-01`, Number(nav.dataset.b3Step)));
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const cell = event.target.closest?.("td[data-b3-date]");
|
|
419
|
+
if (!cell || cell.getAttribute("aria-disabled") === "true")
|
|
420
|
+
return;
|
|
421
|
+
this.#moveFocus(cell.dataset.b3Date);
|
|
422
|
+
this.select(cell.dataset.b3Date);
|
|
423
|
+
}, options);
|
|
424
|
+
for (const type of ["input", "change"])
|
|
425
|
+
this.addEventListener(type, (event) => {
|
|
426
|
+
if (event.target === this.#fallbackInput())
|
|
427
|
+
this.#adoptInput();
|
|
428
|
+
}, options);
|
|
429
|
+
this.ownerDocument.addEventListener("reset", (event) => {
|
|
430
|
+
if (event.target?.contains?.(this))
|
|
431
|
+
setTimeout(() => this.#adoptInput(), 0);
|
|
432
|
+
}, options);
|
|
433
|
+
this.addEventListener("keydown", (event) => {
|
|
434
|
+
if (event.metaKey || event.altKey || event.ctrlKey)
|
|
435
|
+
return;
|
|
436
|
+
const cell = event.target.closest?.("td[data-b3-date]");
|
|
437
|
+
if (!cell)
|
|
438
|
+
return;
|
|
439
|
+
const from = cell.dataset.b3Date;
|
|
440
|
+
const forward = getComputedStyle(this).direction === "rtl" ? "ArrowLeft" : "ArrowRight";
|
|
441
|
+
const back = forward === "ArrowRight" ? "ArrowLeft" : "ArrowRight";
|
|
442
|
+
const weekday = (parse(from).getDay() - this.weekStart + 7) % 7;
|
|
443
|
+
let next = null;
|
|
444
|
+
switch (event.key) {
|
|
445
|
+
case forward:
|
|
446
|
+
next = addDays(from, 1);
|
|
447
|
+
break;
|
|
448
|
+
case back:
|
|
449
|
+
next = addDays(from, -1);
|
|
450
|
+
break;
|
|
451
|
+
case "ArrowDown":
|
|
452
|
+
next = addDays(from, 7);
|
|
453
|
+
break;
|
|
454
|
+
case "ArrowUp":
|
|
455
|
+
next = addDays(from, -7);
|
|
456
|
+
break;
|
|
457
|
+
case "Home":
|
|
458
|
+
next = addDays(from, -weekday);
|
|
459
|
+
break;
|
|
460
|
+
case "End":
|
|
461
|
+
next = addDays(from, 6 - weekday);
|
|
462
|
+
break;
|
|
463
|
+
case "PageUp":
|
|
464
|
+
next = addMonths(from, event.shiftKey ? -12 : -1);
|
|
465
|
+
break;
|
|
466
|
+
case "PageDown":
|
|
467
|
+
next = addMonths(from, event.shiftKey ? 12 : 1);
|
|
468
|
+
break;
|
|
469
|
+
case "Enter":
|
|
470
|
+
case " ":
|
|
471
|
+
event.preventDefault();
|
|
472
|
+
this.select(from);
|
|
473
|
+
this.#cell(from)?.focus();
|
|
474
|
+
return;
|
|
475
|
+
default:
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
event.preventDefault();
|
|
479
|
+
this.#moveFocus(next);
|
|
480
|
+
}, options);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
var unused = B3DatePicker;
|
|
484
|
+
function define(name = "b3-date-picker") {
|
|
485
|
+
if (typeof customElements === "undefined")
|
|
486
|
+
return null;
|
|
487
|
+
const existing = customElements.get(name);
|
|
488
|
+
if (existing)
|
|
489
|
+
return existing;
|
|
490
|
+
const constructor = unused;
|
|
491
|
+
unused = class extends B3DatePicker {
|
|
492
|
+
};
|
|
493
|
+
customElements.define(name, constructor);
|
|
494
|
+
return constructor;
|
|
495
|
+
}
|
|
496
|
+
define();
|
|
497
|
+
export {
|
|
498
|
+
B3DatePicker,
|
|
499
|
+
addDays,
|
|
500
|
+
addMonths,
|
|
501
|
+
daysInMonth,
|
|
502
|
+
define,
|
|
503
|
+
parse,
|
|
504
|
+
toIso,
|
|
505
|
+
today
|
|
506
|
+
};
|
package/dist/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.1.0-alpha.
|
|
3
|
-
"cssSha256": "
|
|
2
|
+
"version": "0.1.0-alpha.37",
|
|
3
|
+
"cssSha256": "1ddda2ac6a76615e6074a3c1c7cf0154056d6d2e9f2d2c2f756223d8eca2790e",
|
|
4
4
|
"classes": [
|
|
5
5
|
"b3-accordion",
|
|
6
6
|
"b3-alert",
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"b3-scroll",
|
|
126
126
|
"b3-inline"
|
|
127
127
|
],
|
|
128
|
-
"guidance": "Shell bounds the page. Stack is vertical, cluster wraps horizontal peers, grid fits columns, split separates two groups. Override --b3-space locally. Preserve meaningful DOM order. Default to phone and desktop support. Use intrinsic peer columns and wrapping before media queries; bound reading/forms separately from the page. Set --b3-content for shell width. Read cross-screen.md for composition choices and targeted verification. In a bounded b3-stack, b3-scroll makes one body independently scrollable while sibling heading/actions stay in flow. Supply a meaningful height or max-height; scrolling cannot occur without a bound. Name a keyboard-focusable scroll region with tabindex=0 and aria-labelledby. Reuse the same atom in panels, dialogs and sheets. Inline keeps a small icon/text or label/badge group together, vertically centers peers and lets the text itself wrap. Use cluster for independently wrapping peers; use inline when wrapping the icon away from its label would break the meaning. Set --b3-grid-min to the minimum useful peer width (e.g. 8rem for concise metrics); the same grid then fits columns without per-screen column counts. Cluster and split children can shrink below intrinsic width, so a label wrapping a full-width select does not force the page wider.",
|
|
128
|
+
"guidance": "Shell bounds the page. Stack is vertical, cluster wraps horizontal peers, grid fits columns, split separates two groups. Override --b3-space locally. Preserve meaningful DOM order. Default to phone and desktop support. Use intrinsic peer columns and wrapping before media queries; bound reading/forms separately from the page. Set --b3-content for shell width. Read cross-screen.md for composition choices and targeted verification. In a bounded b3-stack, b3-scroll makes one body independently scrollable while sibling heading/actions stay in flow. Supply a meaningful height or max-height; scrolling cannot occur without a bound. Name a keyboard-focusable scroll region with tabindex=0 and aria-labelledby. Reuse the same atom in panels, dialogs and sheets. A direct scroll body in dialog.b3-stack retains a minimum reading area; on short screens with enlarged text, the outer dialog scrolls as needed to reach its actions instead of collapsing the body. Inline keeps a small icon/text or label/badge group together, vertically centers peers and lets the text itself wrap. Use cluster for independently wrapping peers; use inline when wrapping the icon away from its label would break the meaning. Set --b3-grid-min to the minimum useful peer width (e.g. 8rem for concise metrics); the same grid then fits columns without per-screen column counts. Cluster and split children can shrink below intrinsic width, so a label wrapping a full-width select does not force the page wider.",
|
|
129
129
|
"example": "<main class=\"b3-shell b3-stack\"><header class=\"b3-split\">…</header></main>"
|
|
130
130
|
},
|
|
131
131
|
{
|
|
@@ -200,8 +200,8 @@
|
|
|
200
200
|
"b3-cover",
|
|
201
201
|
"b3-reel"
|
|
202
202
|
],
|
|
203
|
-
"guidance": "Page/body form a full-height document. App-layout supplies a sidebar and content region, stacking below 48rem. Center aligns its children. Cover gives a hero room; reel provides intentional horizontal scrolling. Preserve document order and label scrollable collections. A reel whose direct children are b3-badge chips is a chip scroller: intrinsic chip widths, room for hit areas, and an inline-end fade that clears at the scroll end; it does not shrink inside a b3-stack.",
|
|
204
|
-
"example": "<div class=\"b3-app-layout\"><aside class=\"b3-sidebar\">Navigation</aside><main class=\"b3-page\"><header>Page heading</header><div class=\"b3-page-body b3-shell\">Content</div><footer>Footer</footer></main></div>"
|
|
203
|
+
"guidance": "Page/body form a full-height document. App-layout supplies a sidebar and content region, stacking below 48rem. Center aligns its children. Cover gives a hero room; reel provides intentional horizontal scrolling. Preserve document order and label scrollable collections. A reel whose direct children are b3-badge chips is a chip scroller: intrinsic chip widths, room for hit areas, and an inline-end fade that clears at the scroll end; it does not shrink inside a b3-stack. Optional mount() wires .b3-reel[data-b3-reel]: reel.b3Reel exposes index (get/set), count and to(index, behavior), the current slide is mirrored on data-b3-reel-index, and a bubbling b3-reel-change CustomEvent carries {index, count}; a smooth scroll passing over slides reports each one, so treat it as a position, not a commit. Index counts direct children and means the slide at the inline-start edge, so RTL needs no separate markup. Dots and arrows are ordinary buttons with data-b3-reel-to set to an index, next or previous, plus aria-controls pointing at the reel id; the current numbered control gets aria-current=true. Arrow keys, Home and End move the reel region only when it is itself focused, respecting RTL, so a control or input inside a slide keeps its own keys; the index clamps and never wraps. That focus is the whole keyboard API, and a reel whose slides hold links or buttons is skipped in tab order entirely, so give a controlled reel tabindex=0 with a label, as a b3-scroll region does; mount() adds tabindex=0 when the markup omits it. Slides with no box (hidden or display:none) are skipped, and a reel with no visible slides reports index -1 and carries no data-b3-reel-index. The cleanup mount() returns removes reel.b3Reel. A reel without data-b3-reel keeps plain CSS scroll-snap behaviour and gains no attribute, controller or listener.",
|
|
204
|
+
"example": "<div class=\"b3-app-layout\"><aside class=\"b3-sidebar\">Navigation</aside><main class=\"b3-page\"><header>Page heading</header><div class=\"b3-page-body b3-shell\">Content</div><footer>Footer</footer></main></div><div class=\"b3-reel\" id=\"gallery\" data-b3-reel tabindex=\"0\" role=\"region\" aria-label=\"Gallery\"><article class=\"b3-surface\">One</article><article class=\"b3-surface\">Two</article></div><div class=\"b3-cluster\"><button class=\"b3-button\" data-b3-reel-to=\"previous\" aria-controls=\"gallery\" aria-label=\"Previous slide\">‹</button><button class=\"b3-button\" data-b3-reel-to=\"0\" aria-controls=\"gallery\" aria-label=\"Slide 1\">1</button><button class=\"b3-button\" data-b3-reel-to=\"next\" aria-controls=\"gallery\" aria-label=\"Next slide\">›</button></div>"
|
|
205
205
|
},
|
|
206
206
|
{
|
|
207
207
|
"id": "control-structure",
|
|
@@ -408,7 +408,7 @@
|
|
|
408
408
|
"b3-sheet",
|
|
409
409
|
"b3-sheet-handle"
|
|
410
410
|
],
|
|
411
|
-
"guidance": "For new apps with persistent navigation, read app-frame.md first: grid owns the navigation height rather than a fixed-padding estimate. Use b3-mobile-app on the app container with data-b3-platform=ios or android. Native anchors carry navigation; app owns URLs/history and aria-current=page. Bottom navigation stays available across primary destinations. Use dialog.b3-sheet with showModal(), a label and explicit cancel; app owns form state and focus restoration. Layout reserves env safe-area insets and targets 44/48 CSS pixels as a starting treatment, not proof of physical platform sizing. Test software keyboard, large text, orientation, real touch and device insets. Never draw fake OS status/gesture bars inside app content. Native runtime and platform fidelity require separate qualification. Default app width supports phone and desktop up to70rem; use intrinsic wrapping grids for content. Set --b3-app-width only for an intentional narrower surface. A platform treatment does not imply a phone-only layout. For a scrollable sheet use dialog.b3-sheet.b3-stack with a direct b3-scroll body and
|
|
411
|
+
"guidance": "For new apps with persistent navigation, read app-frame.md first: grid owns the navigation height rather than a fixed-padding estimate. Use b3-mobile-app on the app container with data-b3-platform=ios or android. Native anchors carry navigation; app owns URLs/history and aria-current=page. Bottom navigation stays available across primary destinations. Use dialog.b3-sheet with showModal(), a label and explicit cancel; app owns form state and focus restoration. Layout reserves env safe-area insets and targets 44/48 CSS pixels as a starting treatment, not proof of physical platform sizing. Test software keyboard, large text, orientation, real touch and device insets. Never draw fake OS status/gesture bars inside app content. Native runtime and platform fidelity require separate qualification. Default app width supports phone and desktop up to70rem; use intrinsic wrapping grids for content. Set --b3-app-width only for an intentional narrower surface. A platform treatment does not imply a phone-only layout. For a scrollable sheet use dialog.b3-sheet.b3-stack with a direct b3-scroll body and nonshrinking heading/actions. The outer dialog can scroll when enlarged text exceeds a short viewport; do not assume the footer is always pinned. For optional handle dragging add data-b3-drag=dismiss and button.b3-sheet-handle with data-b3-close and aria-label=\"Close sheet\". mount() handles drag-to-dismiss through the cancel event. Body gestures remain native scrolling. A handle click/keyboard activation also closes. No multiple detents or content-wide drag are implied. The mounted helper gives a labeled sheet heading initial focus unless the app declares an explicit autofocus target; handles remain keyboard reachable. The sheet owns outer padding, viewport-aware horizontal insets and the bottom safe area: do not repeat these on its header/body/footer. Keep b3-scroll intrinsic sizing instead of overriding it with flex:1 or a zero flex basis. Sheets fit content up to 85dvh and a 32rem reading width by default; --b3-overlay-width is an explicit width escape hatch for denser content. Use a b3-stack footer for a full-width primary action, and group descriptive row text in a stack rather than competing columns. b3-mobile-app already reserves bottom space for its fixed navigation. Do not add a second matching bottom padding to a child panel. Use b3-app-bar or an explicit comfortable top inset; a safe-area value of zero is not ordinary content spacing. Bottom links carry an icon and a label; the aria-current=page link gets a tinted indicator and unsized svg icons render at 1.375rem.",
|
|
412
412
|
"example": "<div class=\"b3-mobile-app b3-app-frame\" data-b3-platform=\"ios\"><header class=\"b3-app-bar\">Today</header><main><ul class=\"b3-mobile-list\"><li><a class=\"b3-mobile-row\" href=\"#detail\">Read a few pages</a></li></ul></main><nav class=\"b3-bottom-nav\" aria-label=\"Main\"><a class=\"b3-bottom-link\" href=\"#today\" aria-current=\"page\">Today</a></nav></div>"
|
|
413
413
|
},
|
|
414
414
|
{
|
|
@@ -450,6 +450,7 @@
|
|
|
450
450
|
"mobile.md",
|
|
451
451
|
"app-frame.md",
|
|
452
452
|
"cross-screen.md",
|
|
453
|
+
"date-picker.md",
|
|
453
454
|
"editable-filtered-rows.md",
|
|
454
455
|
"icons.md",
|
|
455
456
|
"image-viewer.md",
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Date picker element
|
|
2
|
+
|
|
3
|
+
`<b3-date-picker>` is an opt-in custom element for the one thing markup and CSS cannot carry: a
|
|
4
|
+
month grid with correct calendar arithmetic. It is not part of `ui.js`; import it only on pages
|
|
5
|
+
that need it. Never hand-roll `daysInMonth`, `getUTCDay` or `toISOString().slice(0,10)` again.
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<link rel="stylesheet" href="@livx.cc/bare-v3/css">
|
|
9
|
+
<script type="module" src="@livx.cc/bare-v3/elements/date-picker"></script>
|
|
10
|
+
|
|
11
|
+
<!-- Without the module this is just the native input, and the form still works. -->
|
|
12
|
+
<b3-date-picker value="2026-03-18" min="2026-01-05" max="2026-12-20" disabled-weekdays="6">
|
|
13
|
+
<label class="b3-field">Date <input type="date" name="date"></label>
|
|
14
|
+
</b3-date-picker>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Light DOM, no shadow root: bare.css tokens, `data-b3-theme` and your own selectors all reach
|
|
18
|
+
inside. Always author the `<input type="date">` yourself — that child is the degraded experience,
|
|
19
|
+
it stays the form's value carrier, and the element hides it and renders the grid in its place. It
|
|
20
|
+
never removes or replaces your markup.
|
|
21
|
+
|
|
22
|
+
The two stay in sync **both ways**. Every selection is mirrored onto the input (firing `input` and
|
|
23
|
+
`change`, so a form library sees what it would see from a real input), an authored `value` reaches
|
|
24
|
+
the input before the user touches anything, and every write *to* the input moves the grid —
|
|
25
|
+
`form.reset()`, a framework binding, autofill. Without that last direction a reset would clear the
|
|
26
|
+
submitted value while the calendar went on showing the old day. Clearing the input emits
|
|
27
|
+
`b3-select` with `value: ''`; a write the element refuses (a disabled or malformed day) is undone
|
|
28
|
+
and the input is put back to the element's own value, so the two never disagree.
|
|
29
|
+
|
|
30
|
+
`required` on that input works. Because a control that is not rendered cannot be focused — Chrome
|
|
31
|
+
then refuses to submit and has nowhere to put the validation bubble, so the button just dies — the
|
|
32
|
+
element clips a `required` input to a point instead of removing it. The grid is still the visible
|
|
33
|
+
control; the browser's own "please fill in this field" still appears and still blocks the submit.
|
|
34
|
+
|
|
35
|
+
## Local days, not UTC instants
|
|
36
|
+
|
|
37
|
+
Every date in and out of this element is a **local calendar day**, `YYYY-MM-DD`. That is the whole
|
|
38
|
+
point: `toISOString().slice(0,10)` is the *UTC* day and is wrong for 14 of 24 hours in Kiritimati
|
|
39
|
+
and 11 of 24 in Niue, and `new Date('2026-03-18')` is UTC midnight, which reads back as the 17th
|
|
40
|
+
anywhere west of Greenwich. Selecting "today" in Auckland at 09:00 with the UTC-naive version
|
|
41
|
+
hands your backend yesterday.
|
|
42
|
+
|
|
43
|
+
If you need the same arithmetic outside the grid, import it rather than rewriting it:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { today, parse, toIso, addDays, addMonths, daysInMonth }
|
|
47
|
+
from '@livx.cc/bare-v3/elements/date-picker';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`parse` returns `null` for `2026-02-30`, `2026-13-01` and anything that is not a date, instead of
|
|
51
|
+
silently rolling over into March. `addDays` crosses a DST boundary as one calendar day, which
|
|
52
|
+
fixed-millisecond arithmetic does not.
|
|
53
|
+
|
|
54
|
+
The hand-rolled shape this replaces is `new Date(Date.UTC(y, m + 1, 0)).getUTCDate()` for the
|
|
55
|
+
month's length and `first.getUTCDay()` for the leading blanks. That pair lays out the grid
|
|
56
|
+
consistently, and then quietly disagrees with the user's own device about which cell is today.
|
|
57
|
+
|
|
58
|
+
## API
|
|
59
|
+
|
|
60
|
+
| Attribute | Meaning |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| `value` | The selected day, `YYYY-MM-DD`. An invalid one is ignored, not rendered. |
|
|
63
|
+
| `month` | The month to open on, `YYYY-MM`. Defaults to the selection's month, then to today's. A starting point, not a pin: navigating, or choosing a day in another month, moves the grid. |
|
|
64
|
+
| `min` / `max` | Selectable range, inclusive. Days outside it are disabled, and a month step that leads nowhere is disabled too. |
|
|
65
|
+
| `disabled-dates` | Space- or comma-separated `YYYY-MM-DD` days (booked, sold out, closed). |
|
|
66
|
+
| `disabled-weekdays` | Space- or comma-separated weekday numbers, `0` = Sunday. |
|
|
67
|
+
| `week-start` | First column's weekday, `0`–`6`. Default `0` (Sunday). Anything else is ignored. |
|
|
68
|
+
| `locale` | BCP-47 tag for month and weekday names. Defaults to `<html lang>`, then the browser. |
|
|
69
|
+
|
|
70
|
+
Properties: `value`, `month`, `min`, `max`, `weekStart`, `locale`.
|
|
71
|
+
Methods: `select(iso)` (returns `false` and changes nothing if the day is disabled or malformed),
|
|
72
|
+
`goTo(month)`, `isDisabled(iso)`.
|
|
73
|
+
Events: `b3-select` (`detail: { value, date }`) and `b3-month`
|
|
74
|
+
(`detail: { month, year, monthIndex }`). Both are plain bubbling `CustomEvent`s, so they work
|
|
75
|
+
without a framework wrapper.
|
|
76
|
+
|
|
77
|
+
The element never selects on its own and never closes anything: it reports, and the owner decides.
|
|
78
|
+
|
|
79
|
+
### Decorating days
|
|
80
|
+
|
|
81
|
+
There is no shadow root and every day is `td[data-b3-date="YYYY-MM-DD"]`, so per-day marks — a
|
|
82
|
+
logged entry, a holiday, a dot — are your own CSS or a one-line `querySelector`, with no API here:
|
|
83
|
+
|
|
84
|
+
```css
|
|
85
|
+
.b3-date-picker td[data-b3-date="2026-03-18"]::after { content: "\2022"; display: block; }
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Another tag name
|
|
89
|
+
|
|
90
|
+
`import { define } from '@livx.cc/bare-v3/elements/date-picker'` and call `define('my-calendar')`.
|
|
91
|
+
The default tag registers on import; each further name gets its own subclass. Styling follows the
|
|
92
|
+
`b3-date-picker` class the element adds to itself, not the tag, so a renamed picker looks the same.
|
|
93
|
+
|
|
94
|
+
## Accessibility
|
|
95
|
+
|
|
96
|
+
The grid is a `role="grid"` labelled by the month heading, its days are `gridcell`s with
|
|
97
|
+
`aria-selected` and `aria-disabled`, and each one is named with the full spoken date rather than a
|
|
98
|
+
bare number. Focus roves: exactly one cell is in the tab order, so `Tab` enters and leaves the
|
|
99
|
+
grid in one step. The month heading is an `aria-live="polite"` region — the
|
|
100
|
+
*same* node for the life of the element, with only its text rewritten, because an AT announces
|
|
101
|
+
mutations inside a region it is already tracking and a heading rebuilt on every render would
|
|
102
|
+
arrive with its text already in place and go unspoken.
|
|
103
|
+
|
|
104
|
+
Keyboard: arrows move a day and a week, `Home`/`End` jump to the ends of the week, `PageUp`/
|
|
105
|
+
`PageDown` change month (with `Shift`, year), `Enter`/`Space` select. Arrowing off the edge of the
|
|
106
|
+
month pulls the neighbouring month in rather than stalling.
|
|
107
|
+
|
|
108
|
+
## RTL and Hebrew
|
|
109
|
+
|
|
110
|
+
Set `dir="rtl"` (or `lang="he"` with a document `dir`) on an ancestor; the element inherits it and
|
|
111
|
+
needs nothing else. The grid flows right-to-left, the first weekday column lands on the right, the
|
|
112
|
+
month-step chevrons mirror, and `locale` gives Hebrew month and weekday names. Arrow keys follow
|
|
113
|
+
the *visual* neighbour, so `ArrowLeft` moves forward a day in RTL — hard-coding `ArrowRight` as
|
|
114
|
+
"next" is the bug this handles for you.
|
|
115
|
+
|
|
116
|
+
Israeli calendars start on Sunday, which is the default; European ones want `week-start="1"`.
|
|
117
|
+
|
|
118
|
+
## Frameworks
|
|
119
|
+
|
|
120
|
+
Vue 3 binds and listens natively — `:value`, `@b3-select` — once
|
|
121
|
+
`app.config.compilerOptions.isCustomElement` accepts the `b3-` prefix.
|
|
122
|
+
|
|
123
|
+
React 18 has no custom-element property or event support: every value is stringified onto an
|
|
124
|
+
attribute, so pass `value={value || undefined}` (never `null`), and attach `b3-select` on a ref.
|
|
125
|
+
React 19 removes both caveats. In either, a re-render that re-owns the element's children leaves
|
|
126
|
+
the grid standing — the element keeps its own single node and re-attaches it if the framework
|
|
127
|
+
drops it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Composition
|
|
2
2
|
|
|
3
|
-
Shell bounds the page. Stack is vertical, cluster wraps horizontal peers, grid fits columns, split separates two groups. Override --b3-space locally. Preserve meaningful DOM order. Default to phone and desktop support. Use intrinsic peer columns and wrapping before media queries; bound reading/forms separately from the page. Set --b3-content for shell width. Read cross-screen.md for composition choices and targeted verification. In a bounded b3-stack, b3-scroll makes one body independently scrollable while sibling heading/actions stay in flow. Supply a meaningful height or max-height; scrolling cannot occur without a bound. Name a keyboard-focusable scroll region with tabindex=0 and aria-labelledby. Reuse the same atom in panels, dialogs and sheets. Inline keeps a small icon/text or label/badge group together, vertically centers peers and lets the text itself wrap. Use cluster for independently wrapping peers; use inline when wrapping the icon away from its label would break the meaning. Set --b3-grid-min to the minimum useful peer width (e.g. 8rem for concise metrics); the same grid then fits columns without per-screen column counts. Cluster and split children can shrink below intrinsic width, so a label wrapping a full-width select does not force the page wider.
|
|
3
|
+
Shell bounds the page. Stack is vertical, cluster wraps horizontal peers, grid fits columns, split separates two groups. Override --b3-space locally. Preserve meaningful DOM order. Default to phone and desktop support. Use intrinsic peer columns and wrapping before media queries; bound reading/forms separately from the page. Set --b3-content for shell width. Read cross-screen.md for composition choices and targeted verification. In a bounded b3-stack, b3-scroll makes one body independently scrollable while sibling heading/actions stay in flow. Supply a meaningful height or max-height; scrolling cannot occur without a bound. Name a keyboard-focusable scroll region with tabindex=0 and aria-labelledby. Reuse the same atom in panels, dialogs and sheets. A direct scroll body in dialog.b3-stack retains a minimum reading area; on short screens with enlarged text, the outer dialog scrolls as needed to reach its actions instead of collapsing the body. Inline keeps a small icon/text or label/badge group together, vertically centers peers and lets the text itself wrap. Use cluster for independently wrapping peers; use inline when wrapping the icon away from its label would break the meaning. Set --b3-grid-min to the minimum useful peer width (e.g. 8rem for concise metrics); the same grid then fits columns without per-screen column counts. Cluster and split children can shrink below intrinsic width, so a label wrapping a full-width select does not force the page wider.
|
|
4
4
|
|
|
5
5
|
Classes: b3-shell, b3-stack, b3-cluster, b3-grid, b3-split, b3-scroll, b3-inline
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Mobile app composition
|
|
2
2
|
|
|
3
|
-
For new apps with persistent navigation, read app-frame.md first: grid owns the navigation height rather than a fixed-padding estimate. Use b3-mobile-app on the app container with data-b3-platform=ios or android. Native anchors carry navigation; app owns URLs/history and aria-current=page. Bottom navigation stays available across primary destinations. Use dialog.b3-sheet with showModal(), a label and explicit cancel; app owns form state and focus restoration. Layout reserves env safe-area insets and targets 44/48 CSS pixels as a starting treatment, not proof of physical platform sizing. Test software keyboard, large text, orientation, real touch and device insets. Never draw fake OS status/gesture bars inside app content. Native runtime and platform fidelity require separate qualification. Default app width supports phone and desktop up to70rem; use intrinsic wrapping grids for content. Set --b3-app-width only for an intentional narrower surface. A platform treatment does not imply a phone-only layout. For a scrollable sheet use dialog.b3-sheet.b3-stack with a direct b3-scroll body and
|
|
3
|
+
For new apps with persistent navigation, read app-frame.md first: grid owns the navigation height rather than a fixed-padding estimate. Use b3-mobile-app on the app container with data-b3-platform=ios or android. Native anchors carry navigation; app owns URLs/history and aria-current=page. Bottom navigation stays available across primary destinations. Use dialog.b3-sheet with showModal(), a label and explicit cancel; app owns form state and focus restoration. Layout reserves env safe-area insets and targets 44/48 CSS pixels as a starting treatment, not proof of physical platform sizing. Test software keyboard, large text, orientation, real touch and device insets. Never draw fake OS status/gesture bars inside app content. Native runtime and platform fidelity require separate qualification. Default app width supports phone and desktop up to70rem; use intrinsic wrapping grids for content. Set --b3-app-width only for an intentional narrower surface. A platform treatment does not imply a phone-only layout. For a scrollable sheet use dialog.b3-sheet.b3-stack with a direct b3-scroll body and nonshrinking heading/actions. The outer dialog can scroll when enlarged text exceeds a short viewport; do not assume the footer is always pinned. For optional handle dragging add data-b3-drag=dismiss and button.b3-sheet-handle with data-b3-close and aria-label="Close sheet". mount() handles drag-to-dismiss through the cancel event. Body gestures remain native scrolling. A handle click/keyboard activation also closes. No multiple detents or content-wide drag are implied. The mounted helper gives a labeled sheet heading initial focus unless the app declares an explicit autofocus target; handles remain keyboard reachable. The sheet owns outer padding, viewport-aware horizontal insets and the bottom safe area: do not repeat these on its header/body/footer. Keep b3-scroll intrinsic sizing instead of overriding it with flex:1 or a zero flex basis. Sheets fit content up to 85dvh and a 32rem reading width by default; --b3-overlay-width is an explicit width escape hatch for denser content. Use a b3-stack footer for a full-width primary action, and group descriptive row text in a stack rather than competing columns. b3-mobile-app already reserves bottom space for its fixed navigation. Do not add a second matching bottom padding to a child panel. Use b3-app-bar or an explicit comfortable top inset; a safe-area value of zero is not ordinary content spacing. Bottom links carry an icon and a label; the aria-current=page link gets a tinted indicator and unsized svg icons render at 1.375rem.
|
|
4
4
|
|
|
5
5
|
Classes: b3-mobile-app, b3-app-bar, b3-bottom-nav, b3-bottom-link, b3-mobile-list, b3-mobile-row, b3-sheet, b3-sheet-handle
|
|
6
6
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Page composition
|
|
2
2
|
|
|
3
|
-
Page/body form a full-height document. App-layout supplies a sidebar and content region, stacking below 48rem. Center aligns its children. Cover gives a hero room; reel provides intentional horizontal scrolling. Preserve document order and label scrollable collections. A reel whose direct children are b3-badge chips is a chip scroller: intrinsic chip widths, room for hit areas, and an inline-end fade that clears at the scroll end; it does not shrink inside a b3-stack.
|
|
3
|
+
Page/body form a full-height document. App-layout supplies a sidebar and content region, stacking below 48rem. Center aligns its children. Cover gives a hero room; reel provides intentional horizontal scrolling. Preserve document order and label scrollable collections. A reel whose direct children are b3-badge chips is a chip scroller: intrinsic chip widths, room for hit areas, and an inline-end fade that clears at the scroll end; it does not shrink inside a b3-stack. Optional mount() wires .b3-reel[data-b3-reel]: reel.b3Reel exposes index (get/set), count and to(index, behavior), the current slide is mirrored on data-b3-reel-index, and a bubbling b3-reel-change CustomEvent carries {index, count}; a smooth scroll passing over slides reports each one, so treat it as a position, not a commit. Index counts direct children and means the slide at the inline-start edge, so RTL needs no separate markup. Dots and arrows are ordinary buttons with data-b3-reel-to set to an index, next or previous, plus aria-controls pointing at the reel id; the current numbered control gets aria-current=true. Arrow keys, Home and End move the reel region only when it is itself focused, respecting RTL, so a control or input inside a slide keeps its own keys; the index clamps and never wraps. That focus is the whole keyboard API, and a reel whose slides hold links or buttons is skipped in tab order entirely, so give a controlled reel tabindex=0 with a label, as a b3-scroll region does; mount() adds tabindex=0 when the markup omits it. Slides with no box (hidden or display:none) are skipped, and a reel with no visible slides reports index -1 and carries no data-b3-reel-index. The cleanup mount() returns removes reel.b3Reel. A reel without data-b3-reel keeps plain CSS scroll-snap behaviour and gains no attribute, controller or listener.
|
|
4
4
|
|
|
5
5
|
Classes: b3-page, b3-page-body, b3-app-layout, b3-sidebar, b3-center, b3-cover, b3-reel
|
|
6
6
|
|
|
7
7
|
```html
|
|
8
|
-
<div class="b3-app-layout"><aside class="b3-sidebar">Navigation</aside><main class="b3-page"><header>Page heading</header><div class="b3-page-body b3-shell">Content</div><footer>Footer</footer></main></div>
|
|
8
|
+
<div class="b3-app-layout"><aside class="b3-sidebar">Navigation</aside><main class="b3-page"><header>Page heading</header><div class="b3-page-body b3-shell">Content</div><footer>Footer</footer></main></div><div class="b3-reel" id="gallery" data-b3-reel tabindex="0" role="region" aria-label="Gallery"><article class="b3-surface">One</article><article class="b3-surface">Two</article></div><div class="b3-cluster"><button class="b3-button" data-b3-reel-to="previous" aria-controls="gallery" aria-label="Previous slide">‹</button><button class="b3-button" data-b3-reel-to="0" aria-controls="gallery" aria-label="Slide 1">1</button><button class="b3-button" data-b3-reel-to="next" aria-controls="gallery" aria-label="Next slide">›</button></div>
|
|
9
9
|
```
|
package/dist/ui.js
CHANGED
|
@@ -193,6 +193,114 @@ function tabs({ root, document: document2, find, options }) {
|
|
|
193
193
|
}, options);
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// src/interactions/reel.js
|
|
197
|
+
function reel({ root, document: document2, find, options }) {
|
|
198
|
+
const view = document2.defaultView;
|
|
199
|
+
const rtl = (element) => view.getComputedStyle(element).direction === "rtl";
|
|
200
|
+
const slides = (element) => [...element.children].filter((child) => child.getClientRects().length > 0);
|
|
201
|
+
const offset = (element, slide) => {
|
|
202
|
+
const box = element.getBoundingClientRect();
|
|
203
|
+
const item = slide.getBoundingClientRect();
|
|
204
|
+
return rtl(element) ? box.right - item.right : item.left - box.left;
|
|
205
|
+
};
|
|
206
|
+
const read = (element) => {
|
|
207
|
+
let best = -1;
|
|
208
|
+
let distance = Infinity;
|
|
209
|
+
slides(element).forEach((slide, index) => {
|
|
210
|
+
const gap = Math.abs(offset(element, slide));
|
|
211
|
+
if (gap < distance - 1) {
|
|
212
|
+
distance = gap;
|
|
213
|
+
best = index;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
return best;
|
|
217
|
+
};
|
|
218
|
+
const clamp = (element, index) => Math.max(0, Math.min(slides(element).length - 1, Math.trunc(index) || 0));
|
|
219
|
+
const controls = (element) => [...root.querySelectorAll("[data-b3-reel-to]")].filter((button) => find(button.getAttribute("aria-controls")) === element);
|
|
220
|
+
const sync = (element, emit = true) => {
|
|
221
|
+
const index = read(element);
|
|
222
|
+
const previous = element.dataset.b3ReelIndex;
|
|
223
|
+
if (index < 0)
|
|
224
|
+
delete element.dataset.b3ReelIndex;
|
|
225
|
+
else
|
|
226
|
+
element.dataset.b3ReelIndex = String(index);
|
|
227
|
+
for (const button of controls(element)) {
|
|
228
|
+
const value = button.dataset.b3ReelTo;
|
|
229
|
+
if (String(index) === value)
|
|
230
|
+
button.setAttribute("aria-current", "true");
|
|
231
|
+
else if (Number.isInteger(Number(value)))
|
|
232
|
+
button.removeAttribute("aria-current");
|
|
233
|
+
}
|
|
234
|
+
if (emit && previous !== undefined && previous !== String(index))
|
|
235
|
+
element.dispatchEvent(new CustomEvent("b3-reel-change", { bubbles: true, detail: { index, count: slides(element).length } }));
|
|
236
|
+
};
|
|
237
|
+
const go = (element, index, behavior = "smooth") => {
|
|
238
|
+
const slide = slides(element)[clamp(element, index)];
|
|
239
|
+
if (!slide)
|
|
240
|
+
return;
|
|
241
|
+
const distance = offset(element, slide);
|
|
242
|
+
element.scrollBy({ left: rtl(element) ? -distance : distance, behavior });
|
|
243
|
+
};
|
|
244
|
+
for (const element of root.querySelectorAll(".b3-reel[data-b3-reel]")) {
|
|
245
|
+
if (!element.hasAttribute("tabindex"))
|
|
246
|
+
element.tabIndex = 0;
|
|
247
|
+
element.b3Reel = {
|
|
248
|
+
get index() {
|
|
249
|
+
return read(element);
|
|
250
|
+
},
|
|
251
|
+
set index(value) {
|
|
252
|
+
go(element, value);
|
|
253
|
+
},
|
|
254
|
+
get count() {
|
|
255
|
+
return slides(element).length;
|
|
256
|
+
},
|
|
257
|
+
to: (index, behavior) => go(element, index, behavior)
|
|
258
|
+
};
|
|
259
|
+
const observer = new view.ResizeObserver(() => sync(element, false));
|
|
260
|
+
observer.observe(element);
|
|
261
|
+
options?.signal?.addEventListener("abort", () => {
|
|
262
|
+
delete element.b3Reel;
|
|
263
|
+
observer.disconnect();
|
|
264
|
+
}, { once: true });
|
|
265
|
+
let frame = 0;
|
|
266
|
+
element.addEventListener("scroll", () => {
|
|
267
|
+
view.cancelAnimationFrame(frame);
|
|
268
|
+
frame = view.requestAnimationFrame(() => sync(element));
|
|
269
|
+
}, options);
|
|
270
|
+
sync(element, false);
|
|
271
|
+
}
|
|
272
|
+
root.addEventListener("click", (event) => {
|
|
273
|
+
const button = event.target.closest?.("[data-b3-reel-to]");
|
|
274
|
+
const element = button && find(button.getAttribute("aria-controls"));
|
|
275
|
+
if (!element?.b3Reel)
|
|
276
|
+
return;
|
|
277
|
+
const value = button.dataset.b3ReelTo;
|
|
278
|
+
const index = element.b3Reel.index;
|
|
279
|
+
go(element, value === "next" ? index + 1 : value === "previous" ? index - 1 : Number(value));
|
|
280
|
+
}, options);
|
|
281
|
+
root.addEventListener("keydown", (event) => {
|
|
282
|
+
const element = event.target;
|
|
283
|
+
if (!element.b3Reel)
|
|
284
|
+
return;
|
|
285
|
+
const index = element.b3Reel.index;
|
|
286
|
+
const forward = rtl(element) ? "ArrowLeft" : "ArrowRight";
|
|
287
|
+
const back = rtl(element) ? "ArrowRight" : "ArrowLeft";
|
|
288
|
+
let destination;
|
|
289
|
+
if (event.key === forward)
|
|
290
|
+
destination = index + 1;
|
|
291
|
+
if (event.key === back)
|
|
292
|
+
destination = index - 1;
|
|
293
|
+
if (event.key === "Home")
|
|
294
|
+
destination = 0;
|
|
295
|
+
if (event.key === "End")
|
|
296
|
+
destination = slides(element).length - 1;
|
|
297
|
+
if (destination === undefined)
|
|
298
|
+
return;
|
|
299
|
+
event.preventDefault();
|
|
300
|
+
go(element, destination);
|
|
301
|
+
}, options);
|
|
302
|
+
}
|
|
303
|
+
|
|
196
304
|
// src/interactions/disclosures.js
|
|
197
305
|
function disclosures({ root, document: document2, options }) {
|
|
198
306
|
function placeDisclosure(disclosure) {
|
|
@@ -604,6 +712,7 @@ function mount(root = document) {
|
|
|
604
712
|
};
|
|
605
713
|
const context = { root, document: document2, find, options };
|
|
606
714
|
tabs(context);
|
|
715
|
+
reel(context);
|
|
607
716
|
disclosures(context);
|
|
608
717
|
dialogs(context);
|
|
609
718
|
toasts(context);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livx.cc/bare-v3",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.37",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"./manifest": "./dist/manifest.json",
|
|
13
13
|
"./references/*": "./dist/references/*",
|
|
14
14
|
"./ui": "./dist/ui.js",
|
|
15
|
-
"./elements/image-viewer": "./dist/elements/image-viewer.js"
|
|
15
|
+
"./elements/image-viewer": "./dist/elements/image-viewer.js",
|
|
16
|
+
"./elements/date-picker": "./dist/elements/date-picker.js"
|
|
16
17
|
},
|
|
17
18
|
"scripts": {
|
|
18
19
|
"build": "bun scripts/build.ts",
|