@pure-ds/storybook 0.4.22 → 0.4.24

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.
@@ -304,7 +304,7 @@ class PdsDrawer extends HTMLElement {
304
304
  width: 100%; max-width: 100%;
305
305
  margin: 0;
306
306
  border-radius: var(--drawer-radius, var(--radius-lg));
307
- overflow: clip; contain: layout paint style; will-change: transform;
307
+ overflow: visible; contain: layout style; will-change: transform;
308
308
  touch-action: none;
309
309
  outline: none;
310
310
  }
@@ -11,7 +11,7 @@ function getStep(value) {
11
11
  // Default options for pds-form
12
12
  const DEFAULT_OPTIONS = {
13
13
  widgets: {
14
- booleans: "toggle", // 'toggle' | 'checkbox'
14
+ booleans: "toggle", // 'toggle' | 'toggle-with-icons' | 'checkbox'
15
15
  numbers: "input", // 'input' | 'range'
16
16
  selects: "standard", // 'standard' | 'dropdown'
17
17
  },
@@ -669,10 +669,9 @@ export class SchemaForm extends LitElement {
669
669
  return useRange ? "input-range" : "input-number";
670
670
  }
671
671
  if (schema.type === "boolean") {
672
- // Check if toggle should be used
673
- const useToggle =
674
- this.#getOption("widgets.booleans", "toggle") === "toggle";
675
- return useToggle ? "toggle" : "checkbox";
672
+ // Return the actual boolean widget type
673
+ const booleanWidget = this.#getOption("widgets.booleans", "toggle");
674
+ return booleanWidget === "checkbox" ? "checkbox" : booleanWidget;
676
675
  }
677
676
  return "input-text";
678
677
  }
@@ -1489,14 +1488,20 @@ export class SchemaForm extends LitElement {
1489
1488
  this.#emit("pw:after-render-field", { path, schema: node.schema })
1490
1489
  );
1491
1490
 
1492
- // Add data-toggle for toggle switches
1493
- const isToggle = node.widgetKey === "toggle";
1491
+ // Add data-toggle for toggle switches (both toggle and toggle-with-icons)
1492
+ const isToggle = node.widgetKey === "toggle" || node.widgetKey === "toggle-with-icons";
1493
+ const useIconToggle = node.widgetKey === "toggle-with-icons";
1494
1494
 
1495
1495
  // Add range-output class for range inputs if enabled
1496
1496
  const isRange = node.widgetKey === "input-range";
1497
1497
  const useRangeOutput =
1498
1498
  isRange && this.#getOption("enhancements.rangeOutput", true);
1499
- const labelClass = useRangeOutput ? "range-output" : undefined;
1499
+
1500
+ // Build class list for label
1501
+ const labelClasses = [];
1502
+ if (useRangeOutput) labelClasses.push("range-output");
1503
+ if (useIconToggle) labelClasses.push("with-icons");
1504
+ const labelClass = labelClasses.length > 0 ? labelClasses.join(" ") : undefined;
1500
1505
 
1501
1506
  const renderControlAndLabel = (isToggle) => {
1502
1507
  if (isToggle) return html`${controlTpl} <span data-label>${label}</span>`;
@@ -1855,6 +1860,22 @@ export class SchemaForm extends LitElement {
1855
1860
  `
1856
1861
  );
1857
1862
 
1863
+ // Toggle switch with icons (same as toggle, styling comes from .with-icons class on label)
1864
+ this.defineRenderer(
1865
+ "toggle-with-icons",
1866
+ ({ id, path, value, attrs, set }) => html`
1867
+ <input
1868
+ id=${id}
1869
+ name=${path}
1870
+ type="checkbox"
1871
+ .checked=${!!value}
1872
+ ?disabled=${!!attrs.disabled}
1873
+ ?required=${!!attrs.required}
1874
+ @change=${(e) => set(!!e.target.checked)}
1875
+ />
1876
+ `
1877
+ );
1878
+
1858
1879
  this.defineRenderer(
1859
1880
  "select",
1860
1881
  ({ id, path, value, attrs, set, schema, ui, host }) => {
@@ -737,7 +737,6 @@ export const presets = {
737
737
  "Data-dense business intelligence app interface with organized hierarchy and professional polish",
738
738
  options: {
739
739
  liquidGlassEffects: false,
740
- backgroundMesh: 2,
741
740
  },
742
741
  colors: {
743
742
  primary: "#0066cc", // corporate blue for primary actions
@@ -815,7 +814,7 @@ presets.default = {
815
814
  form: {
816
815
  options: {
817
816
  widgets: {
818
- booleans: "toggle", // 'toggle' | 'checkbox'
817
+ booleans: "toggle", // 'toggle' | 'toggle-with-icons' | 'checkbox'
819
818
  numbers: "input", // 'input' | 'range'
820
819
  selects: "standard", // 'standard' | 'dropdown'
821
820
  },
@@ -1923,6 +1923,12 @@ label {
1923
1923
  line-height: var(--font-line-height-relaxed);
1924
1924
  }
1925
1925
 
1926
+ input, textarea, select {
1927
+ &:focus {
1928
+ outline: none;
1929
+ }
1930
+ }
1931
+
1926
1932
  input, textarea, select {
1927
1933
  width: 100%;
1928
1934
  min-height: ${minInputHeight}px;
@@ -1940,11 +1946,7 @@ input, textarea, select {
1940
1946
  -webkit-appearance: none;
1941
1947
 
1942
1948
  &:focus {
1943
- outline: none;
1944
1949
  border-color: var(--color-primary-500);
1945
- box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-primary-500) ${Math.round(
1946
- (focusRingOpacity || 0.3) * 100
1947
- )}%, transparent);
1948
1950
  background-color: var(--color-surface-base);
1949
1951
  }
1950
1952
 
@@ -2324,6 +2326,25 @@ label[data-toggle] {
2324
2326
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
2325
2327
  }
2326
2328
 
2329
+ /* Icons in toggle knob (opt-in via .with-icons class) */
2330
+ &.with-icons .toggle-knob::before {
2331
+ content: "✕";
2332
+ position: absolute;
2333
+ inset: 0;
2334
+ display: flex;
2335
+ align-items: center;
2336
+ justify-content: center;
2337
+ font-size: 12px;
2338
+ font-weight: bold;
2339
+ color: var(--color-gray-600);
2340
+ transition: opacity 200ms ease;
2341
+ }
2342
+
2343
+ &.with-icons:has(input[type="checkbox"]:checked) .toggle-knob::before {
2344
+ content: "✓";
2345
+ color: var(--color-primary-600);
2346
+ }
2347
+
2327
2348
  /* Toggle switch when checked - using :has() selector */
2328
2349
  &:has(input[type="checkbox"]:checked) .toggle-switch {
2329
2350
  background-color: var(--color-primary-fill);
@@ -2887,15 +2908,28 @@ tbody {
2887
2908
  cursor: pointer;
2888
2909
  padding: var(--spacing-3) var(--spacing-4);
2889
2910
  list-style: none;
2890
- outline: none;
2891
2911
  display: flex;
2892
2912
  align-items: center;
2893
2913
  gap: var(--spacing-2);
2914
+ border-radius: var(--radius-sm);
2915
+ transition: background-color var(--transition-fast), box-shadow var(--transition-fast);
2894
2916
 
2895
2917
  &::-webkit-details-marker {
2896
2918
  display: none;
2897
2919
  }
2898
2920
 
2921
+ &:hover {
2922
+ background-color: var(--color-surface-subtle);
2923
+ }
2924
+
2925
+ &:focus {
2926
+ outline: none;
2927
+ }
2928
+
2929
+ &:focus-visible {
2930
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--color-primary-500) 30%, transparent);
2931
+ }
2932
+
2899
2933
  /* Chevron indicator */
2900
2934
  &::after {
2901
2935
  content: "";
@@ -3628,6 +3662,13 @@ nav[data-dropdown] {
3628
3662
  white-space: nowrap;
3629
3663
  }
3630
3664
 
3665
+ /* Required Legend Utility */
3666
+ :where(.required-legend) {
3667
+ display: block;
3668
+ margin: var(--spacing-3) 0;
3669
+ color: var(--color-text-muted);
3670
+ }
3671
+
3631
3672
  /* Max-width utilities */
3632
3673
  .max-w-sm { max-width: 400px; } .max-w-md { max-width: 600px; } .max-w-lg { max-width: 800px; } .max-w-xl { max-width: 1200px; }
3633
3674
 
package/src/js/pds.js CHANGED
@@ -961,10 +961,27 @@ async function __setupAutoDefinerAndEnhancers(options) {
961
961
  enhancers: mergedEnhancers,
962
962
  onError: (tag, err) => {
963
963
  if (typeof tag === "string" && tag.startsWith("pds-")) {
964
- // No config available in this context, using console
965
- console.warn(
966
- `⚠️ PDS component <${tag}> not found. Assets may not be installed.`
967
- );
964
+ // Check if this is a Lit-dependent component with missing #pds/lit import map
965
+ const litDependentComponents = ['pds-form', 'pds-drawer'];
966
+ const isLitComponent = litDependentComponents.includes(tag);
967
+ const isMissingLitError = err?.message?.includes('#pds/lit') ||
968
+ err?.message?.includes('Failed to resolve module specifier');
969
+
970
+ if (isLitComponent && isMissingLitError) {
971
+ console.error(
972
+ `❌ PDS component <${tag}> requires Lit but #pds/lit is not in import map.\n` +
973
+ `Add this to your HTML <head>:\n` +
974
+ `<script type="importmap">\n` +
975
+ ` { "imports": { "#pds/lit": "./path/to/lit.js" } }\n` +
976
+ `</script>\n` +
977
+ `See: https://github.com/pure-ds/core#lit-components`
978
+ );
979
+ } else {
980
+ // Generic component not found warning
981
+ console.warn(
982
+ `⚠️ PDS component <${tag}> not found. Assets may not be installed.`
983
+ );
984
+ }
968
985
  } else {
969
986
  console.error(`❌ Auto-define error for <${tag}>:`, err);
970
987
  }
