@d-zero/custom-components 5.0.0-alpha.45 → 5.0.0-beta.0

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.
@@ -0,0 +1,25 @@
1
+ export declare class Breadcrumbs extends HTMLElement {
2
+ #private;
3
+ get separator(): string;
4
+ set separator(value: string | null);
5
+ constructor();
6
+ attributeChangedCallback(name: string, _: string | null, newValue: string | null): void;
7
+ connectedCallback(): void;
8
+ disconnectedCallback(): void;
9
+ static readonly defaultSeparator = "/";
10
+ static defaultStyle: Readonly<{
11
+ readonly separatorColor: "currentColor";
12
+ readonly separatorSpacingValue: 0.5;
13
+ readonly separatorSpacingUnit: "em";
14
+ readonly color: "currentColor";
15
+ readonly currentColor: "currentColor";
16
+ readonly font: "inherit";
17
+ readonly currentFont: "inherit";
18
+ }>;
19
+ static get observedAttributes(): string[];
20
+ }
21
+ /**
22
+ * @param prefix
23
+ */
24
+ export declare function defineBreadcrumbs(prefix: string): string;
25
+ //# sourceMappingURL=breadcrumbs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":"AAEA,qBAAa,WAAY,SAAQ,WAAW;;IAM3C,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAmBjC;;IAkED,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAWhF,iBAAiB;IAUjB,oBAAoB;IA6GpB,MAAM,CAAC,QAAQ,CAAC,gBAAgB,OAAO;IAEvC,MAAM,CAAC,YAAY;;;;;;;;OAQP;IAEZ,MAAM,KAAK,kBAAkB,aAE5B;CACD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMxD"}
@@ -0,0 +1,197 @@
1
+ export class Breadcrumbs extends HTMLElement {
2
+ #observer;
3
+ #ol;
4
+ #separator;
5
+ #shadowRoot;
6
+ get separator() {
7
+ return this.#separator;
8
+ }
9
+ set separator(value) {
10
+ const newValue = value === null ? Breadcrumbs.defaultSeparator : value;
11
+ if (this.#separator === newValue) {
12
+ return;
13
+ }
14
+ this.#separator = newValue;
15
+ const currentAttr = this.getAttribute('separator');
16
+ if (currentAttr !== newValue) {
17
+ if (newValue === Breadcrumbs.defaultSeparator && value === null) {
18
+ this.removeAttribute('separator');
19
+ }
20
+ else {
21
+ this.setAttribute('separator', newValue);
22
+ }
23
+ }
24
+ this.#updateBreadcrumbs();
25
+ }
26
+ constructor() {
27
+ super();
28
+ this.#shadowRoot = this.attachShadow({ mode: 'open' });
29
+ if (this.hasAttribute('separator')) {
30
+ this.#separator = this.getAttribute('separator') ?? Breadcrumbs.defaultSeparator;
31
+ }
32
+ else {
33
+ this.#separator = Breadcrumbs.defaultSeparator;
34
+ }
35
+ const style = document.createElement('style');
36
+ style.textContent = `
37
+ :host {
38
+ --separator-color: ${Breadcrumbs.defaultStyle.separatorColor};
39
+ --separator-spacing: ${Breadcrumbs.defaultStyle.separatorSpacingValue}${Breadcrumbs.defaultStyle.separatorSpacingUnit};
40
+ --color: ${Breadcrumbs.defaultStyle.color};
41
+ --current-color: ${Breadcrumbs.defaultStyle.currentColor};
42
+ --font: ${Breadcrumbs.defaultStyle.font};
43
+ --current-font: ${Breadcrumbs.defaultStyle.currentFont};
44
+ display: block;
45
+ }
46
+ * {
47
+ box-sizing: border-box;
48
+ }
49
+ ol {
50
+ font: var(--font);
51
+ color: var(--color);
52
+ display: flex;
53
+ flex-wrap: wrap;
54
+ list-style: none;
55
+ padding: 0;
56
+ margin: 0;
57
+ }
58
+ li {
59
+ display: inline-flex;
60
+ align-items: center;
61
+ }
62
+ :host::part(separator) {
63
+ display: block;
64
+ margin: 0 var(--separator-spacing);
65
+ color: var(--separator-color);
66
+ }
67
+ a {
68
+ font: inherit;
69
+ color: inherit;
70
+ }
71
+ a[aria-current="page"] {
72
+ font: var(--current-font);
73
+ color: var(--current-color);
74
+ }
75
+ `;
76
+ this.#ol = document.createElement('ol');
77
+ this.#ol.setAttribute('itemscope', '');
78
+ this.#ol.setAttribute('itemtype', 'https://schema.org/BreadcrumbList');
79
+ this.#shadowRoot.append(style);
80
+ this.#shadowRoot.append(this.#ol);
81
+ this.#observer = new MutationObserver(() => {
82
+ this.#updateBreadcrumbs();
83
+ });
84
+ }
85
+ attributeChangedCallback(name, _, newValue) {
86
+ if (name === 'separator') {
87
+ const internalValue = newValue === null ? Breadcrumbs.defaultSeparator : newValue;
88
+ if (this.#separator !== internalValue) {
89
+ this.#separator = internalValue;
90
+ this.#updateBreadcrumbs();
91
+ }
92
+ }
93
+ }
94
+ connectedCallback() {
95
+ this.#observer.observe(this, {
96
+ childList: true,
97
+ subtree: false,
98
+ characterData: true,
99
+ });
100
+ this.#updateBreadcrumbs();
101
+ }
102
+ disconnectedCallback() {
103
+ this.#observer.disconnect();
104
+ }
105
+ #checkForInvalidTextNodes() {
106
+ for (let i = 0; i < this.childNodes.length; i++) {
107
+ const node = this.childNodes[i];
108
+ if (node &&
109
+ node.nodeType === Node.TEXT_NODE &&
110
+ node.textContent &&
111
+ node.textContent.trim()) {
112
+ throw new Error('Text nodes are not allowed. All items must be explicitly specified as <a> elements. Example: <a href="/path">text</a>');
113
+ }
114
+ }
115
+ }
116
+ #createBreadcrumbItem({ text, href, position, isCurrent = false, isLast = false, }) {
117
+ const li = document.createElement('li');
118
+ li.setAttribute('itemscope', '');
119
+ li.setAttribute('itemprop', 'itemListElement');
120
+ li.setAttribute('itemtype', 'https://schema.org/ListItem');
121
+ const link = document.createElement('a');
122
+ link.setAttribute('itemscope', '');
123
+ link.setAttribute('itemprop', 'item');
124
+ link.setAttribute('itemtype', 'https://schema.org/WebPage');
125
+ link.setAttribute('href', href);
126
+ link.setAttribute('itemid', href);
127
+ if (isCurrent) {
128
+ link.setAttribute('aria-current', 'page');
129
+ }
130
+ const nameSpan = document.createElement('span');
131
+ nameSpan.setAttribute('itemprop', 'name');
132
+ nameSpan.textContent = text;
133
+ link.append(nameSpan);
134
+ const positionMeta = document.createElement('meta');
135
+ positionMeta.setAttribute('itemprop', 'position');
136
+ positionMeta.setAttribute('content', position.toString());
137
+ li.append(link);
138
+ li.append(positionMeta);
139
+ if (!isLast) {
140
+ const separator = document.createElement('span');
141
+ separator.setAttribute('aria-hidden', 'true');
142
+ separator.part.add('separator');
143
+ separator.textContent = this.separator;
144
+ li.append(separator);
145
+ }
146
+ return li;
147
+ }
148
+ #updateBreadcrumbs() {
149
+ this.#ol.innerHTML = '';
150
+ this.#checkForInvalidTextNodes();
151
+ const links = [...this.querySelectorAll('a')];
152
+ if (links.length === 0)
153
+ return;
154
+ for (let i = 0; i < links.length; i++) {
155
+ const link = links[i];
156
+ if (!link)
157
+ continue;
158
+ const isLast = i === links.length - 1;
159
+ const href = link.getAttribute('href');
160
+ if (!href) {
161
+ throw new Error(`Breadcrumb link (${link.textContent || 'noname'}) requires href attribute`);
162
+ }
163
+ const isCurrent = isLast || link.hasAttribute('aria-current');
164
+ const li = this.#createBreadcrumbItem({
165
+ text: link.textContent || '',
166
+ href: href,
167
+ position: i + 1,
168
+ isCurrent: isCurrent,
169
+ isLast: isLast,
170
+ });
171
+ this.#ol.append(li);
172
+ }
173
+ }
174
+ static defaultSeparator = '/';
175
+ static defaultStyle = Object.freeze({
176
+ separatorColor: 'currentColor',
177
+ separatorSpacingValue: 0.5,
178
+ separatorSpacingUnit: 'em',
179
+ color: 'currentColor',
180
+ currentColor: 'currentColor',
181
+ font: 'inherit',
182
+ currentFont: 'inherit',
183
+ });
184
+ static get observedAttributes() {
185
+ return ['separator'];
186
+ }
187
+ }
188
+ /**
189
+ * @param prefix
190
+ */
191
+ export function defineBreadcrumbs(prefix) {
192
+ const tagName = `${prefix}-breadcrumbs`;
193
+ if (!customElements.get(tagName)) {
194
+ customElements.define(tagName, Breadcrumbs);
195
+ }
196
+ return tagName;
197
+ }
@@ -0,0 +1,74 @@
1
+ import type { StoryObj } from '@storybook/web-components';
2
+ declare const meta: {
3
+ title: string;
4
+ component: string;
5
+ argTypes: {
6
+ separator: {
7
+ control: "text";
8
+ name: string;
9
+ description: string;
10
+ defaultValue: string;
11
+ };
12
+ separatorColor: {
13
+ control: "color";
14
+ name: string;
15
+ description: string;
16
+ defaultValue: "currentColor";
17
+ };
18
+ separatorSpacingValue: {
19
+ control: "number";
20
+ name: string;
21
+ description: string;
22
+ defaultValue: 0.5;
23
+ step: number;
24
+ min: number;
25
+ };
26
+ separatorSpacingUnit: {
27
+ control: "select";
28
+ name: string;
29
+ options: readonly ["em", "px", "rem", "cqi", "%"];
30
+ description: string;
31
+ defaultValue: "em";
32
+ };
33
+ color: {
34
+ control: "color";
35
+ name: string;
36
+ description: string;
37
+ defaultValue: "currentColor";
38
+ };
39
+ currentColor: {
40
+ control: "color";
41
+ name: string;
42
+ description: string;
43
+ defaultValue: "currentColor";
44
+ };
45
+ font: {
46
+ control: "text";
47
+ name: string;
48
+ description: string;
49
+ defaultValue: "inherit";
50
+ };
51
+ currentFont: {
52
+ control: "text";
53
+ name: string;
54
+ description: string;
55
+ defaultValue: "inherit";
56
+ };
57
+ separatorPartStyle: {
58
+ control: "text";
59
+ name: string;
60
+ description: string;
61
+ defaultValue: string;
62
+ rows: number;
63
+ };
64
+ };
65
+ render(args: import("@storybook/web-components").Args): HTMLDivElement;
66
+ };
67
+ export default meta;
68
+ type Story = StoryObj;
69
+ export declare const Default: Story;
70
+ export declare const CustomSeparator: Story;
71
+ export declare const LongPath: Story;
72
+ export declare const CustomFonts: Story;
73
+ export declare const PartStyling: Story;
74
+ //# sourceMappingURL=breadcrumbs.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumbs.stories.d.ts","sourceRoot":"","sources":["../src/breadcrumbs.stories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAQhE,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkHM,CAAC;AAEjB,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC;AAetB,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAO7B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAqBtB,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,KAyBzB,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,KA8BzB,CAAC"}
@@ -0,0 +1,205 @@
1
+ import { defineBreadcrumbs, Breadcrumbs } from './breadcrumbs.js';
2
+ import { lengthUnits } from './style-values.js';
3
+ // Define the custom element with a prefix upfront
4
+ const tagName = defineBreadcrumbs('x'); // Use 'x' as prefix
5
+ const meta = {
6
+ title: 'Components/Breadcrumbs',
7
+ component: tagName,
8
+ argTypes: {
9
+ separator: {
10
+ control: 'text',
11
+ name: 'separator',
12
+ description: 'パンくずリストの区切り文字',
13
+ defaultValue: Breadcrumbs.defaultSeparator,
14
+ },
15
+ separatorColor: {
16
+ control: 'color',
17
+ name: '--separator-color',
18
+ description: '区切り文字の色',
19
+ defaultValue: Breadcrumbs.defaultStyle.separatorColor,
20
+ },
21
+ separatorSpacingValue: {
22
+ control: 'number',
23
+ name: '--separator-spacing (数値)',
24
+ description: '区切り文字の間隔(数値部分)',
25
+ defaultValue: Breadcrumbs.defaultStyle.separatorSpacingValue,
26
+ step: 0.1,
27
+ min: 0,
28
+ },
29
+ separatorSpacingUnit: {
30
+ control: 'select',
31
+ name: '--separator-spacing (単位)',
32
+ options: lengthUnits,
33
+ description: '区切り文字の間隔(単位)',
34
+ defaultValue: Breadcrumbs.defaultStyle.separatorSpacingUnit,
35
+ },
36
+ color: {
37
+ control: 'color',
38
+ name: '--color',
39
+ description: 'リスト全体のデフォルト文字色',
40
+ defaultValue: Breadcrumbs.defaultStyle.color,
41
+ },
42
+ currentColor: {
43
+ control: 'color',
44
+ name: '--current-color',
45
+ description: '現在位置を示すアイテムの色',
46
+ defaultValue: Breadcrumbs.defaultStyle.currentColor,
47
+ },
48
+ font: {
49
+ control: 'text',
50
+ name: '--font (ショートハンド)',
51
+ description: '全体のフォントスタイル (例: italic bold 1.2em sans-serif)',
52
+ defaultValue: Breadcrumbs.defaultStyle.font,
53
+ },
54
+ currentFont: {
55
+ control: 'text',
56
+ name: '--current-font (ショートハンド)',
57
+ description: '現在のアイテムのフォントスタイル',
58
+ defaultValue: Breadcrumbs.defaultStyle.currentFont,
59
+ },
60
+ separatorPartStyle: {
61
+ control: 'text',
62
+ name: '::part(separator)',
63
+ description: '::part(separator) に適用するCSS(例: background: yellow; padding: 2px;)',
64
+ defaultValue: '',
65
+ rows: 5, // Make textarea taller
66
+ },
67
+ },
68
+ render(args) {
69
+ const container = document.createElement('div'); // Container for element and style
70
+ // Create the component instance
71
+ const element = document.createElement(tagName);
72
+ // Apply separator attribute
73
+ element.separator = args.separator;
74
+ // Apply CSS Custom Properties
75
+ element.style.setProperty('--separator-color', args.separatorColor);
76
+ element.style.setProperty('--separator-spacing', `${args.separatorSpacingValue}${args.separatorSpacingUnit}`);
77
+ element.style.setProperty('--color', args.color);
78
+ element.style.setProperty('--current-color', args.currentColor);
79
+ // Apply font shorthands
80
+ if (args.font) {
81
+ element.style.setProperty('--font', args.font);
82
+ }
83
+ if (args.currentFont) {
84
+ element.style.setProperty('--current-font', args.currentFont);
85
+ }
86
+ // Set inner HTML
87
+ element.innerHTML = `
88
+ <a href="/">ホーム</a>
89
+ <a href="/category">カテゴリA</a>
90
+ <a href="/category/subcategory/items">アイテム一覧</a>
91
+ <a href="/category/subcategory/items/current" aria-current="page">現在のアイテム</a>
92
+ `;
93
+ container.append(element);
94
+ // Apply ::part styles if provided
95
+ if (args.separatorPartStyle && args.separatorPartStyle.trim()) {
96
+ const style = document.createElement('style');
97
+ // Scope the style to the specific instance using the tag name
98
+ style.textContent = `
99
+ ${tagName}::part(separator) {
100
+ ${args.separatorPartStyle}
101
+ }
102
+ `;
103
+ container.append(style); // Append style next to the element
104
+ }
105
+ return container; // Return the container with element + style
106
+ },
107
+ };
108
+ export default meta;
109
+ const getDefaultArgs = () => {
110
+ const args = {};
111
+ for (const [key, value] of Object.entries(meta.argTypes)) {
112
+ // Skip the individual value/unit controls for composite props
113
+ if (!key.endsWith('Value') && !key.endsWith('Unit')) {
114
+ args[key] = value.defaultValue;
115
+ }
116
+ }
117
+ return args;
118
+ };
119
+ const defaultArgs = getDefaultArgs();
120
+ export const Default = {
121
+ args: defaultArgs,
122
+ };
123
+ export const CustomSeparator = {
124
+ args: {
125
+ ...defaultArgs,
126
+ separator: '>',
127
+ separatorSpacingValue: 0.8,
128
+ separatorSpacingUnit: 'em',
129
+ },
130
+ };
131
+ export const LongPath = {
132
+ args: defaultArgs,
133
+ render: (args) => {
134
+ const element = meta.render(args);
135
+ const breadcrumbsElement = element instanceof HTMLElement && element.tagName.toLowerCase() === tagName
136
+ ? element
137
+ : element.querySelector(tagName);
138
+ if (breadcrumbsElement) {
139
+ breadcrumbsElement.innerHTML = `
140
+ <a href="/">ホーム</a>
141
+ <a href="/category">カテゴリA</a>
142
+ <a href="/category/subcategory">サブカテゴリB</a>
143
+ <a href="/category/subcategory/subsubcategory">サブサブカテゴリC</a>
144
+ <a href="/category/subcategory/subsubcategory/items">アイテム一覧</a>
145
+ <a href="/category/subcategory/subsubcategory/items/123" aria-current="page">現在のアイテム</a>
146
+ `;
147
+ }
148
+ return element;
149
+ },
150
+ };
151
+ // Story to demonstrate font shorthands
152
+ export const CustomFonts = {
153
+ args: {
154
+ ...defaultArgs,
155
+ font: 'italic 1em "Times New Roman", serif',
156
+ currentFont: 'bold 1.1em Arial, sans-serif',
157
+ separator: '→',
158
+ color: '#555',
159
+ currentColor: 'darkred',
160
+ },
161
+ render: (args) => {
162
+ const element = meta.render(args);
163
+ const breadcrumbsElement = element instanceof HTMLElement && element.tagName.toLowerCase() === tagName
164
+ ? element
165
+ : element.querySelector(tagName);
166
+ if (breadcrumbsElement) {
167
+ breadcrumbsElement.innerHTML = `
168
+ <a href="/">Home (Serif)</a>
169
+ <a href="/products">Products (Serif)</a>
170
+ <a href="/products/special" aria-current="page">Special Offer (Arial Bold)</a>
171
+ `;
172
+ }
173
+ return element;
174
+ },
175
+ };
176
+ // New story to demonstrate ::part styling
177
+ export const PartStyling = {
178
+ args: {
179
+ ...defaultArgs,
180
+ separator: '::',
181
+ separatorPartStyle: `
182
+ background-color: gold;
183
+ border: 1px dashed red;
184
+ padding: 0 5px;
185
+ border-radius: 4px;
186
+ font-weight: bold;
187
+ box-shadow: 1px 1px 3px rgba(0,0,0,0.3);
188
+ min-block-size: 1em;
189
+ `,
190
+ },
191
+ render: (args) => {
192
+ const element = meta.render(args);
193
+ const breadcrumbsElement = element instanceof HTMLElement && element.tagName.toLowerCase() === tagName
194
+ ? element
195
+ : element.querySelector(tagName);
196
+ if (breadcrumbsElement) {
197
+ breadcrumbsElement.innerHTML = `
198
+ <a href="/">Home</a>
199
+ <a href="/section">Section</a>
200
+ <a href="/section/current" aria-current="page">Current Page</a>
201
+ `;
202
+ }
203
+ return element;
204
+ },
205
+ };
package/package.json CHANGED
@@ -1,18 +1,21 @@
1
1
  {
2
2
  "name": "@d-zero/custom-components",
3
- "version": "5.0.0-alpha.45",
3
+ "version": "5.0.0-beta.0",
4
4
  "description": "D-ZERO custom components",
5
5
  "author": "D-ZERO",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "url": "https://github.com/d-zero-dev/frontend-env.git"
9
9
  },
