{
 "id": "time-slots",
 "name": "Time slots",
 "purpose": "Free times grouped by day, one button per time, with the time zone stated and a plain line for a day with nothing free.",
 "use_when": [
  "when someone wants to book or move an appointment and needs to pick one of the free times",
  "picking one free time for an appointment, a call or a delivery window, over one to seven days"
 ],
 "avoid_when": [
  "picking a date range or dates months ahead: use date-range-picker",
  "a day's existing plan to read: use calendar-agenda",
  "only two or three times: quick-replies may be enough"
 ],
 "type": "form",
 "style": "friendly",
 "width": "medium",
 "tags": {
  "audience": "work",
  "industries": [
   "health",
   "home",
   "events",
   "saas",
   "any"
  ],
  "keywords": [
   "booking",
   "schedule",
   "appointment",
   "times",
   "calendar"
  ]
 },
 "root": ".odl-time-slots",
 "parts": [
  {
   "name": "title",
   "selector": ".odl-time-slots h3",
   "what": "what is being booked",
   "slot": "text"
  },
  {
   "name": "timezone",
   "selector": ".odl-tz",
   "what": "length, with whom, and the time zone the times are in",
   "slot": "text"
  },
  {
   "name": "days",
   "selector": ".odl-day",
   "what": "one day and its free times",
   "slot": "list"
  },
  {
   "name": "label",
   "selector": ".odl-dlabel",
   "what": "the day, such as 'Tue 18 Nov'",
   "slot": "text"
  },
  {
   "name": "slots",
   "selector": ".odl-day li",
   "what": "one free time",
   "slot": "list"
  },
  {
   "name": "tone",
   "selector": ".odl-wrap",
   "what": "warning marks a time that is almost full with a small dot; say so in the action's a11y_label too",
   "slot": "none"
  },
  {
   "name": "select",
   "selector": ".odl-slot",
   "what": "picks this time; its label is the time",
   "slot": "action"
  },
  {
   "name": "legend",
   "selector": ".odl-legend",
   "what": "what the dot means, when any time carries it",
   "slot": "text"
  }
 ],
 "data": {
  "type": "object",
  "required": [
   "title",
   "days"
  ],
  "properties": {
   "title": {
    "type": "string",
    "maxLength": 48,
    "part": "title"
   },
   "timezone": {
    "type": "string",
    "maxLength": 72,
    "part": "timezone"
   },
   "legend": {
    "type": "string",
    "maxLength": 48,
    "part": "legend"
   },
   "days": {
    "type": "array",
    "minItems": 1,
    "maxItems": 7,
    "part": "days",
    "items": {
     "type": "object",
     "required": [
      "label",
      "slots"
     ],
     "properties": {
      "label": {
       "type": "string",
       "maxLength": 20,
       "part": "label"
      },
      "slots": {
       "type": "array",
       "minItems": 0,
       "maxItems": 12,
       "part": "slots",
       "items": {
        "type": "object",
        "required": [
         "select"
        ],
        "properties": {
         "tone": {
          "type": "string",
          "enum": [
           "neutral",
           "warning"
          ],
          "part": "tone"
         },
         "select": {
          "type": "object",
          "part": "select",
          "properties": {
           "label": {
            "type": "string",
            "maxLength": 40
           },
           "event": {
            "type": "object"
           }
          },
          "required": [
           "label",
           "event"
          ]
         }
        }
       }
      }
     }
    }
   }
  }
 },
 "states": {
  "shown": [
   "picked",
   "almost full",
   "no times that day",
   "hover",
   "focus",
   "disabled",
   "wraps on a phone"
  ],
  "edge": {
   "empty": {
    "status": "handled",
    "how": "a day with no free times says 'No free times' in place of the buttons",
    "evidence": ".odl-day:not(:has(.odl-slot)) .odl-none"
   },
   "loading": {
    "status": "handled",
    "evidence": "data-od-slot",
    "how": "the Smart UI renderer draws each marked slot as a quiet block of its size while the data arrives; the static file shows the filled part"
   },
   "error": {
    "status": "not_built",
    "how": "if a picked time was just taken, the host disables it and the assistant offers the next free time"
   },
   "disabled": {
    "status": "shown",
    "how": "a time that was just taken is disabled and struck through",
    "evidence": ".odl-slot:disabled"
   },
   "overflow": {
    "status": "handled",
    "how": "times wrap onto more lines; on a phone the day's name moves above its times",
    "evidence": "repeat(auto-fill, minmax(5.5rem, 1fr))"
   },
   "long_text": {
    "status": "handled",
    "how": "titles, day names, the time-zone line and an unusually long time label wrap inside their box",
    "evidence": "overflow-wrap: anywhere"
   },
   "missing_image": {
    "status": "none",
    "how": "the part has no photo"
   }
  }
 },
 "tokens": [
  "--ds-border-width-default",
  "--ds-color-bg-action-primary",
  "--ds-color-bg-neutral-subtle",
  "--ds-color-bg-warning-bold",
  "--ds-color-border-default",
  "--ds-color-border-focus",
  "--ds-color-border-separator",
  "--ds-color-border-strong",
  "--ds-color-border-subtle",
  "--ds-color-surface-raised",
  "--ds-color-text-on-action",
  "--ds-color-text-primary",
  "--ds-color-text-secondary",
  "--ds-elevation-raised",
  "--ds-focus-ring-offset",
  "--ds-focus-ring-width",
  "--ds-font-weight-label",
  "--ds-motion-duration-short",
  "--ds-motion-easing-standard",
  "--ds-radius-container",
  "--ds-radius-control",
  "--ds-radius-full",
  "--ds-size-control-md",
  "--ds-size-target-min",
  "--ds-space-6",
  "--ds-space-inline-md",
  "--ds-space-inline-sm",
  "--ds-space-inset-lg",
  "--ds-space-inset-sm",
  "--ds-space-inset-xl",
  "--ds-space-inset-xs",
  "--ds-space-stack-lg",
  "--ds-space-stack-md",
  "--ds-space-stack-sm",
  "--ds-space-stack-xs",
  "--ds-space-target-gap",
  "--ds-text-body-md",
  "--ds-text-label-lg",
  "--ds-text-label-md",
  "--ds-text-title-md"
 ],
 "a11y": {
  "summary": "Each day is a labelled group; each time is a button named with its time and day (\"11:00, Tue 18 Nov\"), and the picked one is marked with aria-pressed.",
  "roles": [
   "banner",
   "group",
   "list",
   "region"
  ],
  "keyboard": [
   "Tab moves through the times, day by day",
   "Enter or Space picks one"
  ],
  "controls": {
   "button": 8,
   "input": 0,
   "link": 0,
   "select": 0,
   "textarea": 0,
   "summary": 0
  },
  "focus_visible": true,
  "reduced_motion": true,
  "min_target": true
 },
 "files": {
  "html": "components/time-slots/component.html",
  "bytes": 8454,
  "script": true
 },
 "source": null,
 "photos": 0,
 "urls": {
  "html": "https://opendesigner.dev/library/time-slots.html",
  "json": "https://opendesigner.dev/library/time-slots.json",
  "page": "https://opendesigner.dev/library/time-slots/"
 },
 "get": {
  "curl": "curl -fsSLo time-slots.html https://opendesigner.dev/library/time-slots.html",
  "opendesigner": "python3 path/to/skills/opendesigner/scripts/library.py add time-slots --from https://opendesigner.dev",
  "prompt": "Add the OpenDesigner component time-slots to this project: https://opendesigner.dev/library/time-slots.html. Keep its markup and states; map its --ds-* variables to my tokens."
 }
}