@@ -10,12 +10,26 @@ From zero to hero with PDS.
10
10
  npm install @pure-ds/core
11
11
  ```
12
12
 
13
- Create `pds.config.js`:
13
+ **What happens during install:**
14
+
15
+ PDS automatically sets up your project:
16
+ - ✅ Creates `pds.config.js` with commented examples (if it doesn't exist)
17
+ - ✅ Exports static assets to your web root (components, icons, styles)
18
+ - ✅ Copies AI/Copilot instructions to `.github/copilot-instructions.md`
19
+ - ✅ Adds helper scripts to your `package.json` (`pds:export`, `pds:build-icons`)
20
+
21
+ The generated `pds.config.js` includes:
14
22
 
15
23
  ```javascript
24
+ // pds.config.js (auto-generated)
16
25
  export const config = {
17
26
  mode: "live",
18
- preset: "default"
27
+ preset: "default",
28
+
29
+ // Uncomment and customize as needed:
30
+ // design: { colors: { primary: '#007acc' } },
31
+ // enhancers: [ /* custom enhancements */ ],
32
+ // autoDefine: { predefine: ['pds-icon'] }
19
33
  }
20
34
  ```
21
35
 
@@ -23,11 +37,21 @@ Then initialize in your app:
23
37
 
24
38
  ```javascript