10
- "private": false,
11
10
  "publishConfig": {
12
11
  "access": "public"
13
12
  },
14
13
  "type": "module",
15
14
  "exports": {
15
+ "./breadcrumbs": {
16
+ "import": "./dist/breadcrumbs.js",
17
+ "types": "./dist/breadcrumbs.d.ts"
18
+ },
16
19
  "./hamburger-menu": {
17
20
  "import": "./dist/hamburger-menu.js",
18
21
  "types": "./dist/hamburger-menu.d.ts"
@@ -28,14 +31,14 @@
28
31
  },
29
32
  "devDependencies": {
30
33
  "@chromatic-com/storybook": "3.2.6",
31
- "@storybook/addon-essentials": "8.6.12",
32
- "@storybook/blocks": "8.6.12",
33
- "@storybook/experimental-addon-test": "8.6.12",
34
- "@storybook/test": "8.6.12",
35
- "@storybook/web-components": "8.6.12",
36
- "@storybook/web-components-vite": "8.6.12",
37
- "lit": "3.2.1",
38
- "storybook": "8.6.12"
34
+ "@storybook/addon-essentials": "8.6.14",
35
+ "@storybook/blocks": "8.6.14",
36
+ "@storybook/experimental-addon-test": "8.6.14",
37
+ "@storybook/test": "8.6.14",
38
+ "@storybook/web-components": "8.6.14",
39
+ "@storybook/web-components-vite": "8.6.14",
40
+ "lit": "3.3.0",
41
+ "storybook": "8.6.14"
39
42
  },
40
- "gitHead": "8f9a1746509e90c061511b19f028c758754b394f"
43
+ "gitHead": "5cc4a9e00ee763e56923ae878704e237d9ce3705"
41
44
  }