25
39
  import { PDS } from '@pure-ds/core';
26
- import { config } from "../../pds.config.js"; // change to match location (project root)
40
+ import { config } from "./pds.config.js"; // project root
27
41
 
28
42
  await PDS.start(config); // That's it! Start writing semantic HTML.
29
43
  ```
30
44
 
45
+ **Manual config generation:**
46
+
47
+ ```bash
48
+ # Create or regenerate config with examples
49
+ npx pds-init-config
50
+
51
+ # Force overwrite existing config
52
+ npx pds-init-config --force
53
+ ```
54
+
31
55
  ### Option B: CDN (Zero Install)
32
56
 
33
57
  Perfect for quick prototypes and learning:
@@ -190,9 +190,7 @@ export const AllPositions = () => {
190
190
  <pds-drawer id="drawer-right" position="right">
191
191
  <div slot="drawer-header" class="flex items-center justify-between">
192
192
  <h2>Filter & Sort</h2>
193
- <button id="close-drawer-right" class="icon-only btn-outline btn-sm">
194
- <pds-icon icon="x" label="Close"></pds-icon>
195
- </button>
193
+
196
194
  </div>
197
195
  <div slot="drawer-content" class="stack-md">
198
196
  <p>
@@ -320,7 +318,7 @@ export const AllPositions = () => {
320
318
 
321
319
  <pds-drawer id="drawer-bottom" position="bottom">
322
320
  <div slot="drawer-header" class="flex items-center gap-md">
323
- <pds-icon icon="toolbox" size="lg"></pds-icon>
321
+ <pds-icon icon="gear" size="lg"></pds-icon>
324
322
  <h2>Quick Actions</h2>
325
323
  </div>
326
324
  <div slot="drawer-content" class="stack-md">